Java反射机制
什么是RTTI
在运行期间,就是你的程序可以发现和使用运行时类型信息。而RTTI的本身就是在运行时识别一个对象的类型。RTTI提供了运行时类型信息的基础,而反射是基于这些类型信息来实现其功能的。
反射的作用
在运行期,对于任意的一个类,可以完成获取其所有的属性,方法,注解,类型信息并且还可以执行其方法和引用属性等操作。
反射用法1,创建类
使用说明:
- 当我们想要获取类本身的信息时,静态加载、查看,使用类.class方式。
- 当我们想要在程序运行时,譬如web中想要增删改查获取到对象后,那么属于动态加载,使用对象.getClass方法。
1. Class.forName方式
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("cn.spy.test.ReflectModel");
System.out.println(clazz.newInstance());
}
结果:
cn.spy.test.ReflectModel@53606bf5
说明:一旦类的Class对象被载入了内存,它就被用来创建这个类的所有对象。如果我们想要在运行时使用类型的信息,就必须首先得获取对应的Class对象的引用。因为Class.forName的形式获取类的结果在编译期是不可知的,所以毫无疑问,如果找不到加载的类,就会报找不到类的异常。
2. 对象.getClass()方式
如果我们已经拥有了类的对象,可以采用getClass方法来获取类的引用;返回Class类对象。
3. 字面量方式:类名.class方式
当使用 .class 方式来创建对Class对象的引用时,不会自动初始化该Class对象。
public class ReflectTest {
public static void main(String[] args) throws Exception {
Class<Apple> appleClazz = Apple.class;
// static final修饰的变量类未被初始化
System.out.println("static final name : " + Apple.name);
System.out.println("------------------------------------");
// static修饰的变量类执行了初始化
System.out.println("static price : " + Apple.price);
System.out.println("------------------------------------");
// Class.forName方式初始化了对象
Class<?> clazz = Class.forName("cn.spy.test.Orange");
}
}
class Apple {
static final String name = "apple";
static int price = 20;
static {
System.out.println("Now Class is Apple");
}
}
class Orange {
static String name = "orange";
static {
System.out.println("Now Class is Orange");
}
}

