java反射与内部类

时间记录:2019-11-19

问题描述: 今天在使用 quartz 开始定时任务的时候,我当时考虑到实现 job 不会给外部使用的情况下,使用了内部的私有类,然后发现其不能够进行实例化操作,然后看了下源码,发现其实通过反射的方式将类进行实例化的,然后我当时写的任务类的问题,导致了其通过反射的方式不能够实例化。
下面探索下反射的方式进行的实例化操作,为什么不行

第一部分: 私有类且没用进行无参构造函数显示创建

package com.huo;

/**
 * 反射的方式初始化测试
 * @author huoruilin
 */
public class TestReflection
{
    public static void main(String[] args)
    {
        try
        {
            Item item = (Item)Item.class.newInstance();
        }catch (IllegalAccessException | InstantiationException exception)
        {
            exception.printStackTrace();
        }
    }
    private class Item
    {

    }
}

然后很明显的是就会报找不到其无参的构造函数,如下报错内容

java.lang.InstantiationException: com.huo.TestReflection$Item
	at java.lang.Class.newInstance(Class.java:418)
	at com.huo.TestReflection.main(TestReflection.java:13)
Caused by: java.lang.NoSuchMethodException: com.huo.TestReflection$Item.<init>()
	at java.lang.Class.getConstructor0(Class.java:3069)
	at java.lang.Class.newInstance(Class.java:403)
	... 1 more

然后我们把其的无参构造函数显示的表示

 private class Item
    {
        public Item()
        {
            
        }
    }

然后依然是会报错,如下的报错

java.lang.InstantiationException: com.huo.TestReflection$Item
	at java.lang.Class.newInstance(Class.java:418)
	at com.huo.TestReflection.main(TestReflection.java:13)
Caused by: java.lang.NoSuchMethodException: com.huo.TestReflection$Item.<init>()
	at java.lang.Class.getConstructor0(Class.java:3069)
	at java.lang.Class.newInstance(Class.java:403)
	... 1 more

这个时候我想为什么会没有找到其的构造函数,难道内部类的构造函数有什么特殊的地方,还是说反射的方式查找的无参构造函数有什么特殊的地方,我们调试发现,其寻找的构造函数,确实有点特殊的地方。以及内部类中的构造函数的特殊地方。我们不免思考,这样的设计方式的目的在什么地方。

public T newInstance()
        throws InstantiationException, IllegalAccessException
    {
        if (System.getSecurityManager() != null) {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
        }

        // NOTE: the following code may not be strictly correct under
        // the current Java memory model.

        // Constructor lookup
        if (cachedConstructor == null) {
            if (this == Class.class) {
                throw new IllegalAccessException(
                    "Can not call newInstance() on the Class for java.lang.Class"
                );
            }
            try {
                Class<?>[] empty = {};
                //这个地方就是查找当前的类的构造函数的地方
                final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                // Disable accessibility checks on the constructor
                // since we have to do the security check here anyway
                // (the stack depth is wrong for the Constructor's
                // security check to work)
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                        public Void run() {
                                c.setAccessible(true);
                                return null;
                            }
                        });
                cachedConstructor = c;
            } catch (NoSuchMethodException e) {
                throw (InstantiationException)
                    new InstantiationException(getName()).initCause(e);
            }
        }
        Constructor<T> tmpConstructor = cachedConstructor;
        // Security check (same as in java.lang.reflect.Constructor)
        int modifiers = tmpConstructor.getModifiers();
        if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            if (newInstanceCallerCache != caller) {
                Reflection.ensureMemberAccess(caller, this, null, modifiers);
                newInstanceCallerCache = caller;
            }
        }
        // Run constructor
        try {
            return tmpConstructor.newInstance((Object[])null);
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            // Not reached
            return null;
        }
    }

getConstructor0 中我们看到了 Member.DECLARED 那么这个表示什么意思呢?
我们从源码中可以看到

Member is an interface that reflects identifying information about
a single member (a field or a method) or a constructor.
是一个反映有关单个成员(字段或方法)或构造函数的标识信息的接口。

DECLARED
标识类或接口的已声明成员的集合,不包括继承的成员。

