• JAVA反射简介及应用


    反射简介及应用

    反射简介

    什么是反射

    JAVA反射机制在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

    java反射的作用

    在运行时判断任意一个对象所属的类

    在运行时构造任意一个类的对象

    在运行时判断任意一个类所具有的成员变量和方法

    在运行时调用任意一个对象的方法

    反射机制有什么用

    通过java语言中的反射机制可以操作字节码文件(可以读和修改字节码文件。)

    通过反射机制可以操作代码片段。(class文件。)

    哪里会用到反射机制

    Web服务器中利用反射调用了Sevlet的服务方法。

    Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。

    模块化的开发,通过反射去调用对应的字节码

    动态代理设计模式也采用了反射机制

    Spring/Hibernate 等框架,也是利用CGLIB 反射机制才得以实现:

    1. JDBC中,利用反射动态加载了数据库驱动程序。

    2. 很多框架都用到反射机制,注入属性,调用方法,如Spring。

    反射机制的应用场景有哪些

    1. 我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;
    2. Spring框架也用到很多反射机制,最经典的就是xml的配置模式。
    JDBC重点(Class.forName导致类加载)

    如果你只是希望一个类的静态代码块执行,其它代码一律不执行,可以使用:

    Class.forName(“完整类名”);

    这个方法的执行会导致类加载,类加载时,静态代码块执行。

    Spring 通过 XML 配置模式装载 Bean 的过程
    1. 将程序内所有 XML 或 Properties 配置文件加载入内存中;
    2. Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息;
    3. 使用反射机制,根据这个字符串获得某个类的Class实例;
    4. 动态配置实例的属性
    可查看数据库连接和Spring的反射案例:

    https://zhuanlan.zhihu.com/p/394766551

    反射机制的优缺点

    优点: 运行期类型的判断,动态加载类(在运行期间根据业务功能动态执行方法、访问属性),提高代码灵活度。

    缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

    反射机制的相关类在哪个包下

    java.lang.reflect.*;

    反射使用步骤(获取 Class 对象、调用对象方法)

    获取 Class 对象的三种方法

    1.通过new对象实现反射机制: 对象.getClass()

    2.通过路径实现反射机制: Class.forName(“完整类名带包名”) 静态方法

    例如:com.mysql.jdbc.Driver Driver类已经被加载到 jvm中,并且完成了类的初始化工作就行了

    3.通过类名实现反射机制: 任何类型(类名).class。 获取Class<?> clz 对象

    代码示例
    public class Student {
    	private int id;
    	String name;
     	protected boolean sex;
    	public float score;
    }
    
    public class Get {
    	//获取反射机制三种方式
    	public static void main(String[] args) throws ClassNotFoundException {
            //方式一(通过建立对象)
            Student stu = new Student();
            Class classobj1 = stu.getClass();
            System.out.println(classobj1.getName());
    
            //方式二(所在通过路径-相对路径)
            Class classobj2 = Class.forName("fanshe.Student");
            System.out.println(classobj2.getName());
    
            //方式三(通过类名)
            Class classobj3 = Student.class;
            System.out.println(classobj3.getName());
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    获取构造器对象,通过构造器new出一个对象

    Clazz.getConstructor([String.class]);

    Con.newInstance([参数]);

    通过反射 class对象创建一个实例对象

    相当与new类名()无参构造器

    Cls.newInstance(); //对象.newInstance()

    注:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。

    否则会抛出java.lang.InstantiationException异常。

    通过Class对象的newInstance()方法

    Object instance = clazz1.newInstance()

    代码示例
    class ReflectTest02{
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
            // 下面这段代码是以反射机制的方式创建对象。
            // 通过反射机制,获取Class,通过Class来实例化对象
            Class c = Class.forName("javase.reflectBean.User");
            // newInstance() 这个方法会调用User这个类的无参数构造方法,完成对象的创建。
            // 重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!
            Object obj = c.newInstance();
            System.out.println(obj);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    通过构造方法实例化对象,代码示例
    //取得无参构造
    Constructor<?> constructor2 = clazz1.getConstructor();
    //通过无参构造创建一个对象
    Object child1 = constructor2.newInstance();
    
    //取得指定参数的构造方法对象
    Constructor<?> constructor3 = clazz1.getConstructor(String.class, int.class);
    //通过构造方法对象创建一个对象
    constructor3.newInstance("wenpan",21);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    通过class对象获得一个属性对象

    获得某个类的所有的公共(public)的字段,包括父类中的字段

    Field c=cls.getFields()

    获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的声明字段

    Field c=cls.getDeclaredFields()

    通过class对象获得一个方法对象

    只能获取公共的

    Cls.getMethod(“方法名”,class……parameaType);

    获取任意修饰的方法,不能执行私有

    Cls.getDeclareMethod(“方法名”);

    让私有的方法可以执行

    M.setAccessible(true);

    让方法执行

    Method.invoke(obj实例对象,obj可变参数); //是有返回值的

    Java反射创建对象效率高还是通过new创建对象的效率高?

    new创建对象的效率高

    Java代码是需要编译后在虚拟机里面运行的。

    一般都是通过一个前端编辑器,比如javac,把java文件转为class文件。程序运行期间,可能会通过一个JIT,即时编译器将字节码文件转换为计算机认识的机器码文件。

    另外一种可能是通过一个AOT编译器,直接把java文件编译为本地机器码文件。

    其中JIT在程序运行期会对程序进行优化,但是反射是通过动态解析的方式,因此可能无法执行某些java虚拟机的优化。

    下方博客有代码示例说明

    Java反射和new效率对比_编程爱好者jony的博客-CSDN博客

    反射机制相关的重要的类有哪些

    含义
    java.lang.Class代表整个字节码。代表一个类型,代表整个类。
    java.lang.reflect.Method代表字节码中的方法字节码。代表类中的方法。
    java.lang.reflect.Constructor代表字节码中的构造方法字节码。代表类中的构造方法。
    java.lang.reflect.Field代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。

    注:必须先获得Class才能获取Method、Constructor、Field。

    Class代码示例
    java.lang.Class:
    public class User{
        // Field
        int no;
        
        // Constructor
        public User(){
    	}
    
        public User(int no){
            this.no = no;
        }
        
        // Method
        public void setNo(int no){
            this.no = no;
    	}
    
        public int getNo(){
            return no;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    反射Filed【反射/反编译一个类的属性】

    Class类方法

    方法名备注
    public T newInstance()创建对象
    public String getName()返回完整类名带包名
    public String getSimpleName()返回类名
    public Field[] getFields()返回类中public修饰的属性
    public Field[] getDeclaredFields()返回类中所有的属性
    public Field getDeclaredField(String name)根据属性名name获取指定的属性
    public native int getModifiers()获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
    public Method[] getDeclaredMethods()返回类中所有的实例方法
    public Method getDeclaredMethod(String name, Class… parameterTypes)根据方法名name和方法形参获取指定方法
    public Constructor[] getDeclaredConstructors()返回类中所有的构造方法
    public Constructor getDeclaredConstructor(Class… parameterTypes)根据方法形参获取指定的构造方法
    获取一个类的父类以及所有实现的接口
    public native Class getSuperclass()返回调用类的父类
    public Class[] getInterfaces()返回调用类实现的接口集合

    Field类方法

    方法名备注
    public String getName()返回属性名
    public int getModifiers()获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
    public Class getType()以Class类型,返回属性类型【一般配合Class类的getSimpleName()方法使用】
    public void set(Object obj, Object value)设置属性值
    public Object get(Object obj)读取属性值
    反编译一个类的属性Field(本类的所有属性,不包含父类和接口), 代码示例
    //通过反射机制,反编译一个类的属性Field(了解一下)
    class ReflectTest06{
        public static void main(String[] args) throws ClassNotFoundException {
    		Class studentClass = Class.forName("javase.reflectBean.Student");
    		Modifier.toString(studentClass.getModifiers();
    		// Class类的getName方法
    		studentClass.getSimpleName()
        
            //获取所有的属性
    		Field[] declaredFields = clazz1.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                //属性名称
                String fieldName = declaredFields[i].getName();
                //属性的类型 
                // declaredFields[i]..getType().getSimpleName()
                String fieldType = declaredFields[i].getType().getName();
                //获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号
                //用Modifier类的toString转换成字符串
                String fieldModifier = Modifier.toString(declaredFields[i].getModifiers());
                System.out.println(fieldModifier + " " + fieldType + " " + fieldName + ";");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    取得实现的接口里的所有属性,代码示例
    //通过属性名取得属性
    Field field = clazz1.getDeclaredField("name");
    //访问私有属性需要设置Accessible为true才可以更改或读取值(get 或 set)
    field.setAccessible(true);
    //取得instance对象里面的属性值
    System.out.println("更改前的name值:" + field.get(instance));
    //更改instance对象里的name属性值
    field.set(instance,"文攀啊");
    System.out.println("更改后的name属性值:" + field.get(instance));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    给属性赋值三要素

    示例:给s对象的no属性赋值1111

    要素1:对象 s

    要素2:no 属性

    要素3:1111 值

    读属性值两个要素

    示例:获取s对象的no属性的值

    要素1:对象 s

    要素2:no属性

    注: Field类中set()、get()使用注意事项:

    1. 属性.set(对象, 值);

    2. 属性.get(对象);

    通过反射机制访问一个java对象的属性,代码示例
    /*
    必须掌握:
    怎么通过反射机制访问一个java对象的属性?
    给属性赋值set
    获取属性的值get
     */
    class ReflectTest07{
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
            // 不使用反射机制给属性赋值
            Student student = new Student();
            // 给属性赋值三要素:给s对象的no属性赋值1111
            student.no = 1111;
            // 读属性值两个要素:获取s对象的no属性的值
            System.out.println(student.no);
    
            // 使用反射机制给属性赋值
            Class studentClass = Class.forName("javase.reflectBean.Student");
    
    		// obj就是Student对象。(底层调用无参数构造方法)
            Object obj = studentClass.newInstance();
    
            // 获取no属性(根据属性的名称来获取Field)
            Field noField = studentClass.getDeclaredField("no");
    
            // 给obj对象(Student对象)的no属性赋值
            noField.set(obj, 22222);
    
            // 读取属性的值
            // 两个要素:获取obj对象的no属性的值。
            System.out.println(noField.get(obj));
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    set()可以访问私有属性嘛?

    不可以,需要打破封装,才可以

    Field方法

    方法备注
    public void setAccessible(boolean flag)默认false,设置为true为打破封装
    代码示例
    // 可以访问私有的属性吗?
    Field nameField = studentClass.getDeclaredField("name");
    // 打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会!!!)
    // 这样设置完之后,在外部也是可以访问private的。
    nameField.setAccessible(true);
    // 给name属性赋值
    nameField.set(obj, "xiaowu");
    // 获取name属性的值
    System.out.println(nameField.get(obj));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    反射Method【反射/反编译一个类的方法】

    Method类方法

    方法名备注
    public String getName()返回方法名
    public int getModifiers()获取方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
    public Class getReturnType()以Class类型,返回方法类型【一般配合Class类的getSimpleName()方法使用】
    public Class[] getParameterTypes()返回方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】
    public Object invoke(Object obj, Object… args)调用方法

    反编译一个类的方法Method

    class ReflectTest09{
        public static void main(String[] args) throws ClassNotFoundException {
            Class userServiceClass = Class.forName("java.lang.String");
    
    StringBuilder s = new StringBuilder();
            s.append(Modifier.toString(userServiceClass.getModifiers()));
            s.append(" class ");
            s.append(userServiceClass.getSimpleName());
            s.append(" {\n");
    
            // 获取所有的Method(包括私有的!)
            Method[] methods = userServiceClass.getDeclaredMethods();
            for (Method m : methods){
                s.append("\t");
                // 获取修饰符列表
                s.append(Modifier.toString(m.getModifiers()));
                s.append(" ");
                // 获取方法的返回值类型
                s.append(m.getReturnType().getSimpleName());
                s.append(" ");
                // 获取方法名
                s.append(m.getName());
                s.append("(");
                // 方法的修饰符列表(一个方法的参数可能会有多个。)
                Class[] parameterTypes = m.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++){
                    s.append(parameterTypes[i].getSimpleName());
                    if (i != parameterTypes.length - 1) s.append(", ");
                }
                s.append(") {}\n");
            }
            s.append("}");
            System.out.println(s);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    调用方法四要素

    示例:调用对象userService的login方法

    1. 对象 userService

    2. login 方法名

    3. 实参列表

    4. 返回值

    注: Method类中invoke()使用注意事项:

    方法.invoke(对象, 实参);

    取得一个类的所有方法(包括父类和实现的接口)

    Method[] methods = clazz1.getMethods();

    代码示例
    Method[] methods = clazz1.getMethods();
    //输出取得的方法
    for (int i = 0; i < methods.length; i++) {
        StringBuffer buffer = new StringBuffer();
        //方法修饰符
        String modifier = Modifier.toString(methods[i].getModifiers());
        //返回值类型
        String returnType = methods[i].getReturnType().getSimpleName();
        //方法名
        String name = methods[i].getName();
        //方法参数类型
        Class<?>[] parameterTypes = methods[i].getParameterTypes();
        buffer.append(modifier).append(" ").append(returnType).append(" ").
            append(name).append("(");
        for (int j = 0; j < parameterTypes.length; j++) {
            buffer.append(parameterTypes[j].getSimpleName()).append(" arg").append(j);
            if(j < parameterTypes.length - 1){
                buffer.append(",");
            }
        }
        buffer.append(")");
        //方法抛出的异常信息
        Class<?>[] exceptionTypes = methods[i].getExceptionTypes();
        if(exceptionTypes.length > 0){
            buffer.append(" throws");
        }
        for (int k = 0; k < exceptionTypes.length; k++) {
            buffer.append(exceptionTypes[k].getSimpleName());
            if(k < exceptionTypes.length -1){
                buffer.append(",");
            }
        }
        buffer.append("{ }");
        System.out.println(buffer);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    取得一个类的所有方法(不包括父类和实现的接口)

    Method[] declaredMethods = clazz1.getDeclaredMethods();

    通过反射机制调用一个对象的方法

    代码示例
    public static void main(String[] args) throws Exception {
        //使用反射将Child类的Class对象加载进来
        Class<?> clazz1 = Class.forName("com.wp.reflect.entity.Child");
        //创建一个实例对象(使用反射调用方法必须要有实例对象)
        Object instance = clazz1.newInstance();
        //通过方法名称和指定的参数类型获取指定方法
        Method method = clazz1.getDeclaredMethod("setName", String.class);
        //调用Method对象的invoke方法执行instance对象的方法
        method.invoke(instance,"文攀啊");
        //通过方法名称和指定的参数类型获取指定方法
        Method getNameMethod = clazz1.getMethod("getName");
        //调用Method对象的invoke方法执行方法
        String name = (String)getNameMethod.invoke(instance);
        //输出执行方法返回的结果
        System.out.println(name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    代码示例
    /*
    重点:必须掌握,通过反射机制怎么调用一个对象的方法?
     */
    class ReflectTest10{
        public static void main(String[] args) throws Exception {
            // 不使用反射机制,怎么调用方法
            // 创建对象
            UserService userService = new UserService();
            // 调用方法
            System.out.println(userService.login("admin", "123") ? "登入成功!" : "登入失败!");
    
            //使用反射机制调用方法
            Class userServiceClass = Class.forName("javase.reflectBean.UserService");
            // 创建对象
            Object obj = userServiceClass.newInstance();
            // 获取Method
            Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
    //        Method loginMethod = userServiceClass.getDeclaredMethod("login");//注:没有形参就不传
            // 调用方法
            // 四要素:loginMethod方法, obj对象,"admin","123" 实参,retValue 返回值
            Object resValues = loginMethod.invoke(obj, "admin", "123");//注:方法返回值是void 结果是null
            System.out.println(resValues);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    通过方法名和方法参数类型取得对象的方法

    Method method = clazz1.getDeclaredMethod(“setName”, String.class);

    反射Constructor【反射/反编译一个类的构造方法】

    Constructor类方法

    方法名备注
    public String getName()返回构造方法名
    public int getModifiers()获取构造方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
    public Class[] getParameterTypes()返回构造方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】
    public T newInstance(Object … initargs)创建对象【参数为创建对象的数据】

    取得一个类的所有构造函数

    Class clazz1 = Class.forName(“xxxx”);

    Constructor[] constructors = clazz1.getConstructors();

    Constructor[] constructors1 = clazz1.getDeclaredConstructors();

    根据参数类型取得构造函数

    取得只有一个参数且参数类型为String的构造方法

    Constructor constructor1 = clazz1.getDeclaredConstructor(String.class);

    System.out.println(constructor1);

    反编译一个类的构造方法Constructor

    代码示例
    /*
    反编译一个类的Constructor构造方法。
    */
    class ReflectTest11{
        public static void main(String[] args) throws ClassNotFoundException {
            StringBuilder s = new StringBuilder();
    
            Class vipClass = Class.forName("javase.reflectBean.Vip");
    
            //public class UserService {
            s.append(Modifier.toString(vipClass.getModifiers()));
            s.append(" class ");
            s.append(vipClass.getSimpleName());
            s.append("{\n");
    
            Constructor[] constructors = vipClass.getDeclaredConstructors();
            for (Constructor c : constructors){
                //public Vip(int no, String name, String birth, boolean sex) {
                s.append("\t");
                s.append(Modifier.toString(c.getModifiers()));
                s.append(" ");
    //            s.append(c.getName());//包名+类名
                s.append(vipClass.getSimpleName());//类名
                s.append("(");
                Class[] parameterTypes = c.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++){
                    s.append(parameterTypes[i].getSimpleName());
                    if (i != parameterTypes.length - 1 ) s.append(", ");
                }
                s.append("){}\n");
            }
    
            s.append("}");
            System.out.println(s);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    反射机制创建对象两步骤

    先获取到这个有参数的构造方法【用ClassgetDeclaredConstructor()方法获取】

    调用构造方法new对象【用Constructor类的newInstance()方法new对象】

    通过反射机制调用构造方法实例化java对象

    代码示例
    /*
    通过反射机制调用构造方法实例化java对象。(这个不是重点)
    */
    class ReflectTest12{
        public static void main(String[] args) throws Exception {
            //不适用反射创建对象
            Vip vip1 = new Vip();
            Vip vip2 = new Vip(123, "zhangsan", "2001-10-19", false);
    
            //使用反射机制创建对象(以前)
            Class vipClass = Class.forName("javase.reflectBean.Vip");
            // 调用无参数构造方法
            Object obj1 = vipClass.newInstance();//Class类的newInstance方法
            System.out.println(obj1);
    
            //使用反射机制创建对象(现在)
            // 调用有参数的构造方法怎么办?
            // 第一步:先获取到这个有参数的构造方法
      Constructor c1 = vipClass.getDeclaredConstructor(int.class, String.class, String.class, boolean.class);
            // 第二步:调用构造方法new对象
            Object obj2 = c1.newInstance(321, "lsi", "1999-10-11", true);//Constructor类的newInstance方法
            System.out.println(obj2);
    
            // 获取无参数构造方法
            Constructor c2 = vipClass.getDeclaredConstructor();
            Object obj3 = c2.newInstance();
            System.out.println(obj3);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    注: 如果需要调用无参构造方法,getDeclaredConstructor()方法形参为空即可【和Class类的newInstance()方法一样的效果】

    获取一个类的父类以及实现的接口

    两个方法【Class类中的】

    public native Class getSuperclass()

    public Class[] getInterfaces()

    代码示例
    /**
     *重点:给你一个类,怎么获取这个类的父类,已经实现了哪些接口?
     */
    class ReflectTest13{
        public static void main(String[] args) throws Exception{
            // String举例
            Class vipClass = Class.forName("java.lang.String");
    		// 获取String的父类
    		Class superclass = vipClass.getSuperclass();
    		// 获取String类实现的所有接口(一个类可以实现多个接口。)
    		Class[] interfaces = vipClass.getInterfaces();
    		System.out.println(superclass.getName());
    		for (Class i : interfaces) {
    			System.out.println(i.getName());
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    反射操作注解

    通过反射获取类上的注解,类属性上的注解,代码示例
    public static void main(String[] args) throws Exception{
    	User user = new User();
        // 取得类上的所有注解
        Annotation[] annotations = user.getClass().getAnnotations();
        // 获取类上指定类型的注解
        MyAnnotation annotation = user.getClass().getAnnotation(MyAnnotation.class);
        // 获取类的某个属性上的所有注解
        Annotation[] allAnnotations = user.getClass().getDeclaredField("name").getAnnotations();
        // 获取类的某个属性上指定类型的注解
        MyAnnotation annotation1 = user.getClass().getDeclaredField("name").getAnnotation(MyAnnotation.class);
        // 获取注解的属性
        String value = annotation1.value();
        String pattern = annotation1.pattern();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    反射实例应用

    使用反射向一个int集合添加一个String元素

    原理:首先通过反射取得该List集合的add()方法,然后使用反射调用该方法向list集合里面添加一个String类型元素

    代码示例
    //创建一个int类型的集合
    ArrayList<Integer> list = new ArrayList<Integer>();
    
    //取得集合的添加方法
    Method addMethod = list.getClass().getMethod("add", Object.class);
    
    //执行集合的add方法,向集合中添加一个String类型元素
    addMethod.invoke(list, "wenpan");
    System.out.println("取得元素=========================>" + list.get(0));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    通过反射修改数组元素的值

    原理:其实就是通过反射中的 Array.get() 和 Array.set()来读取和修改数组中的元素值。

    代码示例
    int temp[] = {1,2,3,4,5};
    System.out.println("数组第一个元素:" + Array.get(temp,0));
    Array.set(temp,0,100);
    System.out.println("修改之后数组第一个元素为:" + Array.get(temp,0));
    
    • 1
    • 2
    • 3
    • 4
    扩展方法
    int temp[] = {1,2,3,4,5};
    //取得数组的类型,该方法为动态扩展数组大小做铺垫
    Class<?> componentType = temp.getClass().getComponentType();
    System.out.println("数组类型:" + componentType.getName());
    System.out.println("数组长度:" + Array.getLength(temp));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    通过反射修改数组的大小

    原理:其本质就是通过反射得到原数组的类型,然后通过Array.newInstance()方法根据数组类型创造出一个指定长度的新数组,最后使用System.arraycopy()方法将原数组的值拷贝到新数组中

    public static Object arrayInc(Object obj, int length) {
      //取得传入数组的类型,以便于创造出同类型的数组
      Class<?> componentType = obj.getClass().getComponentType();
      //根据传入的数组类型创建出新的指定长度的数组实例
      Object newArr = Array.newInstance(componentType, length);
      //原有的数组长度
      int originArrLen = Array.getLength(obj);
      //将原有的数组数据拷贝到新的数组中去
      System.arraycopy(obj,0,newArr,0,originArrLen);
      //返回修改大小后的数组
      return newArr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    通过反射实现通用工厂模式
    class Factory {
    	/**
    	* 通过传入的全类名返回该类的对象
    	*  但是有一点仍然很麻烦,就是需要知道完整的包名和类名,这里可以使用properties配置文件来完成。
    	*  java读取配置文件可实现完全解耦
    	* @param className
    	* @return
    	*/
    	public static Object getInstance(String className){
            Object instance = null;
            try {
                //通过反射创建对象实例
                instance = Class.forName(className).newInstance();
            }catch (Exception e) {
                e.printStackTrace();
            }
    		return instance;
    	}
    }
    
    public static void main(String[] args) {
        //反射工厂
        Apple apple = (Apple)Factory.getInstance("com.wp.reflect.Apple");
        apple.method();
        Banana banana = (Banana)Factory.getInstance("com.wp.reflect.Banana");
        banana.method();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    总结注意

    属性最重要的是名字

    实例方法最重要的是名字和形参列表

    构造方法最重要的是形参列表

    参考文献

    综合了好几篇反射相关的博客整理的一份全集,找不到那些博客地址了,仅供学习笔记使用。

  • 相关阅读:
    在ubuntu上搭建nexus私有仓库[失败草稿]
    【DL】Windiws10系统下安装CUDA和CUDNN实践教程
    记一次 .NET 某传感器采集系统 线程爆高分析
    OSMNX 路网数据下载分析Python包
    LPWA物联网通信
    【JavaSE】Arrays工具类
    计算机毕业设计(附源码)python野生动物保护资讯管理系统
    tkinter: 变量类别
    多线程和并发编程(6)—并发编程的设计模式
    PHP redis hash
  • 原文地址:https://blog.csdn.net/qq_28772075/article/details/130825897