• Java -- 浅入Java反射机制


    1,Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。

      Java 反射机制主要提供了以下功能:
      在运行时判断任意一个对象所属的类。
      在运行时构造任意一个类的对象。
      在运行时判断任意一个类所具有的成员变量和方法。
      在运行时调用任意一个对象的方法。

      在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
      Class类:代表一个类。
      Field 类:代表类的成员变量(成员变量也称为类的属性)。
      Method类:代表类的方法。
      Constructor 类:代表类的构造方法。
      Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

    2,通过Class对象获取成员变量、成员方法、接口、超类、构造方法等。

      API中给我们提供了一下方法

    getName():获得类的完整名字。
    getFields():获得类的public类型的属性。
    getDeclaredFields():获得类的所有属性。
    getMethods():获得类的public类型的方法。
    getDeclaredMethods():获得类的所有方法。
    getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
    getConstructors():获得类的public类型的构造方法。
    getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
    newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
    

      下面就先从是用来说起吧

    • 通过对象获取完整的包名和类名
    public class TestReflect{
        public static void main(String[] args){
            TestReflect testReflect = new TestReflect();
            System.out.println(testReflect.getClass().getName());
        }
    }
    • 实例化class类对象
    package com.qianmo.flowlayout.reflection;
    
    import java.io.Serializable;
    import java.lang.reflect.Array;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Objects;
    
    /**
     * Created by wangjitao on 2017/3/28 0028.
     * E-Mail:543441727@qq.com
     * Java反射机制的简单实现
     */
    
    public class TestReflect{
    
    
        /**
         * @param args
         */
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
         
    
            Class<?> class1 = null;
            Class<?> class2 = null;
            Class<?> class3 = null;
    
            class1 = Class.forName("com.qianmo.flowlayout.reflection.TestReflect");
            class2 = new TestReflect().getClass();
            class3 =TestReflect.class;
            System.out.println("类名称:"+class1.getName());
            System.out.println("类名称:"+class2.getName());
            System.out.println("类名称:"+class3.getName());
    
        }
    }
    
    • 获取对象父类和实现的接口
    package com.qianmo.flowlayout.reflection;
    
    import java.io.Serializable;
    import java.lang.reflect.Array;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Objects;
    
    /**
     * Created by wangjitao on 2017/3/28 0028.
     * E-Mail:543441727@qq.com
     * Java反射机制的简单实现
     */
    
    public class TestReflect{
    
    
        /**
         * @param args
         */
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
          Class<?> clazz =  Class.forName("com.qianmo.flowlayout.reflection.TestReflect");
            //获取父类
            Class<?> superClazz = clazz.getSuperclass();
            System.out.println("父类名称:"+superClazz.getName());
            //获取所有接口
            Class<?> intes[] = clazz.getInterfaces();
            for (int i = 0; i < intes.length; i++) {
                System.out.println("实现的接口有:"+intes[i].getName());
            }
        }
    }
    
    • 通过反射得到一个类中的全部构造函数

      先创建User类

    package com.qianmo.flowlayout.reflection;
    
    
    /**
     * Created by wangjitao on 2017/3/29 0029.
     * E-Mail:543441727@qq.com
     */
    
    public class User {
        private int age;
        private String name;
    
        public User() {
            super();
    
        }
    
        public User(int age) {
            super();
            this.age = age;
        }
    
        public User(String name) {
            super();
            this.name = name;
        }
    
        public User(int age, String name) {
            super();
            this.age = age;
            this.name = name;
    
        }
    
        public int getAge() {
            System.out.println("Java 反射机制 - 调用某个类的方法1.");
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
            System.out.println("Java 反射机制 - 调用某个类的方法2.");
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "User [age=" + age + ",name:" + name + "]";
        }
    }
    

      在main方法中调用

    package com.qianmo.flowlayout.reflection;
    
    import java.io.Serializable;
    import java.lang.reflect.Array;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Objects;
    
    /**
     * Created by wangjitao on 2017/3/28 0028.
     * E-Mail:543441727@qq.com
     * Java反射机制的简单实现
     */
    
    public class TestReflect{
    
    
        /**
         * @param args
         */
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
          Class<?> class1 = null;
            class1 = Class.forName("com.qianmo.flowlayout.reflection.User");
            //第一种方法使用默认的构造方法
            User user_one = (User) class1.newInstance();
            user_one.setAge(20);
            user_one.setName("wangjitao");
            System.out.println(user_one);
    
            //第二种获取所有构造方法,使用构造函数赋值
            Constructor<?> cons[] =  class1.getConstructors();
            //查看每一个构造方法中所需要的参数
            for (int i = 0; i < cons.length; i++) {
                System.out.print("cons[" + i + "] (");
                Class<?> clazzs[] = cons[i].getParameterTypes();
                for (int j = 0; j <clazzs.length ; j++) {
                    System.out.print(clazzs[j].getName()+",");
                }
                System.out.println(")");
            }
    
            //通过获取到的构造函数创建对象
            user_one = (User) cons[0].newInstance(24,"wangjitao04");
            System.out.println(user_one);
            user_one = (User) cons[1].newInstance("wangjitao04");
            System.out.println(user_one);
        }
    }
    
    • 获取类中全部属性
        Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
            //获取本类中的全部属性
            Field[] field = clazz.getDeclaredFields();
            for (int i = 0; i < field.length; i++) {
                //权限修饰符
                String priv = Modifier.toString(field[i].getModifiers());
                //属性类型
                Class<?> type = field[i].getType();
                System.out.println("修饰符:" + priv + ",属性类型:" + type.getName());
    
            }
            //获取实现的接口或者父类的属性
            Field[] fild1 = clazz.getFields();
            for (int i = 0; i <fild1.length ; i++) {
                int mo = fild1[i].getModifiers();
                String priv = Modifier.toString(mo);
                // 属性类型
                Class<?> type = fild1[i].getType();
                System.out.println(priv + " " + type.getName() + " " + fild1[i].getName() + ";");
            }
    
    • 获取类中的全部方法
        Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
            Method method[] = clazz.getMethods();
            for (int i = 0; i < method.length; i++) {
                Class<?> returnType = method[i].getReturnType();
                Class<?> para[] = method[i].getParameterTypes();
                int temp = method[i].getModifiers();
                System.out.println(method[i].getName() + "," + returnType.getName() + "," + Modifier.toString(temp));
                for (int j = 0; j < para.length; j++) {
                    System.out.print(para[j].getName());
                }
            }
    
    • 通过反射调用类中的方法
            Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
            Method method = clazz.getMethod("getAge");
            method.invoke(clazz.newInstance());
    
            method = clazz.getMethod("setAge", int.class);
            method.invoke(clazz.newInstance(), 20);        
    • 通过反射操作类中的属性(包括私有属性)
            Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
            User user = (User) clazz.newInstance();
            Field field = clazz.getDeclaredField("age");
            field.setAccessible(true);
            field.set(user, 50);
            System.out.print(field.get(user));    
    

      通过以上的这些我们基本上可以在运行时候拿到一个类中成员变量、成员方法、接口、超类、构造方法等信息。

    3,深入了解反射机制

      一般来说Java中使用Class.fromName()函数来生成Class对象,那我们来看看源码(这里只展示了主要的部分)

    .......省略........
    @CallerSensitive
        public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            return forName(className, true, VMStack.getCallingClassLoader());
        }
    
    
     .......省略...........
    
      @CallerSensitive
        public static Class<?> forName(String name, boolean initialize,
                                       ClassLoader loader)
            throws ClassNotFoundException
        {
            if (loader == null) {
                loader = BootClassLoader.getInstance();
            }
            Class<?> result;
            try {
                result = classForName(name, initialize, loader);
            } catch (ClassNotFoundException e) {
                Throwable cause = e.getCause();
                if (cause instanceof LinkageError) {
                    throw (LinkageError) cause;
                }
                throw e;
            }
            return result;
        }
    
    /** Called after security checks have been made. */
        static native Class<?> classForName(String className, boolean shouldInitialize,
                ClassLoader classLoader) throws ClassNotFoundException;
    

      Class.forName(classname)方法,实际上是调用了Class类中的 Class.forName(classname, true, currentLoader)方法。参数:name - 所需类的完全限定名;initialize - 是否必须初始化类;loader - 用于加载类的类加载器。currentLoader则是通过调用ClassLoader.getCallerClassLoader()获取当前类加载器的。类要想使用,必须用类加载器加载,所以需要加载器。反射机制,不是每次都去重新反射,而是提供了cache,每次都会需要类加载器去自己的cache中查找,如果可以查到,则直接返回该类。 

      而java的类加载器也很有意思,分为一下四类

    BootStrap Class Loader(引导类加载器);
    Extensions Class Loader (扩展类加载器);
    App ClassLoader(或System Class Loader);
    Custom ClassLoader(用户自定义类加载器)
    

      类在加载的过程中,首先判断类是否被加载过,检测过程自底向上,首先从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。这里如果没有检测到则调用BootStrap ClassLoader加载器

        这幅图简单的说明了类加载器的类加载过程。先检查自己是否已经加载过该类,如果加载过,则直接返回该类,若没有则调用父类的loadClass方法,如果父类中没有,则执行findClass方法去尝试加载此类,也就是我们通常所理解的片面的"反射"了。这个过程主要通过ClassLoader.defineClass方法来完成。defineClass 方法将一个字节数组转换为 Class 类的实例(任何类的对象都是Class类的对象)。这种新定义的类的实例需要使用 Class.newInstance 来创建,而不能使用new来实例化。

  • 相关阅读:
    全局函数和静态函数
    C语言变量总结
    #ifdef、#ifndef 与 #endif
    #include与#define的意义
    exit
    字符常量
    void *:万能指针
    算法(Algorithms)第4版 练习 链表类 1.3.19~1.3.29
    算法(Algorithms)第4版 练习 1.3.219
    算法(Algorithms)第4版 练习 1.3.20
  • 原文地址:https://www.cnblogs.com/wjtaigwh/p/6640748.html
Copyright © 2020-2023  润新知