I was playing with some code to make a "closure like" construct ( not working btw )
Everything looked fine but when I tried to access a final local variable in the code, the exception InstantiationException
is thrown.
If I remove the access to the local variable either by removing it altogether or by making it class attribute instead, no exception happens.
The doc says: InstantiationException
Thrown when an application tries to create an instance of a class using the newInstance method in class Class, but the specified class object cannot be instantiated. The instantiation can fail for a variety of reasons including but not limited to:
- the class object represents an abstract class, an interface, an array class, a primitive type, or void
- the class has no nullary constructor
What other reason could have caused this problem?
Here's the code. comment/uncomment the class attribute / local variable to see the effect (lines:5 and 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 );
}
}
}
Is this a bug in Java?
edit
Oh, I forgot, the stacktrace ( when thrown ) is:
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)
How to Resolve InstantiationException. To avoid the InstantiationException , it should be ensured that the instance of the class that is attempted to be created at runtime using Class. newInstance() is a concrete class and not an abstract class, interface, array class, primitive or void.
A local variable in Java is a variable that's declared within the body of a method. Then you can use the variable only within that method. Other methods in the class aren't even aware that the variable exists. If we are declaring a local variable then we should initialize it within the block before using it.
Class variables also known as static variables are declared with the static keyword in a class, but outside a method, constructor or a block.
Well, that makes sense.
Only your first instance of the _
class has access to the local variable. Subsequent instances can't, unless you provide them with it (via constructor arg)
Constructor[] constructor = a.getClass().getDeclaredConstructors();
for (Constructor c : constructors) {
System.out.println(c.getParameterTypes().length);
}
outputs 1. (a
is the instance of your anonymous class)
That said, I don't think this is a good way to implement closures. The initializer block is called at least once, without the need of it. I assume you are just playing around, but take a look at lambdaj. Or wait for Java 7 :)
Here's an excerpt of the javap -c InstantiationExceptionDemo$1
of the static field
version:
Compiled from "InstantiationExceptionDemo.java"
class InstantiationExceptionDemo$1 extends _{
InstantiationExceptionDemo$1();
Code:
0: aload_0
1: invokespecial #8; //Method _."<init>":()V
4: getstatic #10; //Field InstantiationExceptionDemo.field:
//Ljavax/swing/JTextField;
And here's the javap -c InstantiationExceptionDemo$1
of the final
local variable version:
Compiled from "InstantiationExceptionDemo.java"
class InstantiationExceptionDemo$1 extends _{
InstantiationExceptionDemo$1(javax.swing.JTextField);
Code:
0: aload_0
1: invokespecial #8; //Method _."<init>":()V
4: aload_1
So there's your cause: the final
local variable version needs an extra argument, the JTextField
reference, in the constructor. It has no nullary constructor.
This makes sense if you think about it. Else, how is this version of InstantiationExceptionDemo$1
going to get the field
reference? The compiler hides the fact that this is given as a parameter to the synthetic constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With