反射之构造方法简单记录

前言

简单的记录使用反射获取构造方法碰到的问题。

代码列表

return instantiateClass(clazz.getDeclaredConstructor());

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) { ReflectionUtils.makeAccessible(ctor); return ctor.newInstance(args); } public static void makeAccessible(Constructor<?> ctor) { if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) { ctor.setAccessible(true); } }

正文

下面分析得到的结论

1、所以非public的方法都需要带有Declared这个单词的反射方法,才能得到
2、非public属性要想使用还是老老实实设置setAccessible(true)
3、获取私有内部类,需要给定一个外部类对象

问题列表

如何获取非public的构造方法

代码-例子

public class ConstructorTest {

    private ConstructorTest() {

    }

}
public class ConstructorMain {

    public static void main(String[] args) throws Exception{  

        Constructor constroctor = ConstructorTest.class.getDeclaredConstructor();
        constroctor.setAccessible(true);
        ConstructorTest entity = (ConstructorTest) constroctor.newInstance();
        System.out.println(entity);

    }
}



问题一、第二段代码可不可以用getConstructor?

分析一下这个getConstructor,里面有一行如下代码

return getConstructor0(parameterTypes, Member.PUBLIC);

getConstructor0代码中第二个参数与Member.PUBLIC比较为true

 Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));

privateGetDeclaredConstructors方法中如下代码返回public的构造方法

private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { res = publicOnly ? rd.publicConstructors : rd.declaredConstructors; }

返回为null,在getConstructor0中抛出异常
备注:所以非public的方法都需要带有Declared这个单词,才能得到

问题二、constroctor.setAccessible(true)为什么要设置这一行?

贪图省力,main方法直接写在ConstructorTest这个类中,发现不用setAccessible,照样可以运行。在main中,还可以直接访问私有方法呢。

public class ConstructorTest {

    private ConstructorTest() {

    }
    private void print() {System.out.println("yes");};

    public static void main(String[] args) {
        ConstructorTest ct = new ConstructorTest();
        ct.print();
    }
}

分析代码
newInstance里面的代码片段

public T newInstance(Object ... initargs) {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, null, modifiers);
            }
        }
}

这里main方法直接写在ConstructorTest这个类中,那么caller == clazz

 void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers) { if (caller == clazz) { // quick check return; // ACCESS IS OK } }

检查权限通过,因此不写setAccessible也是可行的

如果设置setAccessible(true)
会设置这样的属性

 obj.override = flag;

从上面可以知道if (!override) 直接跳过checkAccess权限检查
备注:所以,非public属性要想使用还是老老实实设置setAccessible(true)

获取私有内部类静态方法

在获取私有内部类方法的时候比较纠结,外部无法访问私有内部类,做了如下设计
1、ConstructorMain,提供一个方法tryPrivateConstructor,供ConstructorTest调用,传递Constructor
2、在ConstructorTest中提供一个printInnerClazz的public方法调用tryPrivateConstructor并传入私有变量的Constructor
3、在ConstructorMain的main中执行printInnerClazz
这里因为内部类私有,无法转化成具体内部类,可以让内部类实现一个接口,按照多态,强转成接口,使用接口调用具体方法,打印

代码-ConstructorTest

public class ConstructorTest {

    private class InnerClazz {

    }

    public void printInnerClazz() throws Exception{
        ConstructorMain.tryPrivateConstructor(InnerClazz.class.getDeclaredConstructor(ConstructorTest.class),this);
    }
}

代码-ConstructorMain

public class ConstructorMain {

    public static void tryPrivateConstructor(Constructor constructor,ConstructorTest thizz) throws Exception {
        constructor.setAccessible(true);
        System.out.println(constructor.newInstance(thizz));
    }

    public static void main(String[] args) throws Exception{  

        ConstructorTest ct = new ConstructorTest();
        ct.printInnerClazz();

    }
}

上面验证了constructor.setAccessible(true),以及getDeclaredConstructor。非静态内部类还需要一个外部类的对象,作为参数,所以它的构造函数默认就只有一个包含外部类对象的参数。
如果觉得使用getDeclaredConstructor容易错,那么就使用getDeclaredConstructors()[0],返回所有的构造方法,取第一个。

在getDeclaredConstructor中里面参数与实际的构造函数参数不一致,如果抛出异常

代码-getDeclaredConstructor

 if(arrayContentsEq(parameterTypes,constructor.getParameterTypes()))

arrayContextsEq比较他们的个数

备注:获取私有内部类,需要给定一个外部类对象

你可能感兴趣的:(反射)