反射
什么是反射(Reflection)
反射是Java语言的一种特别重要的特性,允许程序在运行时动态地获取类的所有信息、构造对象、调用方法和属性等,而不需要在编译时就确定这些信息。
Java反射允许程序在运行时操作类的成员,而不是在编译时固定下来。
通过Java反射,我们可以获取类的构造函数、方法、属性等各种信息,并且可以利用这些信息来创建类的实例、调用类的方法和访问类的属性。
使得Java程序具有更高的灵活性和可扩展性,因为程序可以在运行时动态地加载和使用类,而不需要在编译时就确定这些信息。
反射有什么用呢?
-
获得不可访问的类和成员的操作权限
通过反射, 可以获得类的一切信息,包括私有的。
这让程序在运行时能够使用更多信息。 -
运行时创建对象
通过反射,可以在运行时根据类名创建对象。
比通过new创建对象更加的灵活,因为我们不需要知道具体的类是什么,而是直接使用它的某些方法。 -
插件设计
可以根据配置文件从而来加载不同的类,实现插件化设计。
反射的主要作用是:
- 提高程序的扩展性和动态性
- 允许在运行期访问名称已知但结构未知的类
- 动态创建对象和调用方法,而非硬编码
- 实现基于配置的插件系统
反射对象的获取
Java中任何类型都是一个对象,除了基本数据类型int, char 等外,都是对象类型的,叫做小class
, 它们都是由小class
修饰的。
包括Java里面有一个特殊的类,名字叫做大Class
,
public final class Class<T>
该大Class
对象,去看它的构造函数,发现它是私有的,因为它是JVM去调用的,我们不用管。
每一个小class
对象,在加载时都会创建一个与之对应的大Class
对象,这就是所谓的反射。
每一个类仅仅有一个大Class
与之对应:
Class<String> stringClass1 = String.class;
Class<String> stringClass2 = String.class;
System.out.println(stringClass1 == stringClass2); // true
上面我们获得了String类的大Class
,其实获得大Class
有三种方法。
- 通过类名去获得
public class Main {
public static void main(String[] args) {
// 获得String的Class
Class<String> stringClass = String.class;
// 获得Person的Class
Class<Person> personClass = Person.class;
}
}
class Person{
private String name;
}
- 通过类的实例去获得
//先创建实例,再通过getClass()
方法去获得
Person p = new Person();
Class<? extends Person> aClass = p.getClass();
- 通过完整类名去获得
Class<?> aClass = Class.forName("Java.lang.String");
记住这种方法:必须要知道类从包开始后的全路径
获取了反射对象之后,我们可以使用反射对象里的方法。
反射对象的使用
这个大Class
的方法可是很多的,它可以获得类的一切:
-
字段信息
-
方法信息
-
构造方法
-
一般方法
-
继承关系
-
注解信息
-
泛型信息
-
类加载器
······
等。
比如:
// 获取Class
// 通过name获得具体方法
// 调用方法
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> aClass = Class.forName("java.lang.String");
Method method = aClass.getMethod("substring", int.class, int.class);
String s = "Hello world";
Object str = method.invoke(s, 0,3);
System.out.println(str); // Hel
}
}
之后我会对Class各个方法的使用进行介绍。