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");
	}
}

image

说明:

  • 字面量.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);
    }
}

image

,

posted @ 2025-04-26 23:04  sunpeiyu  阅读(13)  评论(0)    收藏  举报