反射机制 refection
运行时加载、探知、使用编译期间完全未知的类
程序在运行状态中,动态加载一个只要名称的类,对于任意一个已加载的类,都能知道这个类的所有属性和方法,对于任意一个对象,都能够调用其的方法和属性
加载完类之后,在堆内存中,将产生一个Class类型的对象,这个对象包含了完整的类的结构信息,可以通过这个对象查看类的结构,称为反射
作用:
- 动态加载类、获取类的属性、方法、构造器
- 动态构造对象
- 动态调用类和对象的任意方法、构造器
- 动态调用和处理属性
- 获取泛型信息
- 处理注解
Class c = Class.forName("com.test.User");
@Test
public void reflection() throws Exception {
String path = "annotation.Student";
/******************************
*
* 一个类被加载后,JVM就会创建一个对应类的Class,且一个类只对应一个Class
* 所以 clazz 和 clazz2 hashCode相同
*
* */
Class<?> clazz = Class.forName(path);
System.out.println(clazz.hashCode()); // - 254413710
Class<?> clazz2 = Class.forName(path);
System.out.println(clazz2.hashCode()); // - 254413710
/******************************/
System.out.println(clazz.getName()); // - annotation.Student - 含包名
System.out.println(clazz.getSimpleName()); // - Student
Field[] publicField = clazz.getFields(); // - 获取 public 的 field
Field[] addField = clazz.getDeclaredFields(); // - 获取所有的 field
Method[] methods = clazz.getDeclaredMethods(); // - 获取所有方法
clazz.getDeclaredMethod("getName", null); // - 方法无参,null
clazz.getDeclaredMethod("setName", String.class); // - 方法有参,传入参数类型的class
Constructor<?>[] constructors = clazz.getDeclaredConstructors(); // - 获取构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(null);
/******************************/
/**
* 通过反射API调用
* */
Student o = (Student) constructor.newInstance(null);
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.invoke(o, "小小白");
System.out.println(o.getName());
}
反射操作泛型 Generic
java采用泛型擦除机制引入泛型,在Java中的泛型只是给编译器Javac使用的,是确保数据的安全性和免去强制类型转换的麻烦。class文件编译完成后,所有和泛型有关的类型将全部擦除
为了通过反射操作这些类型以迎合实际开发的需要,Java新增了ParameterizedType、GenericArrayType、TypeVariable、WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型
**ParameterizedType:**表示参数化的类型,Collection<String>
**GenericArrayType:**表示一种元素类型是参数化类型或者类型变量的数组类型
**TypeVariable:**是各种类型变量的公共父接口
**WildcardType:**代表一种通配符类型表达式,? extends Number
反射机制性能问题
setAccessible
启用和禁用访问安全检查的开关,值为 true ,则指示反射的对象在使用时应该取消 Java 语言访问检查。false 则指示反射的对象应该实施 Java 语言访问检查
当禁止安全检查时,可以大大提高反射的运行速度
public Map<Integer, Student> reflectionTest(List<Student> list) {
return null;
}
@Test
public void reflectionTest() throws Exception {
/**
* 获取方法参数泛型
* */
Method method = TestClass.class.getMethod("reflectionTest", List.class);
Type[] type = method.getGenericParameterTypes();
for (Type t : type) {
System.out.println("---" + t); // - java.util.List<annotation.Student>
if (t instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType) t).getActualTypeArguments();
for (Type typeArgument : typeArguments) {
System.out.println("泛型类型:" + typeArgument); // - class annotation.Student
}
}
}
/**
* 获取方法返回值泛型
* */
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
Type[] arguments = ((ParameterizedType) returnType).getActualTypeArguments();
for (Type a : arguments) {
System.out.println("返回值泛型类型:" + a);
// - 返回值泛型类型:class java.lang.Integer
// - 返回值泛型类型:class annotation.Student
}
}
}