说明:
- 字面量.class方式创建对象不会马上初始化对象。
- Class.forName方式创建对象会马上进行初始化操作。
- 字面量.class方式引用静态不可变的属性将不会执行初始化,引用静态非不可变的属性将会执行初始化。(理由:final修饰的类变量在类加载的准备阶段就进行初始化操作,根本不用等到初始化阶段进行初始化操作。而jvm规范中规定了在初始化阶段,如果执行了引用了类的静态非final的变量这种主动引用方式,那么将会对类进行初始化操作)
反射用法2,构造器创建对象
getConstructor(T t...): 获取public的公有构造器,方法参数顺序为构造器参数类型的顺序。
getDeclaredConstructor(T t...):获取私有、受保护、默认、公有的构造器,方法参数顺序为构造器参数类型的顺序。
getConstructors():获取所有的构造器。
public static void main(String[] args) throws Exception {
Class<UserModel> clazz = UserModel.class;
// 调用公有无参构造器
Constructor<UserModel> clazzConstructor1 = clazz.getConstructor();
clazzConstructor1.newInstance();
// 调用公有的参数为String的构造器
Constructor<UserModel> clazzConstructor2 = clazz.getConstructor(String.class);
clazzConstructor2.newInstance("张三");
// 调用公有的参数为String、Integer的构造器
Constructor<UserModel> clazzConstructor3 = clazz.getConstructor(String.class, Integer.class);
clazzConstructor3.newInstance("张三", 30);
// 调用私有的参数为Integer
Constructor<UserModel> clazzConstructor4 = clazz.getDeclaredConstructor(Integer.class);
clazzConstructor4.setAccessible(true);
clazzConstructor4.newInstance(30);
}
public class UserModel {
private String name;
private Integer age;
public UserModel() {
System.out.println("调用公有无参构造器");
}
public UserModel(String name) {
this.name = name;
System.out.println("调用公有的参数为name = "+name+" 的构造器");
}
public UserModel(String name, Integer age) {
this.name = name;
this.age = age;
System.out.println("调用公有的参数为name = "+name+ " age = "+age+" 构造器");
}
private UserModel(Integer age) {
this.age = age;
System.out.println("调用私有的参数为age = "+age+" 的构造器");
}
}
反射用法3,运行期查看包、类、属性、方法、对象、注解信息
public class ReflectTest {
public static void main(String[] args) throws Exception {
UserModel userModel = new UserModel("张三", 30);
Class<? extends UserModel> clazz = userModel.getClass();
Package clazzPackage = clazz.getPackage();
// 获取包名
System.out.println("包名 = " + clazzPackage.getName());
// 获取类名
System.out.println("类名 = " + clazz.getName());
// 获取类的所有的接口
Arrays.stream(clazz.getInterfaces()).forEach(interClazz -> System.out.println("类的所有接口名 = " + interClazz.getName()));
// 获取类的所有属性
Arrays.stream(clazz.getDeclaredFields()).forEach(f -> System.out.println("类的所有属性名 = " + f.getName()));
// 获取类的指定属性
Field field = clazz.getDeclaredField("name");
System.out.println("属性名 = " + field.getName());
System.out.println("属性类型 = " + field.getType().getName());
field.setAccessible(true);
System.out.println("属性值 = " + field.get(userModel));
// 获取类的所有注解
Arrays.stream(clazz.getAnnotations()).forEach(ann -> System.out.println("类的所有注解名 = " + ann.annotationType().getName()));
// 获取类的指定注解
System.out.println("注解 = " + clazz.getAnnotation(org.springframework.stereotype.Component.class));
// 获取类的所有方法
Arrays.stream(clazz.getMethods()).forEach(m -> System.out.println("类的所有方法名 = " + m.getName()));
// 获取类的指定方法
Class<?>[] clazzArr = new Class[2];
clazzArr[0] = String.class;
clazzArr[1] = Integer.class;
System.out.println("方法名 = " + clazz.getMethod("add", clazzArr));
}
}
@Component
public class UserModel implements Serializable {
private String name;
private Integer age;
public UserModel() {
System.out.println("调用公有无参构造器");
}
public UserModel(String name) {
this.name = name;
System.out.println("调用公有的参数为name = "+name+" 的构造器");
}
public UserModel(String name, Integer age) {
this.name = name;
this.age = age;
System.out.println("调用公有的参数为name = "+name+ " age = "+age+" 构造器");
}
private UserModel(Integer age) {
this.age = age;
System.out.println("调用私有的参数为age = "+age+" 的构造器");
}
public void add(String name, Integer age) {
System.out.println("add方法 name = " + name);
System.out.println("add方法 age = " + age);
}
}
反射用法4,反射修改属性值、执行方法
- 反射修改private属性值
public static void main(String[] args) throws Exception {
UserModel userModel = new UserModel("张三", 30);
Class<? extends UserModel> clazz = userModel.getClass();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(userModel, "李四");
System.out.println(userModel.getName());
}
- 反射执行对象的方法
public String concat( String value, String... arr) {
StringBuilder valueBuilder = new StringBuilder(value);
valueBuilder.append("#");
for (String str : arr) {
valueBuilder.append(str);
valueBuilder.append(",");
}
value = valueBuilder.toString();
return value.substring(0, value.length() - 1);
}
public static void main(String[] args) throws Exception {
UserModel userModel = new UserModel();
Class<? extends UserModel> clazz = userModel.getClass();
Method method = clazz.getMethod("concat", String.class, String[].class);
String result = (String) method.invoke(userModel, "开头", new String[]{"1", "2", "3"});
System.out.println(result);
}
反射用法5,反射修改注解信息
public class ValidatorStrResolver {
public static <T> void validateStr(T t) throws IllegalAccessException {
Field[] fields = t.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
ValidatedStr validatedStr = field.getAnnotation(ValidatedStr.class);
String str = (String) field.get(t);
if (validatedStr != null) {
if (!Objects.equals(field.getType(), String.class)) {
throw new RuntimeException("ValidatedStr注解只能修饰字符串变量!");
}
if (str == null || str.length() == 0) {
if (validatedStr.message() == null || validatedStr.message().length() == 0) {
throw new RuntimeException(field.getName() + " 字符串不能为空!");
} else {
throw new RuntimeException(validatedStr.message());
}
}
if (validatedStr.max() <= str.length()) {
throw new RuntimeException(field.getName() + " 字符串长度不能大于" + validatedStr.max());
}
if (validatedStr.min() >= str.length()) {
throw new RuntimeException(field.getName() + " 字符串长度不能小于" + validatedStr.max());
}
}
}
}
public static <T> void modifyStr(T t, String modifyMessage,
int modifyMax, int modifyMin) throws NoSuchFieldException, IllegalAccessException {
Field[] fields = t.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
ValidatedStr validatedStr = field.getAnnotation(ValidatedStr.class);
InvocationHandler handler = Proxy.getInvocationHandler(validatedStr);
Field annField = handler.getClass().getDeclaredField("memberValues");
annField.setAccessible(true);
Map<String, Object> memberValues = (Map<String, Object>) annField.get(handler);
memberValues.put("message", modifyMessage);
memberValues.put("max", modifyMax);
memberValues.put("min", modifyMin);
}
}
}
public class ReflectTest {
public static void main(String[] args) throws Exception {
UserModel userModel = new UserModel("ABCDEF");
ValidatorStrResolver.validateStr(userModel);
System.out.println(userModel.getName());
ValidatorStrResolver.modifyStr(userModel, "当前的字符串的值不能存在空!", 3, 2);
ValidatorStrResolver.validateStr(userModel);
}
}

,

浙公网安备 33010602011771号