Java 反射机制
是什么
Java反射机制就是在Java程序运行时,对于任意一个类,都能知道这个类的所有属性、注解和方法等信息;对于任意一个对象,都能调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能被称为Java语言的反射机制。
有什么用
在第三方应用的开发过程中,经常需要获取某个类的某个属性或方法,但需要获取的东西可能是私有的,这时候利用反射可以获取所需的私有属性或方法(但并不是所有的都适合反射)。
怎么用
先创建一个Apple类:
public class Apple {
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
正射:反射包含了一个“反”字,相应的也有个“正射”,而“正射”就是类似我们平常使用的:
//直接初始化,正射
Apple apple = new Apple();
apple.setPrice(4);
System.out.println("the price is "+ apple.getPrice());
利用Apple类使用new关键字直接创建了一个apple对象,这是“正射”做的事。
反射:看看反射是怎么做的:
//查找这个类,利用其构造一个Class对象
Class clz = Class.forName("com.example.demo.Apple");
//利用Class对象获取这个类的一个构造器
Constructor appleConstructor = clz.getConstructor();
//利用构造器创建一个对象的实例
Object object = constructor.newInstance();
//利用Class对象的getMethod方法获取类的setPrice方法,该方法有一个int类型的参数
Method setMethod = clz.getMethod("setPrice",int.class);
//调用这个Method对象的invoke方法,将object对象传递给invoke方法,同时传递调用这个Method方法的参数
//此处执行了Apple对象的setMethod方法
method.invoke(object, 13);
//获取对象的getMethod方法
Method getMethod = clz.getMethod("getPrice");
//执行对象的getMethod方法
System.out.println("the price is "+ getMethod.invoke(object));
反射的流程:获取反射的Class对象、通过反射创建类对象、通过反射获取类属性方法及构造器
反射常用API
获取反射中的Class对象
要获取一个类或调用一个类的方法,我们首先需要获取到该类的Class对象,有三种方法:
- 使用
Class.forName()
静态方法:需要知道该类的全路径名Class clz = Class.forName("com.example.demo.Apple");
- 使用
类名.class
方法:只适合在编译前就知道操作的Class
Class clz = Apple.class;
- 使用类对象的getClass()方法。
Apple apple = new Apple(); Class clz = apple.getClass()
通过反射创建类对象
主要有两种方式:
- 通过
Class对象的newInstance()
方法Class clz = Apple.class; Apple apple = (Apple)clz.newInstance();
- 通过
Constructor对象的newInstance()
方法Class clz = Apple.class; Constructor constructor = clz.getConstructor(); Apple apple = (Apple)constructor.newInstance();
通过第一种方法只能使用默认的无参数构造方法,而通过Constructor对象创建类对象可以选择特定构造方法。
通过反射获取类属性、方法、构造器
通过Class对象的getFields()方法 可以获取Class类的属性,但无法获取私有属性,但如果使用Class对象的getDeclaredFields()方法就能获取包括私有属性在内的所有属性:
Class clz = Apple.class();
Field[] fields = clz.getDeclaredFields();
for(Field field : fields){
System.out.println(field.getName());
}
但是如果要获取私有属性的值,需要使用field.setAccessible(true)
来用以获取私有属性的值。
与获取类属性一样,当我们去获取类方法、类构造器时,如果要获取私有方法或私有构造器,则必须使用有declared关键字的方法。
反射提供了一种使用私有构造方法去创建类对象的途径。
反射机制的相关类
与Java反射相关的类:
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java程序中表示类和接口 |
Field类 | 代表类的属性(属性也称为成员变量) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
Class类:
Class代表类的实体,在运行的Java应用程序中表示类和接口,在这个类中提供了很多有用的方法。
Field类:
Field代表类的成员变量。
Method类
Method代表类的方法。
- invoke方法:
invoke(Object object, Object... args)
- 用途:传递object对象及参数调用该对象对应的方法
Constructor类
代表类的构造方法。
- newInstance(Object… initargs):根据传递的参数创建类的对象
反射的优缺点
- 优点:
- 能够运行时动态获取类的实例,大大提高了系统的灵活性和拓展性;
- 与java动态编译相结合,可以实现无比强大的功能。
- 缺点:
- 使用反射的性能较低
- 使用反射相对来说不安全
- 破坏了类的封装性,可以通过反射来获取这个类的属性和私有方法。