Java通识 -- 反射解析

版权声明:转载原创博客请附上原文链接 https://blog.csdn.net/weixin_43495590/article/details/89146671

一:反射的意义

Refliction反射重大意义在于运行时期的数据信息获取、修改,例如Spring的AOP等经典应用

二:反射入口 – Class

2.1 class对象
        // Object提供的本地方法,只适用于引用类型
        Class<? extends Singleton> singletonClass1 = new Singleton().getClass();

        // Class提供的静态方法,
        Class<?> singletonClass2 = Class.forName("com.zsl.Singleton");
        
        // 隐藏属性class
        Class<Singleton> singletonClass3 = Singleton.class;
        
        // 封装类常量TYPE
        Class<Integer> type = Integer.TYPE;
  1. Object提供的getClass()以及Class提供的forName()都仅仅针对引用类型基本类型只适用于class隐藏属性
  2. Class提供的forName()实现如下所示,参数需要绝对路径,处理抛出异常ClassNotFoundException
  3. 八种基本类型的封装类都有一个TYPE常量储存Class对象
	
	// 参数需要为绝对路径
	// 上层调用需要处理异常
	// 利用类加载器组装对象
    @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
2.2 关联类
        // 调用类父类
        Class<? extends Singleton> singletonClass = new Singleton().getClass();
        Class<?> superclass = singletonClass.getSuperclass();
        System.out.println(superclass);

        // 调用类父类、接口,包括继承
        Class<?>[] classes = singletonClass.getClasses();
        
        // 调用类显示声明父类、接口
        Class<?>[] declaredClasses = singletonClass.getDeclaredClasses();

        // 属性、方法、构造器所在类(采用同一方法)
        Field flag = singletonClass.getDeclaredField("flag");
        Class<?> declaringClass = flag.getDeclaringClass();
        System.out.println(declaringClass);
2.3 :属性、方法、构造

属性、方法、构造函数获取操作按照两个维度划分,继承指定

  1. 继承维度上若需要获取父类信息则限定在pubic修饰范围内
        // 本类中与继承自父类的属性、方法、构造函数,被public修饰
        Field[] fields = fatherClassClass.getFields();
        ......

        // 本类中所有属性、方法、构造函数
        Field[] declaredFields = fatherClassClass.getDeclaredFields();
        ......
  1. 指定获取某属性参数为属性名字,获取方法参数为方法名字与形参类Class对象,获取构造函数参数为形参类Class对象
        // 指定属性
        Field name = fatherClassClass.getDeclaredField("name");

        // 指定方法
        Method test = fatherClassClass.getDeclaredMethod("test", String.class);
        
        // 指定构造函数
        Constructor<FatherClass> declaredConstructor = fatherClassClass.getDeclaredConstructor(String.class);

三:访问控制 – AccessibleObject

Field、Method、Constructor反射中分别定义属性、方法、构造函数的类都直接亦或是间接继承该抽象类,反射具备运行过程修改属性值、执行方法的能力,这时需要解决访问权限问题需要借助AccessibleObject类。类中方法setAccessible()通过修改访问状态标志flag控制属性、方法、构造函数是否可以被访问

    public void setAccessible(boolean flag) throws SecurityException {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
        setAccessible0(this, flag);
    }

四:修饰解码 – Modifier

Class类中本地方法getModifiers()获取类修饰符。Field、Method、Constructor中维护属性modifiers保存修饰符编码,getModifiers()方法返回该属性值

		// 修饰符描述编码
        int modifiers = FatherClass.class.getModifiers();
        // 调用Modifer类toString()解码修饰符
        System.out.println(Modifier.toString(modifiers));

查看Modifer方法toString()源码可以清晰的看到解码过程就是进行不断对比

    public static String toString(int mod) {
        StringBuilder sb = new StringBuilder();
        int len;

        if ((mod & PUBLIC) != 0)        sb.append("public ");
        if ((mod & PROTECTED) != 0)     sb.append("protected ");
        if ((mod & PRIVATE) != 0)       sb.append("private ");
        if ((mod & ABSTRACT) != 0)      sb.append("abstract ");
        if ((mod & STATIC) != 0)        sb.append("static ");
        if ((mod & FINAL) != 0)         sb.append("final ");
        if ((mod & TRANSIENT) != 0)     sb.append("transient ");
        if ((mod & VOLATILE) != 0)      sb.append("volatile ");
        if ((mod & SYNCHRONIZED) != 0)  sb.append("synchronized ");
        if ((mod & NATIVE) != 0)        sb.append("native ");
        if ((mod & STRICT) != 0)        sb.append("strictfp ");
        if ((mod & INTERFACE) != 0)     sb.append("interface ");

        if ((len = sb.length()) > 0)
            return sb.toString().substring(0, len-1);
        return "";
    }

五:成员属性 – Field

        Class<?> classz = Class.forName("com.zsl.FatherClass");
        FatherClass fatherClass = (FatherClass) classz.newInstance();
        Field name = classz.getDeclaredField("name");

        // 属性设置值,如果是包装类可选择对应方法
        name.set(fatherClass,"father");

        // 获取属性值,包装类也有对应专用方法
        String s = (String)name.get(fatherClass);
		
		// 获取属性类型
		System.out.println(name.getType());

Field类继承AccessibleObject抽象类,实现Member接口。里面主要实现属性值设置属性值获取属性类型获取等操作

六:成员方法 – Method

    private String              name;
    private Class<?>            returnType;
    private Class<?>[]          parameterTypes;
    private Class<?>[]          exceptionTypes;
    test.invoke(fatherClass,"111");

根据Method类属性可看出该类主要提供有关方法名字返回值类型异常参数类型参数数量等操作。方法执行invoke()指定对象与实参

七:实例构造 – Constructor

    private Class<?>[]          parameterTypes;
    private Class<?>[]          exceptionTypes;
Object o = classz.getDeclaredConstructor(String.class).newInstance("12");

Constructor类中针对构造器参数异常两方面做实现,方法newInstance()配合构造器实例进行对象的初始化

八:可变参处理

可变参底层实现采用数组实现,例如方法中存在可变参,反射操作获取方法需要形参Class对象则可以传入可变参类型数组Class对象

    public void test(String ... s){
        System.out.println("方法可变参");
    }
	
	// 反射获取方法需要传入数组
	Method test = classz.getDeclaredMethod("test",String[].class);
    String[] sarr = {"123"};
    // 方法执行需要将数组转换为Object对象
    test.invoke(fatherClass,(Object) sarr);

猜你喜欢

转载自blog.csdn.net/weixin_43495590/article/details/89146671
今日推荐