Ein generisches Array löst die ClassCastException aus, wenn es direkt referenziert wird (beim Aufruf der Hilfsmethode nicht)

8

Das ist Magie! Schau dir diesen einfachen Code an:

%Vor%

Ausgabe:

  

10
MAGIC INCOMING
Ausnahme im Thread "main"   java.lang.ClassCastException: [Ljava.lang.Object; kann nicht umgewandelt werden   [Ljava.lang.Integer; bei ArrayOFMagic.main (ArrayOFMagic.java:25)

Ich rufe array.length zweimal auf. Einmal durch die Methode und einmal direkt. Es geht weiter, wenn method verwendet wird, und löst eine Ausnahme aus, wenn es direkt aufgerufen wird. O.o Jemand erklären?

bearbeiten: Nur um zu verdeutlichen: Klasse funktioniert gut, wenn sie nicht direkt angerufen wird. Sie können Setter / Getter für Array-Elemente und alle ..!

haben     
Vistritium 11.09.2013, 16:36
quelle

4 Antworten

4

AKTUALISIERT Antwort:

HAFTUNGSAUSSCHLUSS : Diese Antwort stammt nicht von mir. Ich habe einen früheren Mitarbeiter von Sun, der an Generika in Java gearbeitet hat, gefragt, warum das so ist. Seine Antwort:

Der erste Aufruf greift auf das Member innerhalb der generischen Klasse selbst zu, die an der unteren Grenze (in diesem Fall Object) gelöscht wird, so dass in ref auf array.length keine Umwandlung erfolgt.

Aber der zweite Aufruf erfolgt über eine parametrisierte Instanz eines generischen Typs , sodass die Typvariable (das Array) an Integer gebunden ist.

Das Array-Feld wird vom Typ T [] deklariert, der an Integer [] gebunden ist. Der Accessor-Code, der vom Compiler ausgegeben wird, wirft ihn auf diesen Typ, und der Cast bläst (in jeder Hinsicht des Wortes).

ALTE ANTWORT: Hier ist eine bessere Möglichkeit, Ihre Klasse zu implementieren (als Ergänzung zur Antwort von zhong.j.yu).

%Vor%     
Kylar 11.09.2013, 16:57
quelle
4

Idealerweise sollte diese Zeile sofort zur Laufzeit fehlschlagen

%Vor%

Leider wird der Fehler aufgrund der Löschung verschluckt. Der Fehler könnte später auftreten, aber wann und wo? Das ist undefiniert. Die Sprachspezifikation gibt nicht an, ob der Zugriff auf arrayOFMagic.array.length erfolgreich sein soll. Siehe auch: Generics Oddity - Ich kann einen Long-Wert in eine Map einfügen & lt; String, String & gt; und es kompiliert und scheitert nicht zur Laufzeit

Vorschlag: Verwenden Sie nicht T[] array ; benutze einfach Object[] array .

    
ZhongYu 11.09.2013 16:45
quelle
1

Bei Verwendung eines generischen Typs erstellt der Compiler verborgene Umwandlungen, sodass die Ausnahme aufgrund einer falschen Array-Erstellung auftritt. Aber Sie können das Array mit dem richtigen Typ erstellen, indem Sie den Konstruktor mithilfe von java ändern .lang.reflect.Array :

%Vor%     
Arne Burmeister 11.09.2013 17:59
quelle
1

Es ist höchst lehrreich, dies ohne Generika zu schreiben. Jedes Programm, das mit Generika geschrieben wurde, kann in ein gleichwertiges Programm konvertiert werden, indem nur Generika entfernt und Umwandlungen hinzugefügt werden. Diese Konvertierung wird type-Löschung genannt. Nach dem Löschen wird deutlich, was passiert:

%Vor%

(In diesem Fall könnten Sie argumentieren, dass die Umwandlung in Integer[] unnötig ist. Ein intelligenter Compiler könnte dies eliminieren, da Object[] bereits das Feld length hat. In der Regel jedoch immer Wenn Sie etwas von der generischen Klasse in das "Äußere" des generischen Bereichs holen, wird es in den entsprechenden Typ umgewandelt, wobei das Argument type ersetzt wird.)

    
newacct 11.09.2013 21:53
quelle

Tags und Links