Warum habe ich diese InstantiationException in Java, wenn ich auf finale lokale Variablen zugreife?

8

Ich habe mit etwas Code gespielt, um ein "close-like" Konstrukt zu erstellen (funktioniert nicht übrigens)

Alles sah gut aus, aber als ich versuchte, auf eine letzte lokale Variable im Code zuzugreifen, wurde die Ausnahme InstantiationException ausgelöst.

Wenn ich den Zugriff auf die lokale Variable lösche, indem ich sie entweder komplett lösche oder indem ich sie stattdessen class-Attribut mache, geschieht keine Ausnahme.

Das Dokument sagt: InstantiationException

  

Wird ausgelöst, wenn eine Anwendung versucht, mithilfe der Methode newInstance in der Klasse Class eine Instanz einer Klasse zu erstellen, das angegebene Klassenobjekt jedoch nicht instanziiert werden kann. Die Instanziierung kann aus verschiedenen Gründen fehlschlagen, einschließlich, aber nicht beschränkt auf:

     

- Das Klassenobjekt repräsentiert eine abstrakte Klasse, eine Schnittstelle, eine Array-Klasse, einen primitiven Typ oder void

     

- Die Klasse hat keinen neuen Konstruktor

Welchen anderen Grund könnte dieses Problem verursacht haben?

Hier ist der Code. Kommentieren Sie das Klassenattribut / die lokale Variable, um den Effekt zu sehen (Zeilen: 5 und 10).

%Vor%

Ist das ein Fehler in Java?

Bearbeiten

Oh, ich habe vergessen, der Stacktrace (wenn er geworfen wird) ist:

%Vor%     
OscarRyz 25.05.2010, 17:31
quelle

3 Antworten

8

Nun, das macht Sinn.

Nur Ihre erste Instanz der Klasse _ hat Zugriff auf die lokale Variable. Nachfolgende Instanzen können nicht, es sei denn, Sie geben sie (über Konstruktor arg)

%Vor%

gibt 1. aus ( a ist die Instanz Ihrer anonymen Klasse)

Das heißt, ich glaube nicht, dass dies eine gute Möglichkeit ist, Schließungen zu implementieren. Der Initialisierungsblock wird mindestens einmal aufgerufen, ohne dass er benötigt wird. Ich nehme an, Sie spielen nur herum, aber schauen Sie sich lambdaj an. Oder warte auf Java 7:)

    
Bozho 25.05.2010, 18:02
quelle
6

Hier ist ein Auszug der javap -c InstantiationExceptionDemo der static field Version:

%Vor%

Und hier ist das javap -c InstantiationExceptionDemo der final lokalen Variablenversion:

%Vor%

Es gibt also Ihre Ursache: Die lokale Version von final benötigt ein zusätzliches Argument, den JTextField -Referenz, im Konstruktor. Es hat keinen neuen Konstruktor.

Das macht Sinn, wenn Sie darüber nachdenken. Sonst, wie wird diese Version von InstantiationExceptionDemo die field Referenz erhalten? Der Compiler verbirgt die Tatsache, dass dies dem synthetischen Konstruktor als Parameter übergeben wird.

    
polygenelubricants 25.05.2010 18:02
quelle
1

Danke Bozho und Polygenlubricants für die aufschlussreichen Antworten.

Also, der Grund ist (in meinen eigenen Worten)

Wenn eine lokale finale Variable verwendet wird, erstellt der Compiler einen Konstruktor mit den Feldern, die von der anonymen inneren Klasse verwendet werden, und ruft sie auf. Es "inject" auch ein Feld mit den Werten.

Also, was ich getan habe, war, meine Erstellung zu ändern, um den richtigen Konstruktor mit den richtigen Werten mittels Reflektion zu laden.

Dies ist der resultierende Code:

%Vor%

Natürlich, wie Bozho betont, ist dies kein guter Weg, um Schließungen zu schaffen (es ist kein Weg, aber kein guter Weg).

Es gibt zwei Probleme damit.

1.- Der Initialisierungsblock wird aufgerufen, wenn er deklariert wird.

2.- Es gibt keine Möglichkeit, die Parameter des tatsächlichen Codes zu erhalten (zB actioneEvent in actionPerformed)

Wenn wir die Ausführung des Initialisiererblocks nur verzögern könnten, würde dies eine nette (in Bezug auf die Syntax) Schließungsalternative ergeben.

Vielleicht in Java 7 :(

    
OscarRyz 25.05.2010 20:09
quelle

Tags und Links