Java反射

2021-02-03 13:17

阅读:372

标签:class类   安全   idt   字符   利用反射   value   配置文件   field   由来   

一、什么是反射?

二、反射与正射

三、使用

 


 

一、什么是反射?

1.概念:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法。所以先要获取到每一个字节码文件对应的Class类型的对象.。反射就是把Java类中的各种成分映射成一个个的Java对象。

例如:
一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。(其实:一个类中这些成员方法、构造方法,在加入类中都有一个类来描述)
如图是类的正常加载过程:反射的原理在于class对象。

熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

类的正常加载过程:

技术图片

 

2.好处:

  • 可以在程序运行过程中,操作这些对象。
  •  可以解耦,提高程序的可扩展性。

二、反射与正射

反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释。

一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。
如:

1 Phone phone = new Phone(); //直接初始化,「正射」
2 phone.setPrice(4);

上面这样子进行类对象的初始化,我们可以理解为「正」。

而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。

这时候,我们使用 JDK 提供的反射 API 进行反射调用:

1 Class clz = Class.forName("com.xxp.reflect.Phone");
2 Method method = clz.getMethod("setPrice", int.class);
3 Constructor constructor = clz.getConstructor();
4 Object object = constructor.newInstance();
5 method.invoke(object, 4);
上面两段代码的执行结果,其实是完全一样的。但是其思路完全不一样,第一段代码在未运行时就已经确定了要运行的类(Phone),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.xxp.reflect.Phone)。

所以说什么是反射?反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

一个简单的例子:
上面提到的示例程序,其完整的程序代码如下:

 1 public class Phone {
 2     private int price;
 3     public int getPrice() {
 4         return price;
 5     }
 6     public void setPrice(int price) {
 7         this.price = price;
 8     }
 9 
10     public static void main(String[] args) throws Exception{
11         //正常的调用
12         Phone phone = new Phone();
13         phone.setPrice(5000);
14         System.out.println("Phone Price:" + phone.getPrice());
15         //使用反射调用
16         Class clz = Class.forName("com.xxp.api.Phone");
17         Method setPriceMethod = clz.getMethod("setPrice", int.class);
18         Constructor phoneConstructor = clz.getConstructor();
19         Object phoneObj = phoneConstructor.newInstance();
20         setPriceMethod.invoke(phoneObj, 6000);
21         Method getPriceMethod = clz.getMethod("getPrice");
22         System.out.println("Phone Price:" + getPriceMethod.invoke(phoneObj));
23     }
24 }

从代码中可以看到我们使用反射调用了 setPrice 方法,并传递了 6000 的值。之后使用反射调用了 getPrice 方法,输出其价格。上面的代码整个的输出结果是:

1 Phone Price:5000
2 Phone Price:6000

从这个简单的例子可以看出,一般情况下我们使用反射获取一个对象的步骤:

 
1 //获取类的 Class 对象实例
2 Class clz = Class.forName("com.xxp.api.Phone");
3 //根据 Class 对象实例获取 Constructor 对象
4 Constructor phoneConstructor = clz.getConstructor();
5 //使用 Constructor 对象的 newInstance 方法获取反射类对象
6 Object phoneObj = phoneConstructor.newInstance();

而如果要调用某一个方法,则需要经过下面的步骤:

 
1 //获取方法的 Method 对象
2 Method setPriceMethod = clz.getMethod("setPrice", int.class);
3 //利用 invoke 方法调用方法
4 setPriceMethod.invoke(phoneObj, 6000);

到这里,我们已经能够掌握反射的基本使用。但如果要进一步掌握反射,还需要对反射的常用 API 有更深入的理解。

 三、使用

 1 * 获取Class对象的方式:
 2     1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
 3         * 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
 4     2. 类名.class:通过类名的属性class获取
 5         * 多用于参数的传递
 6     3. 对象.getClass():getClass()方法在Object类中定义着。
 7         * 多用于对象的获取字节码的方式
 8 
 9     * 结论:
10         同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
 1 * Class对象功能:
 2 * 获取功能
 3 1. 获取成员变量们
 4 2. 获取构造方法们
 5 3. 获取成员方法们
 6 4. 获取全类名
 7 
 8     * 获取功能:
 9         1. 获取成员变量们
10             * Field[] getFields() :获取所有public修饰的成员变量
11             * Field getField(String name)   获取指定名称的 public修饰的成员变量
12 
13             * Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
14             * Field getDeclaredField(String name)  
15         2. 获取构造方法们
16             * Constructor>[] getConstructors()  
17             * Constructor getConstructor(类>... parameterTypes)  
18 
19             * Constructor getDeclaredConstructor(类>... parameterTypes)  
20             * Constructor>[] getDeclaredConstructors()  
21         3. 获取成员方法们:
22             * Method[] getMethods()  
23             * Method getMethod(String name, 类>... parameterTypes)  
24 
25             * Method[] getDeclaredMethods()  
26             * Method getDeclaredMethod(String name, 类>... parameterTypes)  
27         4. 获取全类名    
28             * String getName()  
* Field:成员变量
    * 操作:
        1. 设置值
            * void set(Object obj, Object value)  
        2. 获取值
            * get(Object obj) 

        3. 忽略访问权限修饰符的安全检查
            * setAccessible(true):暴力反射
* Constructor:构造方法
    * 创建对象:
        * T newInstance(Object... initargs)  

        * 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
* Method:方法对象
    * 执行方法:
        * Object invoke(Object obj, Object... args)  

    * 获取方法名称:
        * String getName:获取方法名

 

Java反射

标签:class类   安全   idt   字符   利用反射   value   配置文件   field   由来   

原文地址:https://www.cnblogs.com/aaaazzzz/p/12801160.html


评论


亲,登录后才可以留言!