一篇文章带你搞定JAVA反射
目录
- 1、反射的概念
- 1、概念
- 2、获取字节码文件对象的方式
- 2.1 元数据的概念
- 2.2 获取class对象的方式
- 1、访问权限
- 2、获取方法
- 2.1 访问静态方法
- 2.2 访问类方法
- 3、获取字段,读取字段的值
- 4、获取实现的接口
- 5、获取构造函数,创建实例
- 6、获取继承的父类
- 7、获取注解
- 4、反射实例
- 5、总结
1、反射的概念
1、概念
反射,指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意一个方法。这种动态获取信息,以及动态调用对象方法的功能,叫做java语言的反射机制。反射很强大,有优点也有缺点。
优点:灵活性高。因为反射属于动态编译,即只有到运行时才动态创建 &获取对象实例。
缺点:执行效率低。
2、获取字节码文件对象的方式
2.1 元数据的概念
元数据(metadata):元数据是指用来描述类的数据,就是class的代码数据。所有的class文件加载到虚拟机之后都会被构建成class对象,class对象描述了一个类都有哪些东西,大家都知道的实现的接口,继承的抽象类,成员变量,类变量,成员方法,类方法,静态方法等,这个class对象就是元数据。
- Class类:代表一个类。
- Field类:代表类的成员变量(成员变量也称为类的属性)。
- Method类:代表类的方法。
- Constructor类:代表类的构造方法。
文章图片
2.2 获取class对象的方式
- 通过对象获得,因为任何对象都必须和class对象关联
- 通过类对象直接获得
- 通过类加载器获得,因为类加载器读取class文件会返回class对象
package org.pdool.reflect; /*** @author 香菜*/public class Npc {// 静态fieldpublic static int NPC_TYPE_1 = 1; // 私有成员变量private int npcType; // 共有成员变量public String name; // 无参构造函数public Npc() {}// 有参构造函数public Npc(int npcType, String name) {this.npcType = npcType; this.name = name; } public int getNpcType() {return npcType; } public void setNpcType(int npcType) {this.npcType = npcType; } public String getName() {return name; } public void setName(String name) {this.name = name; }// 静态方法public static void sayHello(String word){System.out.println("hello " + word); }}
获取反射class的三种方式
package org.pdool.reflect; /*** @author 香菜*/public class ClazzTest {public static void main(String[] args) {//第一种方式获取Class对象Npc npc1 = new Npc(); //这一new 产生一个Npc对象,一个Class对象。Class npcClazz1 = npc1.getClass(); //获取Class对象System.out.println(npcClazz1.getName()); //第二种方式获取Class对象Class npcClazz2 = Npc.class; System.out.println(npcClazz1 == npcClazz2); //判断第一种方式获取的Class对象和第二种方式获取的是否是同一个 //第三种方式获取Class对象try {Class npcClazz3 = Class.forName("org.pdool.reflect.Npc"); //注意此字符串必须是真实路径,就是带包名的类路径,包名.类名System.out.println(npcClazz3 == npcClazz2); //判断三种方式是否获取的是同一个Class对象} catch (ClassNotFoundException e) {e.printStackTrace(); } }}
1、访问权限
反射机制的默认行为受限于Java的访问控制,可通过 setAccessible 绕过控制。
// 设置对象数组可访问标志static void setAccessible(AccessibleObject[] array, boolean flag)
2、获取方法
文章图片
2.1 访问静态方法
public static void main(String[] args) throws NoSuchMethodException,InvocationTargetException, IllegalAccessException {Npc npc = new Npc(1, "妖神·凰女"); Class npcClazz = Npc.class; // 第一个参数是方法名,第二个参数是函数的参数class对象,因为存在重载的可能性,用参数类型区分Method sayHello = npcClazz.getMethod("sayHello", String.class); sayHello.invoke(npc, "world"); }
2.2 访问类方法
Npc npc = new Npc(1, "妖神·凰女"); System.out.println(npc.getName()); Class npcClazz = Npc.class; // 第一个参数是方法名,第二个参数是函数的参数class对象,因为存在重载的可能性,用参数类型区分Method sayHello = npcClazz.getMethod("setName", String.class); sayHello.invoke(npc, "world"); System.out.println(npc.getName());
3、获取字段,读取字段的值
文章图片
Npc npc = new Npc(1, "妖神·凰女"); Class npcClazz = Npc.class; // 获取字段,并设置可访问Field field = npcClazz.getField("name"); field.setAccessible(true); System.out.println( field.get(npc));
4、获取实现的接口
文章图片
5、获取构造函数,创建实例
文章图片
Class npcClazz = Npc.class; Constructor declaredConstructor = npcClazz.getDeclaredConstructor(int.class,String.class); Npc npc = (Npc) declaredConstructor.newInstance(1, "妖神"); System.out.println(npc.getName());
6、获取继承的父类
Class npcClazz = Npc.class; Class superclass = npcClazz.getSuperclass(); System.out.println(superclass.getName());
7、获取注解
Class npcClazz = Npc.class; Annotation[] annotations = npcClazz.getAnnotations(); // 运行时注解for (Annotation annotation : annotations) {System.out.println(annotation.getClass().getName()); }
4、反射实例 获取到元数据不是最终的目的,我们最终的目的是想在运行时去调用,访问类。说了太多,还是举个例子,大家都知道Spring的IOC,怎么实现的呐?
过程:
1、Spring 在项目启动的时间通过读取xml中配置的bean的路径,
2、然后通过Class.forName 读取class 到类加载器,
3、然后通过反射创建所有的bean实例并保存到容器中,启动容器之后,
4、在项目中可以直接获取bean对象。
我们来大概实现这一过程,因为xml的读取比较麻烦,直接用property来代替了。大家体会一下思想就可以了。
package org.pdool.reflect; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.Set; /*** @author 香菜*/public class ClazzTest {public static void main(String[] args){try {Map container = new HashMap<>(); //1.读取配置InputStream in = ClazzTest.class.getResourceAsStream("/beans.properties"); Properties property = new Properties(); property.load(in); //2.反射创建对象Set
5、总结 在使用Java反射机制时,主要步骤包括:
【一篇文章带你搞定JAVA反射】获取 目标类型的Class对象
通过 Class 对象分别获取Constructor类对象、Method类对象 或者 Field 类对象
通过 Constructor类对象、Method类对象 & Field类对象分别获取类的构造函数、方法&属性的具体信息,并进行后续操作。
本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- 宽容谁
- 一个人的旅行,三亚
- 第6.2章(设置属性)
- 布丽吉特,人生绝对的赢家
- 家乡的那条小河
- 讲述,美丽聪明的海欧!
- PMSJ寻平面设计师之现代(Hyundai)
- 夜游宫|夜游宫 心语
- 增长黑客的海盗法则
- 画画吗()