2013-04-12 13 views
6

Ich habe ein Problem bei der Hausaufgaben für Online-Algorithmen-Klasse aufgetreten. Casting Object[] zu T[] wobei T Vergleichbar wirft eine LaufzeitausnahmeCasting Array von Objekten zu Array von vergleichbaren

public static <T extends Comparable<? super T>> void mergeSort(T[] xs) { 
    T[] aux = (T[]) new Object[xs.length]; 
    mergeSort(xs, aux, 0, xs.length); 
} 

ich es in C# umschreiben könnte, die keine Probleme haben mit generischen Arrays zu schaffen, aber ich würde lieber lernen, wie man damit umgehen in Java.

+0

Ich glaube, Sie sollten sehen, http://stackoverflow.com/questions/1817524/generic-arrays-in-java es sehr interessant ist. –

Antwort

12

Wenn Sie eine Laufzeitausnahme erhalten, bedeutet dies, dass die Objekte, die Sie zu übertragen versucht haben, diesen Typ nicht haben. Die Sprache hat damit nichts zu tun. Es ist wahrscheinlich ein Fehler in Ihrem Code.

Edit: Es klingt wie Sie verwirrt sind, wie Java-Typ-System funktioniert. In C# repräsentieren Generika tatsächlich zur Laufzeit verschiedene Typen. In Java existieren generische Typen zur Laufzeit nicht. Sie sind nur eine Annehmlichkeit, um eine bessere Prüfung der Kompilierungszeit zu ermöglichen. Während der Kompilierung werden Generika in einem Prozess, der als Typlöschung bezeichnet wird, durch einen echten Typ ersetzt.

Normalerweise ist das Löschen eines generischen Typs Object, aber da Sie eine obere Grenze für T angegeben haben, wird es in diese gebundene Comparable konvertiert. Daher sieht Ihr Code nach dem Löschen so aus.

Comparable[] aux = (Comparable[]) new Object[xs.length]; 

In anderen Worten, Sie sind ein Array vom Typ Object[] erstellen und sofort versucht, es zu werfen Comparable[] zu geben. Da ObjectComparable nicht implementiert, sind die Typen inkompatibel, daher erhalten Sie eine Laufzeitausnahme. Sie können dies beheben, indem Sie stattdessen ein Array von Comparable s erstellen.

+0

Offensichtlich gibt es einen Bug und offensichtlich hat es etwas damit zu tun, wie Java mit Generics umgeht. In C# gibt es kein Problem beim Erstellen von Feldern mit eingeschränktem Typparameter. – synapse

+0

@synapse Ich habe meine Antwort bearbeitet, um die Dinge hoffentlich für Sie zu klären. – Antimony

2

Arrays sind kovariant und das bedeutet, dass sie den Typ ihrer Elemente zur Laufzeit beibehalten. Generika von Java sind nicht. Also im Grunde mischen sie sich nicht.

Siehe auch: Generic arrays in Java

Sie können keine Arrays von Generika und Sie können ihnen nicht werfen. Besser, Arraylisten zu verwenden.

3

Try this:

public static <T extends Comparable<? super T>> void mergeSort(T[] xs) { 
    T[] aux = (T[])java.lang.reflect.Array.newInstance(xs.getClass().getComponentType(), xs.length); 
    mergeSort(xs, aux, 0, xs.length); 
} 
+0

Danke. Kein Wunder, dass Java Generics FAQ hundert Seiten lang sind. – synapse

+0

Es gibt einen viel einfacheren Weg, dies zu tun. Siehe meine Antwort. – Antimony

+0

Einfacher aber gefährlich. Sie können den Typ auch einfach so ändern: > und er wird sogar mit dem ursprünglichen Code kompiliert und ausgeführt (abhängig von der Signatur der mergeSort-Methode). Aber wenn zum Beispiel T immer String ist und Sie versuchen, String [] aux2 = (String []) aux auszuführen, erhalten Sie eine Ausnahme. Ihr vergleichbares Array hat das gleiche Problem. So ist es einfacher, aber es funktioniert möglicherweise nicht die ganze Zeit. – jdb