Java 的内部类反射,使用 newInstance 总是抛 NoSuchMethodException 异常呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
amiwrong123
V2EX    程序员

Java 的内部类反射,使用 newInstance 总是抛 NoSuchMethodException 异常呢?

  •  
  •   amiwrong123 2019 年 7 月 22 日 5140 次点击
    这是一个创建于 2375 天前的主题,其中的信息可能已经有所发展或是发生改变。
    package com.prac; public class outer { int i = 1; private static class staticInner{ int j = 2; staticInner(){} void print(){ System.out.println("in staticInner"); } } private class normalInner{ int k =3; void print(){ System.out.println("in normalInner"); } } } 

    外部类,里面有一个静态内部类,非静态内部类,它们都是私有的。

    import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import com.prac.outer; public class test2 { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { outer ooo = new outer(); Class<?> clazz = null; try { clazz = Class.forName("com.prac.outer$normalInner"); System.out.println(clazz.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } Constructor<?> con = clazz.getDeclaredConstructor(); Object obj = con.newInstance(); } } 

    有一个测试类,我想试试用反射来创建私有的内部类实例,因为内部类是权限是私有的,所以获得 Class 引用只能通过 forName (不然就可以 import 这个内部类,然后通过类名.class来获得了)。

    当 31 行,为clazz = Class.forName("com.prac.outer$normalInner")即获得非静态内部类 Class 的引用,然后 newInstance 报错:

    com.prac.outer$normalInner Exception in thread "main" java.lang.NoSuchMethodException: com.prac.outer$normalInner.<init>() at java.base/java.lang.Class.getConstructor0(Class.java:3354) at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2558) at test2.main(test2.java:38) 

    看起来好像是这篇博客讲的原因: https://www.jianshu.com/p/ecda088dcc5f 即非静态内部类构造时,构造函数会隐式地加一个 this 即外部类的引用。但这种情况还有解决办法吗?

    当 31 行为clazz = Class.forName("com.prac.outer$staticInner")即获得静态内部类 Class 的引用,然后 newInstance 报错:

    com.prac.outer$staticInner Exception in thread "main" java.lang.IllegalAccessException: class test2 cannot access a member of class com.prac.outer$staticInner with modifiers "" at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:376) at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:639) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:490) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) at test2.main(test2.java:39) 

    为什么这个就直接报错,有标识符的成员类就无法访问,因为是静态内部类吗?这种情况还有解决办法吗?

    8 条回复    2019-07-23 14:51:25 +08:00
    shily
        1
    shily  
       2019 年 7 月 22 日
    测试一下就知道了啊,错误报在 getDeclaredConstructor(),这个是返回无参数的构造上。你已经通过博客知道,默认的非静态内部类会捕获外部类引用。

    通过 clazz.getDeclaredConstructors() 可以知道它有一个构造,<init>(com.prac.outer),所以很容易修正啊。
    通过 Constructor<?> con = clazz.getDeclaredConstructor(outer.class); 来获取构造方法
    调用时是 Object obj = con.newInstance(ooo);
    amiwrong123
        2
    amiwrong123  
    OP
       2019 年 7 月 22 日
    @shily
    好吧,原来是我 getDeclaredConstructor 用的不对,谢谢回答啦。
    但是,现在就报错:
    com.prac.outer$normalInner
    Exception in thread "main" java.lang.IllegalAccessException: class test2 cannot access a member of class com.prac.outer$normalInner with modifiers "private"
    at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:376)
    at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:639)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:490)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    at test2.main(test2.java:39)
    所以不管是静态内部类还是非静态内部类,只要访问权限是私有,就不可以创建实例了吗
    bringyou
        3
    bringyou  
       2019 年 7 月 22 日
    contructor.setAccessible(true)
    codeyung
        4
    codeyung  
       2019 年 7 月 22 日
    setAccessible
    amiwrong123
        5
    amiwrong123  
    OP
       2019 年 7 月 23 日
    @bringyou
    好吧,现在成功了。谢谢回答啦。
    Constructor<?> con = clazz.getDeclaredConstructor(outer.class);
    con.setAccessible(true);
    Object obj = con.newInstance(ooo);
    但这种情况下,我是不是只能用 Object 引用来指向这个实例,因为没法 import 私有内部类,所以也无法用私有内部类类型来声明变量了?
    palmers
        6
    palmers  
       2019 年 7 月 23 日
    这种情况出现的原因,我认为有两方面:
    1. 内部类实例化无参构造是有一个影藏参数就是外部类指针 this, 所以其实不是相比正常的无参构造它并不是无参构造; 非 static 需要先实例化外部类,所以需要这样:
    ```java
    outer ot = new outer();
    Class<?> clazz = Class.forName("com.prac.outer$normalInner");
    Constructor<?> cOnstructor= clazz.getDeclaredConstructor(outer.class);
    Object o = constructor.newInstance(ot);
    ```
    2. 对于私有类或方法外部访问都是拒绝的, 需要解决访问权限问题;

    以上问题解决了, 我想基本不会有问题了,希望能帮到你
    helloSpringBoot
        7
    helloSpringBoot  
       2019 年 7 月 23 日
    @amiwrong123 私有的目的不就是这样吗。。。。
    amiwrong123
        8
    amiwrong123  
    OP
       2019 年 7 月 23 日
    @palmers
    谢谢回答,现在都解决了。

    @helloSpringBoot
    虽然只能用 Object 引用来指向这个实例,但是有了这个实例我发现就可以做一些“坏事”了,比如获得私有成员。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1201 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 23:46 PVG 07:46 LAX 15:46 JFK 18:46
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86