Java反射常用API解读

概要

Java 反射是造很多轮子必要的技能,比如依赖注入,Json和类的实例的转换等等。本文将介绍Java反射的一些常用类和API

Java 反射常用类

  • Class 包含了类T的所有信息,Java的每个类都有一个Class实例,比如你的项目有一个Student.java 文件,首先你需要把.java文件通过编译器(javac)编译成.class文件,JVM读取Student.class文件会生成一个Class的实例,如果你需要new一个Studen实例时,JVM就会使用Class实例里的信息创造一个Student实例,如果不存在Class实例,就会去classpath找Student.class把它加载进来,如果找不到就会报错。
  • Constructor 构造器类,包含构造器方法信息,可以使用它构造一个实例
  • Field 属性类
  • Method 方法类
  • Annotation 注解类
  • 一个共性: 不Declared的方法只返回public访问权限的部分,包含Declared的方法返回所有访问权限

Class

反射通常都是从Class类开始的,所以我们着重讲Class类
先创建一个项目,导入一些工具包方便我们写代码,依赖

<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.3.0-alpha5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.0-alpha1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies>
  • 编写一个Student类
// Student.java import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Student { public static String grade = "一年级"; int id; double score; private String name; private int age; private String phone; }
  • 获取Student类的Class实例
// 直接.class Class<?> stuClass1 = Student.class; // 使用ClassLoader Class<?> stuClass2 = ClassLoader.getSystemClassLoader().loadClass("com.yeyeck.Student"); // 通过一个Student实例 Student student = new Student(); Class<?> stuClass3 = student.getClass(); log.info("类名(包含包名): {}", stuClass1.getName()); log.info("类名(不包含包名):{}", stuClass1.getSimpleName()); // 15:58:55.946 [main] INFO com.yeyeck.ClassTest - 类名(包含包名): com.yeyeck.Student // 15:58:55.946 [main] INFO com.yeyeck.ClassTest - 类名(不包含包名):Student
  • 获取Student的属性
log.info("所有属性:"); Field[] fields = stuClass1.getDeclaredFields(); for(Field field: fields) { log.info(field.toString()); } log.info("public属性"); Field[] fields2 = stuClass1.getFields(); for (Field field : fields2) { log.info(field.toString()); } // 15:58:55.955 [main] INFO com.yeyeck.ClassTest - 所有属性: // 15:58:55.955 [main] INFO com.yeyeck.ClassTest - public static java.lang.String com.yeyeck.Student.grade // 15:58:55.966 [main] INFO com.yeyeck.ClassTest - int com.yeyeck.Student.id // 15:58:55.967 [main] INFO com.yeyeck.ClassTest - double com.yeyeck.Student.score // 15:58:55.967 [main] INFO com.yeyeck.ClassTest - private java.lang.String com.yeyeck.Student.name // 15:58:55.968 [main] INFO com.yeyeck.ClassTest - private int com.yeyeck.Student.age // 15:58:55.968 [main] INFO com.yeyeck.ClassTest - private java.lang.String com.yeyeck.Student.phone // 15:58:55.968 [main] INFO com.yeyeck.ClassTest - public属性 // 15:58:55.969 [main] INFO com.yeyeck.ClassTest - public static java.lang.String com.yeyeck.Student.grade
  • 获取Student的方法
Method[] methods = stuClass1.getMethods(); log.info("方法:"); for (Method method: methods) { log.info(method.toString()); } 15:58:55.970 [main] INFO com.yeyeck.ClassTest - 方法: // 15:58:55.980 [main] INFO com.yeyeck.ClassTest - public boolean com.yeyeck.Student.equals(java.lang.Object) // 15:58:55.981 [main] INFO com.yeyeck.ClassTest - public java.lang.String com.yeyeck.Student.toString() // 15:58:55.982 [main] INFO com.yeyeck.ClassTest - public int com.yeyeck.Student.hashCode() // 15:58:55.982 [main] INFO com.yeyeck.ClassTest - public java.lang.String com.yeyeck.Student.getName() // 15:58:55.983 [main] INFO com.yeyeck.ClassTest - public void com.yeyeck.Student.setName(java.lang.String) // 15:58:55.983 [main] INFO com.yeyeck.ClassTest - public int com.yeyeck.Student.getId() // 15:58:55.984 [main] INFO com.yeyeck.ClassTest - public void com.yeyeck.Student.setId(int) // 15:58:55.984 [main] INFO com.yeyeck.ClassTest - public void com.yeyeck.Student.setScore(double) // 15:58:55.985 [main] INFO com.yeyeck.ClassTest - public int com.yeyeck.Student.getAge() // 15:58:55.985 [main] INFO com.yeyeck.ClassTest - public double com.yeyeck.Student.getScore() // 15:58:55.985 [main] INFO com.yeyeck.ClassTest - public void com.yeyeck.Student.setPhone(java.lang.String) // 15:58:55.986 [main] INFO com.yeyeck.ClassTest - public java.lang.String com.yeyeck.Student.getPhone() // 15:58:55.986 [main] INFO com.yeyeck.ClassTest - public void com.yeyeck.Student.setAge(int) // 15:58:55.986 [main] INFO com.yeyeck.ClassTest - public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException // 15:58:55.986 [main] INFO com.yeyeck.ClassTest - public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException // 15:58:55.987 [main] INFO com.yeyeck.ClassTest - public final void java.lang.Object.wait() throws java.lang.InterruptedException // 15:58:55.999 [main] INFO com.yeyeck.ClassTest - public final native java.lang.Class java.lang.Object.getClass() // 15:58:56.000 [main] INFO com.yeyeck.ClassTest - public final native void java.lang.Object.notify() // 15:58:56.000 [main] INFO com.yeyeck.ClassTest - public final native void java.lang.Object.notifyAll()
  • 获取Student的构造器