我们来看具体的方法信息

 private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
                                        int which) throws NoSuchMethodException
    {
        //这一步有找到其的构造函数,且数量为1,然后再下面的判断中被舍弃,然后报找不到方法
        Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
        for (Constructor<T> constructor : constructors) {
            if (arrayContentsEq(parameterTypes,
                                constructor.getParameterTypes())) {
                return getReflectionFactory().copyConstructor(constructor);
            }
        }
        throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
    }

我们来看下 arrayContentsEq 的意思,比较的意思是查看当前的构造函数是不是无参构造函数

 private static boolean arrayContentsEq(Object[] a1, Object[] a2) {
        if (a1 == null) {
            return a2 == null || a2.length == 0;
        }

        if (a2 == null) {
            return a1.length == 0;
        }
        //这里直接返回了
        if (a1.length != a2.length) {
            return false;
        }

        for (int i = 0; i < a1.length; i++) {
            if (a1[i] != a2[i]) {
                return false;
            }
        }

        return true;
    }

这里导致的其,没有无参构造函数,也就是指返回的构造函数不是无参构造函数,那么这个构造函数代表的是什么含义,我们来自己来获取下这个构造函数,看看为什么不是无参构造函数

package com.huo;

import java.lang.reflect.Constructor;

/**
 * 反射的方式初始化测试
 * @author huoruilin
 */
public class TestReflection
{
    public static void main(String[] args)
    {
        Constructor[] constructors = Item.class.getDeclaredConstructors();
        for(Constructor c:constructors){
            System.out.println(c);
        }
    }
    
    private class Item
    {
        public Item()
        {
        
        }
    }
}

结果如下,我们发现了其会带上 TestReflection 这个外部类

public com.huo.TestReflection$Item(com.huo.TestReflection)

我们来看下真正执行的class文件中的内容一探究竟,我们看下TestReflection$Item.class这个内部类的实际执行内容

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.huo;

class TestReflection$Item {
    public TestReflection$Item(TestReflection var1) {
        this.this$0 = var1;
    }
}

很明显其没有显示的无参构造函数,而且java文件中的无参构造直接被忽略了,从而导致了反射的方式实例化的方式没有成功。从这里我们可以和上面的查找其构造函数对应上了,其找到一个构造函数的原因。然后内部类是和外部的类进行关联的,想要创建内部的类,就需要先创建外部的类,然后才能创建内部的类,所以这里的构造函数会传一个外部的类。如果是一个静态的内部类我们会发现其是有无参构造函数的,然后这个内部类是独立的无需与外部类进行关联。

总结:
1 反射的方式进行实例化的操作是要查找其无参构造函数的,先从缓存中查找,缓存中没有查找到,再去虚拟机中查找
2 内部类的编译会生成一个带其外部类的一个构造函数,而且会直接忽视了其java中的无参构造,不参与 了编译【还是需要了解下编译的规则】

时间记录:2019-11-19

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Java反射可以获取一个类中的所有方法。实现思路如下: 1. 使用`Class.forName()`方法获取指定的Class对象。 2. 使用`getMethods()`或`getDeclaredMethods()`方法获取类中的所有方法。 3. 可以通过遍历获取到的方法数组来获取每个方法的详细信息。 下面是一个使用Java反射获取类中所有方法的示例代码: ```java import java.lang.reflect.Method; public class ReflectionExample { public static void main(String\[\] args) throws ClassNotFoundException { Class<?> clazz = Class.forName("com.example.MyClass"); // 替换为你要获取方法的类的完整路径 Method\[\] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getName()); } } } class MyClass { public void method1() { // 方法1的实现 } private void method2() { // 方法2的实现 } protected void method3() { // 方法3的实现 } } ``` 在上述示例中,我们使用`Class.forName()`方法获取了指定类的Class对象,然后使用`getDeclaredMethods()`方法获取了该类中的所有方法。最后,我们通过遍历方法数组,使用`getName()`方法获取每个方法的名称并打印出来。 请注意,上述示例中的类名和方法名仅作为示例,你需要根据你的实际情况替换为你要获取方法的类的完整路径和方法名。 #### 引用[.reference_title] - *1* [如何使用Java反射机制获取一个类中全部方法呢?](https://blog.csdn.net/qq_25073223/article/details/126136202)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Java反射调用类的私有方法和内部类的私有方法](https://blog.csdn.net/weixin_45644323/article/details/120753661)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值