Java反射机制允许运行时动态获取类信息并操作其成员。获取class对象有三种方式:使用类名.class、对象.getclass()或class.forname(“全限定类名”)。创建实例可用clazz.getdeclaredconstructor().newinstance()方法。调用方法需通过method类,如method.invoke(obj, “world”)。访问字段则用field类,私有时要设置setaccessible(true)。应用中需注意性能问题、泛型擦除及安全限制。反射虽强大但应合理使用。
Java 的反射机制允许程序在运行时动态获取类的信息,并能操作类的属性和方法。核心就在于 Class 对象的获取与使用。只要拿到了 Class 对象,就能访问类的各种成员、创建实例、调用方法、修改字段值等。
获取 Class 对象的几种方式
要使用反射,第一步是获得类的 Class 对象。有以下几种常见方式:
- 使用 类名.class:比如 String.class
- 通过对象调用 .getClass() 方法:比如 “hello”.getClass()
- 利用 Class.forName(“全限定类名”):比如 Class.forName(“java.util.ArrayList”)
这三种方式各有适用场景。例如,已知类型时用 .class 最方便;运行时拿到对象时,用 .getClass() 更合适;而需要根据字符串加载类(如配置文件中指定类名)时,就用 forName()。
立即学习“Java免费学习笔记(深入)”;
创建类的实例
有了 Class 对象之后,就可以用来创建类的实例了。通常使用 newInstance() 方法,不过这个方法要求类必须有一个无参构造函数。
Class<?> clazz = MyClass.class; MyClass obj = (MyClass) clazz.newInstance();
注意:从 Java 9 开始,newInstance() 被标记为过时,推荐使用 getDeclaredConstructor().newInstance() 来替代,这样可以更灵活地控制构造方法。
例如:
MyClass obj = clazz.getDeclaredConstructor().newInstance();
如果构造函数带参数,也可以传进去对应的类型和值。
操作类的方法和字段
反射不仅可以创建对象,还能动态调用方法和访问字段。
调用方法
使用 Method 类来表示方法。先通过 getMethod() 或 getDeclaredMethod() 获取方法对象,然后调用 invoke() 执行。
Method method = clazz.getMethod("sayHello", String.class); method.invoke(obj, "World");
注意几点:
- getMethod() 只能获取 public 方法,包括继承来的。
- getDeclaredMethod() 可以获取所有声明的方法(不管访问权限),但不会包含父类方法。
- 如果方法是 private 的,需要先调用 method.setAccessible(true) 才能调用。
访问字段
字段操作类似,用 Field 类处理:
Field field = clazz.getDeclaredField("name"); field.setAccessible(true); field.set(obj, "Tom"); String value = (String) field.get(obj);
同样要注意访问权限的问题,私有字段必须设置 setAccessible(true) 才能读写。
实际应用中的小细节
- 性能问题:反射操作比直接代码调用慢很多,特别是在频繁调用时。如果对性能敏感,建议缓存 Method 或 Field 对象,避免重复查找。
- 泛型擦除:Java 的泛型在运行时会被擦除,所以不能通过反射获取泛型的具体类型信息。
- 安全性限制:有些环境(如安全管理器启用时)会限制反射访问私有成员,需要注意权限配置。
基本上就这些。反射虽然强大,但也不是万能的,用的时候要考虑清楚是否真的需要它。