log.info("构造器:"); Constructor[] constructors = stuClass1.getConstructors(); for (Constructor constructor : constructors) { log.info(constructor.toString()); } // 使用默认构造器初始化一个实例 Constructor constructor = stuClass1.getDeclaredConstructor(); Object obj = constructor.newInstance(); log.info(obj.toString()); // 15:58:56.001 [main] INFO com.yeyeck.ClassTest - 构造器: // 15:58:56.001 [main] INFO com.yeyeck.ClassTest - public com.yeyeck.Student() // 15:58:56.001 [main] INFO com.yeyeck.ClassTest - public com.yeyeck.Student(int,double,java.lang.String,int,java.lang.String) // 15:58:56.002 [main] INFO com.yeyeck.ClassTest - Student(id=0, score=0.0, name=null, age=0, phone=null)
  • 获取Student类的注解
Annotation[] annotations = stuClass1.getAnnotations();

Constructor类

  • 带Declared的方法会获取所有声明的构造器,不带Declared的方法只会获取public修饰的构造器,我们先给Student添加一个private的构造器,可以看到两个方法的区别
Class<?> stuClass = Student.class; log.info("非Declared: "); Constructor[] constructors1 = stuClass.getConstructors(); for (Constructor constructor : constructors1) { log.info(constructor.toString()); } log.info("Declared"); Constructor[] constructors2 = stuClass.getDeclaredConstructors(); for (Constructor constructor : constructors2) { log.info(constructor.toString()); } // 16:26:52.959 [main] INFO com.yeyeck.AppTest - 非Declared: // 16:26:52.961 [main] INFO com.yeyeck.AppTest - public com.yeyeck.Student(int,double,java.lang.String,int,java.lang.String) // 16:26:52.961 [main] INFO com.yeyeck.AppTest - public com.yeyeck.Student() // 16:26:52.961 [main] INFO com.yeyeck.AppTest - Declared // 16:26:52.961 [main] INFO com.yeyeck.AppTest - public com.yeyeck.Student(int,double,java.lang.String,int,java.lang.String) // 16:26:52.961 [main] INFO com.yeyeck.AppTest - private com.yeyeck.Student(java.lang.String,int,java.lang.String) // 16:26:52.961 [main] INFO com.yeyeck.AppTest - public com.yeyeck.Student()
  • 根据参数获取构造器
// 获取无参构造器并初始化一个实例 Constructor noArgsConstructor = stuClass.getConstructor(); Object stu1 = noArgsConstructor.newInstance(); log.info(stu1.toString()); // 获取有参构造器并初始化一个实例 Constructor withArgsConstructor = stuClass.getConstructor(int.class, double.class, String.class, int.class, String.class); Object stu2 = withArgsConstructor.newInstance(1, 90.0, "张三", 20, "133333333333"); log.info(stu2.toString()); // 16:41:08.301 [main] INFO com.yeyeck.AppTest - Student(id=0, score=0.0, name=null, age=0, phone=null) // 16:41:08.304 [main] INFO com.yeyeck.AppTest - Student(id=1, score=90.0, name=张三, age=20, phone=133333333333)

Field类

  • 根据名称获取属性
Class<?> stuClass = Student.class; // 根据名称获取一个public属性 Field field1 = stuClass.getField("grade"); log.info(field1.toString()); // 根据名称获取一个非public属性 Field field2 = stuClass.getDeclaredField("name"); log.info(field2.toString()); log.info(field2.getName()); // 访问属性的名称 log.info(field2.getType().toString()); // 访问属性的类型 // 16:53:04.366 [main] INFO com.yeyeck.FieldTest - public static java.lang.String com.yeyeck.Student.grade // 16:53:04.366 [main] INFO com.yeyeck.FieldTest - private java.lang.String com.yeyeck.Student.name // 16:53:04.374 [main] INFO com.yeyeck.FieldTest - name // 16:53:04.375 [main] INFO com.yeyeck.FieldTest - class java.lang.String
  • 访问一个对象的属性值
Field field2 = stuClass.getDeclaredField("name"); Object instance = Student.class.getDeclaredConstructor().newInstance(); log.info("name是否可以访问: {}", field2.canAccess(instance)); // name是private属性不允许访问 // 强制访问private属性 field2.setAccessible(true); field2.set(instance, "张三"); log.info(instance.toString()); // 17:01:36.639 [main] INFO com.yeyeck.FieldTest - name是否可以访问: false // 17:01:36.643 [main] INFO com.yeyeck.FieldTest - Student(id=0, score=0.0, name=张三, age=0, phone=null)

Method 类

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import lombok.extern.slf4j.Slf4j; @Slf4j public class MethodTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class<?> stuClass = Student.class; // 根据方法名获取一个无参方法 Method methodGetName = stuClass.getMethod("getName"); // 查看返回类型 log.info(methodGetName.getReturnType().toString()); // 调用该方法,调用的时候需要一个Student实例 Object instance = Student.class.getConstructor().newInstance(); Object res = methodGetName.invoke(instance); log.info("getName返回: {}", String.valueOf(res)); // 根据方法名和参数获取一个有参方法 Method methodSetName = stuClass.getMethod("setName", String.class); // 调用该方法 methodSetName.invoke(instance, "张三"); // 查看效果 log.info("name: {}", String.valueOf(methodGetName.invoke(instance))); } }
阅读(28)
评论(0)
updated@2020-11-18
评论区
目录