Warum bin ich mit dieser InstantiationException, die in Java beim Zugriff auf Finale, lokale Variablen?
Spielte ich mit einigen code, um eine "Schließung, wie" bauen ( funktioniert nicht btw )
Alles sah gut aus aber als ich versuchte, den Zugriff auf eine Finale lokale variable in den code, der Ausnahme InstantiationException
geworfen wird.
Wenn ich entfernen Sie den Zugriff auf die lokale variable, entweder indem Sie es insgesamt oder indem Sie class-Attribut statt, es wird keine exception passiert.
Der doc sagt: InstantiationException
Ausgelöst, wenn eine Anwendung versucht, eine Instanz einer Klasse mit der newInstance-Methode der Klasse Class, aber das angegebene Objekt der Klasse kann nicht instanziiert werden. Die Instanziierung kann fehlschlagen, für eine Vielzahl von Gründen, einschließlich, aber nicht beschränkt auf:
- das class-Objekt repräsentiert eine abstrakte Klasse, interface, array-Klasse, ein primitiver Typ oder void
- die Klasse hat keine nullary Konstruktor
Welchen anderen Grund haben könnte, dieses problem verursacht?
Hier ist der code. Kommentar/kommentieren Sie das Klassenattribut /lokale variable um den Effekt zu sehen (Linien 5 und 10 ).
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
class InstantiationExceptionDemo {
//static JTextField field = new JTextField();//works if uncommented
public static void main( String [] args ) {
JFrame frame = new JFrame();
JButton button = new JButton("Click");
final JTextField field = new JTextField();//fails if uncommented
button.addActionListener( new _(){{
System.out.println("click " + field.getText());
}});
frame.add( field );
frame.add( button, BorderLayout.SOUTH );
frame.pack();frame.setVisible( true );
}
}
class _ implements ActionListener {
public void actionPerformed( ActionEvent e ){
try {
this.getClass().newInstance();
} catch( InstantiationException ie ){
throw new RuntimeException( ie );
} catch( IllegalAccessException ie ){
throw new RuntimeException( ie );
}
}
}
Ist das ein bug in Java?
Bearbeiten
Oh, ich vergaß, der stacktrace ( wenn geworfen ) ist:
Caused by: java.lang.InstantiationException: InstantiationExceptionDemo$1
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at _.actionPerformed(InstantiationExceptionDemo.java:25)
- Welche Zeile wird die exception geworfen?
- 25:
this.getClass().newInstance()
- Ich bin verwirrt über die syntax der anonymen inneren Klasse. Soll dies der Konstruktor?
- Es ist ein block-Initialisierer.
- Nicht den Initialisierung-block von einem anonymen Klasse müssen statisch sein? (Ich habe nie wirklich versucht, diese).
- Es gibt zwei Arten der Initialisierung blockiert, Klasse und Instanz-Initialisierer Initialisierungen, wie alles andere, das erste verwendet
static
und die erstere nicht. Der Effekt ist, den Initialisierung-block wird ausgeführt, bevor der Konstruktor. Es ist nicht weit verbreitet, weil es die Konstruktoren in den ersten Platz, während diestatic {}
Konstrukt ist die alternative zum initialisieren der Klasse Ressourcen, weil es nicht "Klasse" Konstruktoren. - Dies wird oft verwendet in Schwung. Zum Beispiel: ` JLabel label = new JLabel("Hallo"){{ setFont( new Font("Arial", Font.PLAIN, 32 ));}};`
- Ich bin vertraut mit beiden Arten initialisiert, war sich aber nicht sicher sind, welche Arten geeignet sind, im Falle einer anonymen Klasse. Ich in der Regel nur definieren einen Konstruktor, der im Nachhinein ist wahrscheinlich eine Verschwendung von Speicherplatz.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gut, das macht Sinn.
Nur die erste Instanz der
_
Klasse hat Zugriff auf die lokale variable. Nachfolgenden Instanzen nicht, es sei denn, Sie bieten Ihnen mit über constructor-arg)Ausgänge 1. (
a
ist die Instanz der anonymen Klasse)Sagte, ich glaube nicht, dass dies ist ein guter Weg, um zu implementieren Verschlüsse. Die Initialisierung-block wird mindestens einmal aufgerufen werden, ohne dass es. Ich nehme an, Sie sind nur Herumspielen, aber werfen Sie einen Blick auf lambdaj. Oder warten, bis Java 7 🙂
Hier ein Auszug der
javap -c InstantiationExceptionDemo$1
desstatic field
version:Und hier ist die
javap -c InstantiationExceptionDemo$1
desfinal
lokale variable version:So ist Ihre Ursache: die
final
lokale variable version muss ein zusätzliches argument, dieJTextField
Referenz in den Konstruktor. Es hat keine nullary Konstruktor.Dies macht Sinn, wenn man darüber nachdenkt. Anderes, wie ist diese version von
InstantiationExceptionDemo$1
gehen, um dasfield
Referenz? Der compiler versteckt die Tatsache, dass dies gegeben ist, die als parameter der synthetischen Konstruktor.Danke Euch beiden Bozho und Polygenlubricants für die erleuchtenden Antworten.
So, der Grund dafür ist ( in meinen eigenen Worten )
Wenn Sie ein lokales Letzte variable, erstellt der compiler einen Konstruktor mit den Feldern verwendet, die durch die anonyme innere Klasse und ruft ihn. Auch "Spritzen" - Feld mit den Werten.
So, was ich Tat, war, zu ändern, meine Schöpfung zu laden die richtigen Konstruktor mit den richtigen Werten mit Reflexion.
Dies ist der resultierende code:
Natürlich, wie Bozho Punkte heraus, ist dies nicht ein guter Weg ( nicht, es ist ein Weg, aber nicht eine gute ) zu erstellen, Verschlüsse.
Gibt es zwei Probleme.
1.- Die block-Initialisierer wird aufgerufen, wenn es deklariert ist.
2.- Es gibt keinen Weg, die Parameter des eigentlichen Codes ( ie actioneEvent in actionPerformed )
Wenn wir verzögern die Ausführung der Initialisierung dieser block wäre ein schönes ( im Sinne der syntax ) - Schließung alternative.
Vielleicht in Java 7 🙁