一、反射的基本概念
1、定义
- Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类所有的属性和方法。
- 对于任意一个对象,都能够调用它的任意一个方法和属性。
- 这种动态获取信息和动态调用对象的功能被称作Java语言的反射机制。
- 要想通过反射解剖一个类就必须先获得该类的字节码对象。
- 解剖使用的就是Class类中的方法,所以要先获取每一个字节码文件对应的Class类型对象。
- 通俗的讲,一个类的字节码文件对象就是这个类的骨架。
2、获取字节码对象的三种方式。
- 对象.getClass();
- 类名.Class;
- Class类中的静态方法forName("类的全限定名");
代码示例
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.qianfeng.Student");
Student object = (Student)clazz.newInstance();
object.method();
}
二、反射获取构造函数
1、定义
- Class类中的newInstance()方法是使用该类的无参构造方法创建对象。
- 如果一个类没有无参构造函数,那么就不呢个按照上述方法创建对象了,可以调用Class类中的getConstructor(String .class,int .class.....)方法获取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象。
- 代码示例如下:
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.qianfeng.Student");
Student object = (Student)clazz.newInstance();
object.method();
}
2、榨汁机案例及分析
- 分别有水果(Fruit)苹果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)
- 根据客户的需求, 随时更换果汁
interface Fruit {
public void squeeze();
}
class Apple implements Fruit {
public void squeeze() {
System.out.println("榨出一杯苹果汁儿");
}
}
class Orange implements Fruit {
public void squeeze() {
System.out.println("榨出一杯桔子汁儿");
}
}
class Juicer {
public void run(Fruit f) {
f.squeeze();
}
}
public static void main(String[] args) throws Exception {
//从本地读取配置文件
BufferedReader br = new BufferedReader(new FileReader("config.txt"));
//创建输入流对象,关联配置文件
Class<?> clazz = Class.forName(br.readLine()); //读取配置文件一行内容,获取该类的字节码对象
Fruit f = (Fruit) clazz.newInstance(); //通过字节码对象创建实例对象
Juicer j = new Juicer();
j.run(f);
}
三、反射获取成员变量
1、定义
- Class.getField(String str);方法可以获取类中指定的字段(可见的)。
- 如果是私有的可以用Class.getDeclaedFiled(String )获取。
- 然后通过调用setAccessible(true)设置访问权限放开。
- 再通过get(Obj)和set(obj)可以获取和设定指定字段上该字段的值,Obj指的是这个类的对象。
2、代码示例
public static void main(String[] args) throws Exception {
Student student = new Student();
Class<?> clazz = Class.forName("com.qianfeng.Student");
//获取共有的属性
Field field = clazz.getField("name");
//获取所有的属性
Field field2 = clazz.getDeclaredField("name");
//取消语言检查
field2.setAccessible(true);
//给一个对象的属性设置值
field2.set(student, "333");
//获取这个对象的属性的值
String str= (String) field2.get(student);
System.out.println(str);
}
四、反射获取成员方法
1、定义
- Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法
- 调用invoke(Object, Object...)可以调用对象的这个方法
2、代码示例
需求: 往一个ArrayList<Integer> 的对象中添加String类型的值。
泛型限定只会在编译过程中起作用,一旦程序开始运行泛型限定就失去了作用
package part02;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Reflect02 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ArrayList<Integer> list=new ArrayList<>();
list.add(10);
//通过对象获取.class文件
Class<?> class1 = list.getClass();
//获取“add()”方法。
Method method = class1.getMethod("add", Object.class);
//将add()方法暴力破解
//method.setAccessible(true); 只有私有化的方法/属性才用破解
//运行add();方法添加数据“小红”
method.invoke(list, "小红");
System.out.println(list);
Method[] fields = class1.getDeclaredMethods();
for(Method e:fields){
e.setAccessible(true);
System.out.println(e);
}
}
}