Java 反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的方法和属性;这种动态获取信息以及调用对象方法的功能称之为Java语言的反射机制。
在运行时 - 判断任意一个对象所属的类
在运行时 - 构造任意一个类的实例
在运行时 - 判断任意一个类的成员变量和方法
在运行时 - 调用任意对象的方法
类名 | 用途 |
---|---|
Class | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field | 代表类的成员变量/属性 |
Method | 代表类的方法 |
Constructor | 代表类的构造方法 |
Class对象是Java反射的基础,它包含了与类相关的信息,事实上,Class对象就是用来创建类的所有对象的。Class对象是java.lang.Class<T>
这个类生成的对象,其中类型参数T表示由此 Class 对象建模的类的类型。例如,String.class的类型是 Class<String>
;如果将被建模的类未知,则使用Class<?>。以下是Java API的描述:
Class类的实例表示正在运行的 Java应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。基本的Java类型(boolean、byte、char、short、int、long、float和double)和关键字void也表示为Class对象。
Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
实际上,每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当的说,是被保存在一个同名的.class文件中)。如果我们想生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用类加载器子系统,类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件,并将其载入,一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有实例。
通过实例变量的getClass()方法。例如:
Class c1 = new String("abc").getClass();
通过Class类的静态方法——forName()来实现,例如:
Class class =Class.forName("com.class");
注意:当使用Class.forName()方法时,你必须提供完全限定类名。即类名要包括所有包
推荐 - 使用类字面常量或TYPE字段,例如:
Class myObjectClass= MyObject.class
(类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型),这种方式不仅更简单,而且更安全,因为它在编译时就会受到检查,并且根除了对forName方法的调用,所以也更高效,建议使用“.class”的形式。
Class c = Integer.TYPE;
TYPE是基本数据类型的包装类型的一个标准字段,它是一
个引用,指向对应的基本数据类型的Class对象,附表如下,两边等价
基本类型 | 包装类 |
---|---|
boolean.class | Boolean.TYPE |
char.class | Character.TYPE |
byte.class | Byte.TYPE |
short.class | Short.TYPE |
int.class | Integer.TYPE |
long.class | Long.TYPE |
float.class | Float.TYPE |
double.class | Double.TYPE |
void.class | Void.TYPE |
下面我们使用代码来演示一下反射:
基础类
package com;
public class TargetObject {
private String value;
public TargetObject() {
value = "TargetObject";
}
public void publicMethod(String s) {
System.out.println("publicMethod " + s);
}
private void privateMethod() {
System.out.println("privateMethod " + value);
}
}
主类
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException, NoSuchMethodException,
InvocationTargetException, NoSuchFieldException {
/**
* 获取TargetObject类的Class对象并且创建TargetObject类实例
*/
Class<?> tagetClass = Class.forName("com.TargetObject");
TargetObject targetObject = (TargetObject) tagetClass.newInstance();
/**
* 获取所有类中所有定义的方法
*/
Method[] methods = tagetClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
/**
* 获取指定方法并调用
*/
Method publicMethod = tagetClass.getDeclaredMethod("publicMethod",
String.class);
publicMethod.invoke(targetObject, "JavaGuide");
/**
* 获取指定参数并对参数进行修改
*/
Field field = tagetClass.getDeclaredField("value");
//为了对类中的参数进行修改我们取消安全检查
field.setAccessible(true);
field.set(targetObject, "JavaGuide");
/**
* 调用 private 方法
*/
Method privateMethod = tagetClass.getDeclaredMethod("privateMethod");
//为了调用private方法我们取消安全检查
privateMethod.setAccessible(true);
privateMethod.invoke(targetObject);
}
测试工程:reflection-demo
优点: 运行期类型的判断,动态加载类,提高代码灵活度。
缺点:
性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。
安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。
反射是框架设计的灵魂。
在模块化或者是通用性的开发中,我们经常通过反射来创建实例并使用。在我们日常使用spring框架中大量使用到了反射机制
示例:
在使用原生的JDBC连接数据库时,采用 Class.forName()
通过反射加载数据库的驱动程序。
Spring 框架的IoC(动态创建管理Bean)以及AOP功能都和反射有关系
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。