一、概述
什么是反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象
总之,反射就是把java类中的各种成分映射成一个个的Java对象。例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象
反射机制是Java特性之一,反射机制是构建框架技术的基础所在。
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高。
二、Java反射的核心类库
核心类
Java反射机制主要涉及以下四个核心类库:
Class类:反射的核心类,反射所有的操作都是围绕该类来生成的,通过它,可以获取类的属性,方法等内容。
Field类:表示类的属性,可以获取和设置类中属性的值。
Method类:表示类的方法,它可以用来获取类中方法的信息,或者执行方法。
Constructor类:表示类的构造方法。
关于Class类
(1)Class 是一个特殊的类,但它和一般类一样继承自Object。
(2)Class是Reflection故事起源,针对任何你想使用反射技术的类,必须先为它产生一个Class 对象。
(3)Class包含的信息有某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
(4)Class 对象只能由系统建立对象。
(5)一个类在 JVM 中只会有一个Class实例。
(6)每个类的实例都会记得自己是由哪个 Class 实例所生成。
三、Class对象功能
1,获取成员变量们
Field[] getFields() :获取所有public修饰的成员变量
Field getField(String name) 获取指定名称的 public修饰的成员变量
Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name)
2,获取构造方法们
Constructor<?>[] getConstructors()
Constructor<T> getConstructor(类<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()
3,获取成员方法们:
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口的公共 member 方法。
Method[] getMethods()
Method getMethod(String name, 类<?>... parameterTypes)
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
也就是说getDeclaredMethods能拿到所有(不包括继承的方法),而getMethods只能拿到public方法(包括继承的类或接口的方法)
4,获取全类名
String getName()
String getSimpleName():类名
四、Java反射的基本使用
1,获取Class对象
要使用反射,首先需要获取目标类的Class对象。有以下几种方式:
(1)通过类的class属性获取:
Class clazz = String.class;
(2)通过对象的getClass()方法获取:
String str = "hello";
Class clazz = str.getClass();
(3)通过Class.forName()方法获取:
Class clazz = Class.forName("java.lang.String");
2,创建对象
通过Class对象的newInstance()方法可以创建一个实例,但前提是该类有默认的无参构造方法:
Object obj = clazz.newInstance();
如果目标类没有无参构造方法,可以通过Constructor类来创建对象:
Constructor constructor = clazz.getConstructor(String.class);
Object obj = constructor.newInstance("hello");
如果需要调用目标私有的构造方法,则用通过getDeclaredConstructor类来构造对象:
Constructor constructor2 = cls.getDeclaredConstructor(String.class, int.class);
//得到私有的构造方法
//暴力反射,解除封装
constructor2.setAccessible(true);
Student student3 = (Student) constructor2.newInstance("12", 12);
3,获取属性
要获取一个类的公共属性,可以使用Class
类的getFields()
方法。这个方法返回一个包含类的所有公共属性的Field
对象数组:
Field[] fields = cls.getFields();//获取公共的属性的数组
for (Field field : fields) {
System.out.println(field.getName());
}
要获取一个类的私有属性,需要使用Class
类的getDeclaredFields()
方法。这个方法返回一个包含类的所有属性(包括私有属性)的Field
对象数组:
Field[] fields1 = cls.getDeclaredFields();//获取私有的属性数组
for (Field field : fields1) {
System.out.println(field.getName());
}
根据属性名获取单个属性并设置值:
Field cex = cls.getField("cex");//获取公开的单个属性
cex.set(student1, "12");//设置值,对象+值
Field name = cls.getDeclaredField("name");//获取私有的单个属性
//解除封装
name.setAccessible(true);
name.set(student1, "小明");//设置值,对象+值
4,调用方法
通过Method类可以调用目标对象的方法,包括私有方法。
公开方法:
Method method = cls.getMethod("eat");//得到指定的公开的成员方法
method.invoke(student1);//调用方法,方法名.invoke(对象)
私有方法:
Method method2 = cls.getDeclaredMethod("Study");//得到指定的私有的成员方法
method2.setAccessible(true);
method2.invoke(student1);//调用方法,方法名.invoke(对象)
如果方法有参数,需要在getMethod()方法中传入参数类型:
Method method1 = cls.getMethod("sheep", String.class);//String.class为字解码
method1.invoke(student1, "李华");//调用方法,对象+值
五、Java反射的应用场景
ORM框架:如Hibernate、MyBatis等,通过反射实现数据库表与Java对象的映射。
JSON解析:如Fastjson、Gson等,通过反射将JSON字符串转换为Java对象。
动态代理:如Spring AOP,通过反射创建代理对象,实现方法拦截和增强。
单元测试:如JUnit,通过反射调用测试方法。
总结
Java反射机制是一种在运行时动态获取类信息、创建对象、调用方法、访问字段的能力,它提供了程序的灵活性和扩展性,但同时也可能带来性能下降和安全隐患。正确使用反射可以简化代码、实现框架设计,但需注意避免滥用。