Wie wirkt sich die Java-Löschung auf die generischen Arrays aus?

9

Ich studiere Generika in dieser Zeit und heute habe ich dieses Geheimnis für mich gefunden.

Betrachten wir die folgende Dummy-Klasse:

%Vor%

Wegen des Löschens wird der Rückgabetyp T [] der Methode getArray () zur Laufzeit in ein Objekt [] umgewandelt, was für mich völlig vernünftig ist.

Wenn wir auf diese Methode zugreifen, wie sie ist (c.getArray ()), werden keine Exceptions ausgelöst, aber wenn wir versuchen, einige Methoden für das zurückgegebene Array aufzurufen, zum Beispiel c.Array (). getClass () oder if wir versuchen, auf ein Feld zuzugreifen, zum Beispiel c.getArray (). length, dann wird die folgende Ausnahme ausgelöst:

  

Ausnahme im Thread "main" java.lang.ClassCastException:   [Ljava.lang.Object; kann nicht in [Ljava.lang.Integer;

umgewandelt werden

Warum wird diese Ausnahme ausgelöst? Warum wird es nicht auch für den einfachen Aufruf c.getArray () geworfen? Warum versucht es, in Integer [] zu konvertieren, wenn wir einfach getClass () aufrufen oder auf die Länge zugreifen? Sind getClass () und length nicht auch für Object []?

verfügbar?

Vielen Dank im Voraus für Ihre vielen (hoffe ich) und erklärenden (hoffe ich auch dies) Antworten.

    
acejazz 08.07.2016, 12:53
quelle

3 Antworten

1

Wenn Sie eine unsichere ungeprüfte Besetzung machen, kann es irgendwo eine Ausnahme geben oder nicht. Es ist nicht garantiert, dass irgendwo eine Ausnahme auftritt.

In diesem Fall hängt es davon ab, ob der Compiler eine Umwandlung in den gelöschten Code eingefügt hat, um das Ergebnis des Aufrufs in Integer[] zu konvertieren. In diesem Fall scheint eine Besetzung im zweiten und dritten Fall eingefügt worden zu sein, aber nicht im ersten Fall.

In jedem der drei Fälle darf der Compiler einen Cast einfügen (weil man annehmen darf, dass das Ergebnis Integer[] ist oder einen Cast nicht einfügt), weil der Ausdruck so verwendet wird, dass er nur benötigt wird Object[] in allen dreien. Ob eine Umwandlung eingefügt werden soll oder nicht, hängt von der jeweiligen Compiler-Implementierung ab.

Warum sollte dieser Compiler im ersten Fall keinen Cast einfügen und im zweiten und dritten Fall einen Cast einfügen? Eine offensichtliche Erklärung wäre, dass im ersten Fall das Ergebnis offensichtlich nicht verwendet wird, so dass es sehr einfach ist festzustellen, dass eine Umwandlung unnötig ist. Um festzustellen, ob eine Umwandlung notwendig ist, müsste im zweiten und dritten Fall untersucht werden, wie der Ausdruck verwendet wird, um zu sehen, dass er auch mit Object[] ; und das ist eine ziemlich komplizierte Analyse. Die Compiler-Autoren haben sich wahrscheinlich für einen einfachen Ansatz entschieden, bei dem sie die Besetzung nur dann überspringen, wenn das Ergebnis nicht verwendet wird.

Ein anderer Compiler könnte in allen drei Fällen Umwandlungen einfügen. Und ein anderer Compiler könnte in allen drei Fällen keine Umwandlungen haben. Sie können sich nicht darauf verlassen.

    
newacct 08.07.2016, 18:41
quelle
2

Der Grund für die Ausnahme ist, dass der Compiler eine Integer[] erwartet, aber eine Object[] . Es wurde ein Laufzeit-Cast hinzugefügt - an den Aufruf-Sites von getArray . Diese Modelle haben den Lügen-, Dummy- und Nicht-Effekt-Cast in Ihrem Konstruktor entdeckt.

Damit es korrekt ist, braucht man die tatsächliche Klasse von T, um Instanzen zu erzeugen.

%Vor%

Auch hier bleibt eine "unsichere" Umwandlung in T[] , aber dies ist unvermeidbar, da Array.newInstance eine Methode auf niedriger Ebene für n-dimensionale Arrays ist, wie in:

%Vor%     
Joop Eggen 08.07.2016 13:25
quelle
1

Ich konnte den genauen Ort in der JLS nicht finden, der besagt, dass dies das Verhalten ist, aber ich denke, der Grund ist etwa so:

Der Ausdruck:

%Vor%

entspricht ungefähr:

%Vor%

wo der Cast wegen Type Erase hinzugefügt werden muss. Diese implizite Umwandlung fügt einen checkcast -Befehl in den Bytecode ein, der mit einem ClassCastException fehlschlägt, da c.getArray() vom Typ Object[] ist.

Blick auf den Bytecode für:

%Vor%

wir bekommen:

%Vor%

Der einzige Unterschied in der explicit Version sind die drei Anweisungen:

%Vor%

Was gibt es nur, weil ich das explizit in einer Variablen hinterlasse, so weit ich es verstehe.

    
Andy Turner 08.07.2016 13:43
quelle

Tags und Links