什么是反射
反射是指在运行状态中,对于任意一个类,都能够知道这个类所有的属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能称为反射机制。 例如:
- 加载
jdbc
驱动Class.forName('com.mysql.jdbc.Driver.class');
Spring
框架的注解
优点:可以让代码更加灵活、为各种框架提供开箱即用的功能提供了便利。
缺点:让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。
实现方式
1 . 获取 Class 对象
方法一:类.class
Class clazz = String.class;
方法二:实例.getClass()
Class clazz = string.getClass();
方法三:全限定类名
Class clazz = Class.forName("java.lang.String");
方法四:xxxClassLoader.loadClass()
ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
方式五:基本数据类型的包装类的 TYPE 属性
Class clazz = Integer.TYPE;
方式五:使用类加载器加载
Class 常用方法
Class<?> clazz = Class.forName("com.company.User");
// 获取全限定类名
System.out.println(clazz.getName());
// 获取类名
System.out.println(clazz.getSimpleName());
// 获取类的所有属性
Field[] fields = clazz.getDeclaredFields();
for (Field field: fields) {
System.out.println(field);
}
// 获取本类和父类的所有方法
Method[] methods = clazz.getMethods();
for (Method method: methods) {
System.out.println(method);
}
// 获取类的所有方法
Method[] methods2 = clazz.getDeclaredMethods();
for (Method method: methods2) {
System.out.println(method);
}
// 获取指定的方法
Method method = clazz.getMethod("setName", String.class);
- Class 包含类型的 Constructor、Method、Field 等信息
- 获取公开 (public) 元信息,使用
get{元信息名}s
- 获取所有的元信息,使用
getDeclared{元信息名}s
调用构造器创建对象
- 类必须有无参构造器
- 类的构造器访问权限必须足够
Class<?> clazz = Class.forName("com.company.User");
// 直接 new 对象
User user = (User) clazz.newInstance();
// 通过构造器创建对象
Constructor constructor = clazz.getDeclaredConstructor(int.class, String.class, Date.class);
User user2 = (User) constructor.newInstance(1, "1", new Date());
// 通过反射获取普通方法
Method setName = clazz.getMethod("setName", String.class);
// 通过 invoke 调用方法
setName.invoke(user,"马里奥");
// 通过反射获取私有属性
Field name = clazz.getDeclaredField("name");
// 设置 private 属性为可访问
name.setAccessible(true);
name.set(user2, "马里奥");
System.out.println(user2.getName());
反射获取泛型信息
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
Method method = Main.class.getMethod("test", Map.class);
// 获取 method 的形参类型
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
// System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
// 返回 genericParameterTypes 的实际类型参数
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
// System.out.println(actualTypeArgument);
}
}
}
}
public void test(Map<String, Integer> map) {}
}
反射获取注解信息
// 定义@TableAnno
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableAnno {
String value();
}
// 定义@ColumnAnno
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnAnno {
String columnName();
String type();
int length();
}
@Data
@TableAnno("db_user")
public class User {
@ColumnAnno(columnName = "age", type = "smallint", length = 3)
private int age;
@ColumnAnno(columnName = "name", type = "varchar", length = 20)
private String name;
@ColumnAnno(columnName = "birthday", type = "date", length = 10)
private Date birthday;
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> clazz = Class.forName("com.company.User");
// 获取类的注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
// System.out.println(annotation);
}
// 获取属性的注解
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
// 获取注解 columnName 属性的值
ColumnAnno annotation = declaredField.getAnnotation(ColumnAnno.class);
// System.out.println(annotation.columnName());
}
// 获取指定注解的属性值
TableAnno tableAnno = clazz.getAnnotation(TableAnno.class);
String value = tableAnno.value();
// System.out.println(value);
}
}
Reference