Java中方法中定义的访问类

时间:2017-12-12 01:04:43

标签: java reflection

在Java中,是否可以通过某种方式(反射等)访问方法中定义的类?怎么样?

例如,我想在下面的示例中创建InnerClass的实例:

class Example {
    public void outerMethod() {
        class InnerClass {
            double d = 0;
        }
    }

    public void testMethod() {
        outerMethod::InnerClass instance = new outerMethod::InnerClass();
    }
}

感谢您的回答。

2 个答案:

答案 0 :(得分:0)

不,那是不可能的。在方法内声明的名称只能在方法本身内引用。本地类(以您的情况为例)在Java 8语言规范的第14.3节中定义。

https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-Block

答案 1 :(得分:0)

技术上有可能。
实际上这是一种黑客攻击,你应该避免在生产代码中使用这种做法。

示例:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class Example {

     public void outerMethod() {

        class InnerClass {

            private double d = 7.62;

            @Override
            public String toString() {
                return String.format("[%s] d = %f", this.getClass().getName(), d);
            }

        }

    }

    public void testMethod() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

        final Class<?> clazz = Class.forName("Example$1InnerClass");
        final Constructor<?> constructor = clazz.getDeclaredConstructor(Example.class);
        constructor.setAccessible(true);
        final Object instance = constructor.newInstance(this);

        System.out.println(instance);
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
         Example instance = new Example();
         instance.testMethod();
    }

}

这里我们首先通过他们的名字为我们的本地课程获取Class<?>
本地类名生成规则是编译器实现细节,可能会有所不同。 AFAIK javacECJ使用不同的方法 然后我们通过反射得到我们感兴趣的类的构造函数。
由于类没有定义构造函数,因此编译器会自动生成它,并且此构造函数不是公共的。所以我们在这里使用getDeclaredConstructor()方法 由于此类不是静态的(本地类不能定义为静态),因此构造函数的第一个也是唯一的参数是外部类引用。在我们的案例中Example 之后我们通过调用constructor.newInstance(this)来创建一个类的实例 this作为参数传递给构造函数。请参阅上面有关构造函数参数的说明。

最后,我们打印刚创建的对象,隐式调用InnerClass::toString()