• Java学习:反射


    一、反射概述

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

    从Oracle的官方文档来看,反射主要应用在以下几方面:

    • 反射让开发人员可以通过外部类的全部路径名创建这些类,并使用这些类,实现一些扩展的功能
    • 反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的代码
    • 测试时可以利用反射API访问类的私有成员,以保证测试代码覆盖率

    反射的实现原理是什么呢?

    1. 首先我们要知道class对象是怎么产生的,每个类都有一个Class对象(更恰当的说,是被保存在一个同名的.class文件中)。比如创建一个Student类,Java程序会先进行编译,生成.class文件,编译完成后,会把所有class文件中所包含的类的基本元信息装载到JVM内存中,以class类的形式保存
    2. 当我们使用反射的时候,直接获取到class对象,相当于跳过jvm的编译直接获取到jvm运行时需要的class对象,然后进行反编译,获取对象的各种信息
    3. Java属于先编译再运行的语言,程序中对象的类型在编译器就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,需要哪个就加载哪个

    二、反射API

    反射API用途
    Field类提供有关类的属性信息,以及对它的动态访问权限。它是一个封装反射类的属性的类
    Constructor类提供有关类的构造方法的信息,以及对它的动态访问权限。它是一个封装反射类的构造方法的类
    Method类提供有关类的方法的信息,包括抽象方法。它是用来封装反射类方法的一个类
    Class类表示正在运行的Java应用程序中的类的实例
    Object类Object是所有Java类的父类。所有对象都默认实现了Object类的方法

    三、实例

    package Reflect;
    
    public class User {
        private int id;
        public String name;
    
        public User(int id,String name){
            this.id = id;
            this.name = name;
        }
    
        public int add(int number){
            this.id += number;
            return id;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    1、获取class对象

    package Reflect;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class reflect {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
    
            //获取class对象
            //1、通过完整路径名获取class对象
            Class clazz = Class.forName("Reflect.User");
            //2、通过类的class属性获取
            Class clazz1 = User.class;
            //3、通过对象来获取,这种方式已经获取了对象不需要再使用反射
            User zhangsan = new User(1,"yangguang");
            Class clazz2 = zhangsan.getClass();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2、通过反射来访问成员变量和私有成员变量

    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class reflect {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
    
            //获取class对象
            //1、通过完整路径名获取class对象
            Class clazz = Class.forName("Reflect.User");
            //2、通过类的class属性获取
            Class clazz1 = User.class;
            //3、通过对象来获取,这种方式已经获取了对象不需要再使用反射
            User zhangsan = new User(1,"yangguang");
            Class clazz2 = zhangsan.getClass();
    
            //通过反射来访问成员变量,name是public的
            Field idfield = clazz.getField("name");
            System.out.println(idfield.get(zhangsan));
            //这时候可能有人会说,已经通过zhangsan创建了对象,直接用System.out.println(zhangsan.name);不就可以把成员变量打印出来,为什么要多此一举用反射?
            
            //其实通过反射还可以访问类的私有成员变量,通过getDeclareField方法
            Field field = clazz.getDeclaredField("id");
            field.setAccessible(true);
            System.out.println(field.get(zhangsan));
        }
    }
    
    
    • 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

    3、通过反射来调用方法

    package Reflect;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class reflect {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
    
            //获取class对象
            //1、通过完整路径名获取class对象
            Class clazz = Class.forName("Reflect.User");
            //2、通过类的class属性获取
            Class clazz1 = User.class;
            //3、通过对象来获取,这种方式已经获取了对象不需要再使用反射
            User zhangsan = new User(1,"杨广");
            Class clazz2 = zhangsan.getClass();
           
            //通过反射来调用方法,如果是私有方法用getDeclareMethod
            Method method = clazz.getMethod("add",int.class);
            System.out.println(method.invoke(zhangsan,100));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4、获取构造方法,创建实例

    package Reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class reflect {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException, InstantiationException {
    
            //获取class对象
            //1、通过完整路径名获取class对象
            Class clazz = Class.forName("Reflect.User");
            //2、通过类的class属性获取
            Class clazz1 = User.class;
    
    		//获取构造方法,传入构造方法的两个参数类型,若是私有构造方法,则用getDeclareConstructor
            Constructor constructor = clazz.getConstructor(int.class,String.class);
            //创建实例
            Object zhangsan = constructor.newInstance(1,"杨坚");
    		
    		
            Field field = clazz.getField("name");
            System.out.println(field.get(zhangsan));
        }
    }
    
    
    • 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
  • 相关阅读:
    阿桂天山的技术小结:Flask实现对Ztree树状节点的增改删操作
    【机器学习可解释性】1.模型洞察的价值
    软考高级软件架构师学习笔记二(软件工程)
    派金SDK接入文档
    Postman(2): postman发送带参数的GET请求
    ldap服务安装,客户端安装,ldap用户登录验证测试
    Docker容器搭建Hadoop集群(hadoop-3.1.3)
    Pandas loc与iloc
    借用binlog2sql工具轻松解析MySQL的binlog文件,再现Oracle的闪回功能
    《剑指Offer》栈&队列全题——妙解思路,难度由浅入深
  • 原文地址:https://blog.csdn.net/nzbing/article/details/128062746