为什么我在访问最终局部变量时在Java中有这个InstantiationException?

Osc*_*Ryz 9 java instantiationexception

我正在玩一些代码来制作一个"封闭式"构造(不工作顺便说一句)

一切看起来都不错但是当我尝试访问代码中的最终局部变量时,InstantiationException抛出了异常.

如果我通过完全删除局部变量或通过改为使用类属性来删除对局部变量的访问,则不会发生异常.

该文档说:InstantiationException

当应用程序尝试使用类Class中的newInstance方法创建类的实例时抛出,但无法实例化指定的类对象.实例化可能由于各种原因而失败,包括但不限于:

- 类对象表示抽象类,接口,数组类,基元类型或void

- 该类没有空构造函数

还有什么其他原因可能导致这个问题?

这是代码.注释/取消注释类属性/局部变量以查看效果(行:5和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 );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是Java中的错误吗?

编辑

哦,我忘了,堆栈跟踪(抛出时)是:

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)
Run Code Online (Sandbox Code Playgroud)

Boz*_*zho 8

嗯,这是有道理的.

只有您的第一个_类实例才能访问本地变量.后续实例不能,除非你提供它(通过构造函数arg)

Constructor[] constructor = a.getClass().getDeclaredConstructors();
for (Constructor c : constructors) {
     System.out.println(c.getParameterTypes().length);
}
Run Code Online (Sandbox Code Playgroud)

输出1.(a是您的匿名类的实例)

也就是说,我不认为这是实现闭包的好方法.初始化块至少被调用一次,而不需要它.我假设你只是在玩,但看看lambdaj.或者等待Java 7 :)


pol*_*nts 6

以下javap -c InstantiationExceptionDemo$1是该static field版本的摘录:

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;
Run Code Online (Sandbox Code Playgroud)

javap -c InstantiationExceptionDemo$1final局部变量版本:

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
Run Code Online (Sandbox Code Playgroud)

所以这是你的原因:final局部变量版本JTextField在构造函数中需要一个额外的参数,即引用.它没有nullary构造函数.

如果你考虑一下,这是有道理的.否则,这个版本InstantiationExceptionDemo$1将如何获得field参考?编译器隐藏了这个作为合成构造函数的参数给出的事实.