文章目录
- 6.Java反射知识总结
- 6.1概述
- 6.1.1什么是反射?
- 6.1.2为什么使用反射?
- 6.2反射的原理
- 6.3反射的使用
- 6.3.1获取类对象
- (1)通过具体类的类名获取
- (2)通过对象实例获取
- (3)通过class.forName(类的全路径)获取
- (4)通过类加载器 xxxClassLoader.loadClass(类的全路径)
- 6.3.2获取类对象的构造函数
- 6.3.3获取类对象的方法
- 6.3.4获取类对象的属性
- 6.4反射的优缺点
6.Java反射知识总结
6.1概述
6.1.1什么是反射?
- Java反射机制指的是在Java程序 运行状态 中,对于任何一个类,都可以获得这个类的 所有属性和方法;
- 对于给定的一个对象,都能够调用它的任意一个属性和方法。
6.1.2为什么使用反射?
在Java编程语言中,反射是一种强有力的工具,是 面向抽象编程的一种实现方式,它能使代码语句更加灵活,极大提高代码的运行时装配能力。Java反射机制允许编程人员在对类未知的情况下,获取类相关信息的方式变得更加多样灵活,调用类中相应方法,是Java增加其灵活性与动态性 的一种机制。
总结一下,Java反射机制有如下作用:
- 反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力;
- 通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类;
- 使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法;
- 反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。
6.2反射的原理
- 首先我们需要了解Java程序运行的过程,该过程包含两个阶段:编译和运行。
- 在程序编译阶段,Java代码会通过JDK编译成 .class字节码文件;
- 在程序运行阶段,JVM会去调用业务逻辑对应需要的的字节码文件,生成对应的Class对象,并调用其中的属性方法完成业务逻辑。
- Java的反射机制原理:在程序运行阶段,主动让JVM去加载某个 .class文件生成Class对象,并调用其中的方法和属性。 如下图:
6.3反射的使用
- 四个常用的类
类名 | 作用 |
---|---|
Class类 | 类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 类的成员变量(成员变量也称为类的属性) |
Method类 | 类的方法 |
Constructor类 | 类的构造方法 |
6.3.1获取类对象
(1)通过具体类的类名获取
Class bookClass = Book.class;
//输出类名
System.out.println(bookClass.getName());
(2)通过对象实例获取
Book book = new Book();
Class bookClass = book.getClass();
//输出类名
System.out.println(bookClass.getName());
(3)通过class.forName(类的全路径)获取
Class bookClass;
try {
bookClass = Class.forName("test.Book");
//输出类名
System.out.println(bookClass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
(4)通过类加载器 xxxClassLoader.loadClass(类的全路径)
ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
6.3.2获取类对象的构造函数
- 当获取到一个类的Class对象之后,可以调用Class对象的==getDeclaredConstructors()==方法获取该类的构造函数,如下:
// 反射所有声明的构造方法
public static void reflectAllConstructor() {
System.out.println(TAG + "=============获取所有的声明的构造函数==============");
try {
Class<?> classBook = Class.forName("test.Book");
Constructor<?>[] constructorsBook = classBook
.getDeclaredConstructors();
for (Constructor constructor : constructorsBook) {
System.out.println(TAG + constructor);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
- 获取了构造函数之后,调用Constructor类对象的newInstance()即可构造出我们想要类的对象,如下:
Book book = (Book)constructor.newInstance();
6.3.3获取类对象的方法
- 当我们得到了一个Class对象之后,我们可以获取该类的所有方法,如下:
- getDeclaredMethods()和getMethods()都可以获取到类的方法,辨别?
- getMethods()获取了自己定义的公用方法(private获取不了),还把Object父类的公用方法也获取了
- getDeclaredMethods()只能获取自己类中定义的方法,但是可以获取到private方法
// 反射所有的public的函数
public static void reflectPublicMethods() {
System.out.println(TAG + "=============获取所有的public的函数==============");
try {
Class<?> classBook = Class.forName("test.Book");
Method[] methodsBook = classBook.getMethods();
for (Method method : methodsBook) {
System.out.println(TAG + method);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射所有的声明的方法
public static void reflectAllMethods() {
System.out.println(TAG + "=============获取所有的声明的函数==============");
try {
Class<?> classBook = Class.forName("test.Book");
Method[] methodsBook = classBook.getDeclaredMethods();
for (Method method : methodsBook) {
System.out.println(TAG + method);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
6.3.4获取类对象的属性
当我们得到了一个Class对象之后,我们可以获取该类的所有属性,代码如下:
同Methods,获取属性也有getDeclaredFields()和getFields()两种。
// 反射所有的public的属性
public static void reflectPublicFields() {
System.out.println(TAG + "=============获取所有的public的属性==============");
try {
Class<?> classBook = Class.forName("test.Book");
Field[] fieldsBook = classBook.getFields();
for (Field field : fieldsBook) {
System.out.println(TAG + field);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射所有的声明的属性
public static void reflectAllFields() {
System.out.println(TAG + "=============获取所有的声明的属性==============");
try {
Class<?> classBook = Class.forName("test.Book");
Field[] fieldsBook = classBook.getDeclaredFields();
for (Field field : fieldsBook) {
System.out.println(TAG + field);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
6.4反射的优缺点
- 优点:让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利
- 缺点:
- 同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。
- 另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。