> 文章列表 > Java 反射常用方法

Java 反射常用方法

Java 反射常用方法

参考资料

  1. Java反射系列–方法大全
  2. Java反射(通俗易懂)
  3. 【小家java】Java反射机制中Class.getXXX()和Class.getDeclaredXXX()的使用区别和注意事项
  4. 【小家java】java8新特性之—反射获取方法参数名

目录

  • 一. 前期准备
    • 1.1 准备类与接口
    • 1.2 方法总结
  • 二. 获取类的字节码对象
    • 2.1 类.class
    • 2.2 类对象.getClass()
    • 2.3 Class.forName("类的全路径")
    • 2.4 cls.getSuperclass() 获取父类字节码对象
  • 三. 类相关信息的获取
    • 3.1 cls.getName() 获取全路径类名
    • 3.2 cls.getSimpleName() 获取类名
    • 3.3 cls.getPackageName() 获取包名
    • 3.4 cls.getInterfaces() 获取接口的字节码对象
    • 3.5 类注解
      • 3.5.1 类注解判断
      • 3.5.2 类注解获取
  • 四. 创建对象
    • 4.1 cls.getConstructor().newInstance() 无参构造
    • 4.2 cls.getConstructor(类型.class).newInstance(参数) 有参构造
  • 五. 获取Field属性
    • 5.1 cls.getFields()
    • 5.2 cls.getField("属性名")
    • 5.3 cls.getDeclaredFields()
  • 六. Field属性相关信息的获取
    • 6.1 field.getName()
    • 6.2 field.canAccess(类对象)
    • 6.3 field.setAccessible( )
    • 6.4 field.get(类对象) 属性值获取
    • 6.5 field.getType()
    • 6.6 field.getModifiers()
    • 6.7 Filed注解
      • 6.7.1 field.isAnnotationPresent(注解.class)
      • 6.7.2 field.getAnnotations()
      • 6.7.3 field.getAnnotation(注解.class)
  • 七. 获取Method方法
    • 7.1 cls.getMethods()
    • 7.2 cls.getMethod("方法名", 参数.class)
    • 7.3 cls.getDeclaredMethods()
  • 八. Method相关信息的获取
    • 8.1 method.invoke("类对象", "参数") 执行方法
    • 8.2 Method注解
      • 8.2.1 method.isAnnotationPresent(注解.class)
      • 8.2.2 method.getAnnotation(注解.class)
    • 8.3 method.getReturnType()
    • 8.4 method.getParameterCount()
    • 8.5 method.getParameterTypes()
    • 8.6 执行private方法

一. 前期准备

1.1 准备类与接口

⏹接口

public interface Test25Interface {String address = "地球";String queryInfo();
}

⏹定义一个类,内含

  • public属性和方法
  • private属性和方法
import java.math.BigDecimal;
import java.util.List;public class Test25Form {private BigDecimal id = BigDecimal.ONE;public List<String> hobbyList;protected BigDecimal getId() {return this.id;}private String printTest25FormInfo(String param) {System.out.println("printTest25FormInfo方法执行了,传入的参数为:" + param);return "传入的参数为:" + param;}public void setId(BigDecimal id) {this.id = id;}public List<String> getHobbyList() {return hobbyList;}public void setHobbyList(List<String> hobbyList) {this.hobbyList = hobbyList;}
}

⏹继承父类,并且实现接口

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;public class Test26Form extends Test25Form implements Test25Interface {@NotNull(message = "不能为空")private String name = "贾飞天";public Integer age = 18;protected BigDecimal money = new BigDecimal(18);public Test26Form(@NotNull(message = "不能为空") String name, Integer age) {this.name = name;this.age = age;}private Integer getNum(Integer num) {return 10 + num;}public Test26Form() {System.out.println();}@Overridepublic String queryInfo() {System.out.println("queryInfo方法执行了");return "默认的返回消息!";}public void printInfo(String msg) {System.out.println("打印消息: " + msg + "了!");}@NotNullpublic BigDecimal printInfo(String msg1, String msg2) {System.out.println("打印消息: " + msg1 + "了!");System.out.println("打印消息: " + msg2 + "了!");return BigDecimal.ZERO;}@Overridepublic String toString() {return "Test26Form{" +"name='" + name + '\\'' +", age=" + age +"} " + super.toString();}
}

1.2 方法总结

  • Class,Field,Method都可以获取标记在身的注解
  • get系列:可获取本类的public + 父类或接口的public(含静态方法)
  • getDeclared系列:可获取本类所有的访问权限的元素(含静态方法)
  • private的Method和Filed不能直接使用,必须要设置允许访问
  • 通过名称获取Filed或Method的时候,该名称所对应的Filed或Method必须存在,否则会报错

二. 获取类的字节码对象

2.1 类.class

Class<Test26Form> cls1 = Test26Form.class;
System.out.println(cls1);  // class com.example.jmw.form.Test26Form

2.2 类对象.getClass()

Test26Form form = new Test26Form();
Class<? extends Test26Form> cls2 = form.getClass();
System.out.println(cls2);  // class com.example.jmw.form.Test26Form

2.3 Class.forName(“类的全路径”)

Class cls3 = Class.forName("com.example.jmw.form.Test26Form");
System.out.println(cls3);  // class com.example.jmw.form.Test26Form

2.4 cls.getSuperclass() 获取父类字节码对象

Class<? super Test26Form> superclass = cls1.getSuperclass();
System.out.println(superclass);  // class com.example.jmw.form.Test25Form

三. 类相关信息的获取

3.1 cls.getName() 获取全路径类名

String fullName = cls1.getName();
System.out.println(fullName);  // com.example.jmw.form.Test26Form

3.2 cls.getSimpleName() 获取类名

String simpleName = cls1.getSimpleName();
System.out.println(simpleName);  // Test26Form

3.3 cls.getPackageName() 获取包名

String packageName = cls1.getPackageName();
System.out.println(packageName);  // com.example.jmw.form

3.4 cls.getInterfaces() 获取接口的字节码对象

  • 一个类可以实现多个接口,所以得到的是一个数组
  • 得到接口的字节码之后,可以获取接口中的属性和方法
Class<?>[] interfaces = cls1.getInterfaces();
System.out.println(Arrays.toString(interfaces));  
// [interface com.example.jmw.form.Test25Interface]// 获取第一个接口的字节码对象
Class<?> anInterface = interfaces[0];
// 获取接口上的名叫address的属性
Field fieldInterface = anInterface.getField("address");
// 获取该属性所对应的属性值
Object address = fieldInterface.get(anInterface);
System.out.println(address);  // 地球

3.5 类注解

3.5.1 类注解判断

  • 判断该注解是否在类上存在
cls.isAnnotationPresent(注解.class);

3.5.2 类注解获取

  • 获取类上标记的所有的注解
 cls.getAnnotations()
  • 获取类上标记的指定注解
cls.getAnnotation(注解.class)

四. 创建对象

4.1 cls.getConstructor().newInstance() 无参构造

Test26Form form1 = cls1.getConstructor().newInstance();
System.out.println(form1);

4.2 cls.getConstructor(类型.class).newInstance(参数) 有参构造

Test26Form form2 = cls1.getConstructor(String.class, Integer.class).newInstance("枫叶红", 10);
System.out.println(form2);

五. 获取Field属性

5.1 cls.getFields()

  • 获取当前类和父类上所有标记为public的属性名
Field[] fields = cls1.getFields();
Arrays.stream(fields).map(Field::getName).forEach(System.out::println);

5.2 cls.getField(“属性名”)

  • 获取当前类和父类上为public的age属性,如果该属性不存在会报错
Field ageField = cls1.getField("age");
System.out.println(ageField);
  • 获取本类或父类上为public的id属性,由于该属性不存在会报错,因此使用filter函数过滤
Optional<Field> idOptional = Arrays.stream(fields).filter(filed -> "id".equals(filed.getName())).findAny();
System.out.println(idOptional);

5.3 cls.getDeclaredFields()

  • 获取本类(不包含父类)的所有修饰符的属性,包括privateprotected
Field[] declaredFields = cls1.getDeclaredFields();
Arrays.stream(declaredFields).map(Field::getName).forEach(System.out::println);  // name age money

六. Field属性相关信息的获取

  • 获取名称为name的私有Field属性对象
Optional<Field> namePrivateFieldOptional = Arrays.stream(declaredFields).filter(filed -> "name".equals(filed.getName())).findAny();// 获取名称为name的Field属性
if (namePrivateFieldOptional.isPresent()) {Field namePrivateField = namePrivateFieldOptional.get();
}

6.1 field.getName()

  • 获取当前属性名
String filedName = namePrivateField.getName();
System.out.println(filedName);

6.2 field.canAccess(类对象)

  • 判断该属性是否可以访问
boolean accessAble1 = namePrivateField.canAccess(form1);
System.out.println(accessAble1);  // false

6.3 field.setAccessible( )

  • 置压制访问类型检查,这样才能访问到private修饰符的属性值
namePrivateField.setAccessible(true);// 因为访问类型检查已经被压制,因此该属性可以访问
boolean accessAble2 = namePrivateField.canAccess(form1);
System.out.println(accessAble2);  // true

6.4 field.get(类对象) 属性值获取

  • 属性值获取
// 设置压制访问类型检查,这样才能访问到private修饰符的属性值
namePrivateField.setAccessible(true);// 获取属性所对应的属性值,注意:参数为类对象,不能为类的字节码文件
Object filedValue = namePrivateField.get(form1);
System.out.println(filedValue);  // 枫叶红

6.5 field.getType()

  • 获取属性所对应的类型
Class<?> fieldType = namePrivateField.getType();
System.out.println(fieldType.getName());  // java.lang.String

6.6 field.getModifiers()

  • 获取该属性的修饰符,常与Modifier对象一同使用
import java.lang.reflect.Modifier;// 获取该属性的修饰符
int modifiers = namePrivateField.getModifiers();// 判断该属性是否为public
boolean isPublicResult = Modifier.isPublic(modifiers);
System.out.println(isPublicResult);  // false// 判断该属性是否为Static
boolean isStaticResult = Modifier.isStatic(modifiers);
System.out.println(isStaticResult);  // false// 判断该属性是否为Private
boolean isPrivateResult = Modifier.isPrivate(modifiers);
System.out.println(isPrivateResult);  // true

6.7 Filed注解

6.7.1 field.isAnnotationPresent(注解.class)

  • 判断该注解是否存在于Field上

6.7.2 field.getAnnotations()

  • 获取属性上标记的所有注解
Annotation[] annotations = namePrivateField.getAnnotations();
System.out.println(Arrays.toString(annotations));

6.7.3 field.getAnnotation(注解.class)

  • 获取属性上标记的指定类型的注解
import javax.validation.constraints.NotNull;NotNull notNullAnnotation = namePrivateField.getAnnotation(NotNull.class);
// 获取注解上message值
System.out.println(notNullAnnotation.message());  // 不能为空

七. 获取Method方法

7.1 cls.getMethods()

  • 获取当前类和其父类上所有修饰符为public的Method
Method[] methods = cls1.getMethods();

7.2 cls.getMethod(“方法名”, 参数.class)

  • 通过方法名和参数获取当前类和其父类上指定的Method对象
// 通过指定方法名称和参数类型的方法来获取Method对象(注意: 如果方法名称不存在或参数类型不正确的话,会报错,不会返回null)
Method printInfoTwoParamMethod = cls1.getMethod("printInfo", String.class, String.class);// 对象中的printInfo方法被重载,因此此处调用的是只有一个参数的printInfo方法
Method printInfoOneParam = cls1.getMethod("printInfo", String.class);

7.3 cls.getDeclaredMethods()

  • 获取本类所有的访问权限的方法(private方法也会被获取)
Method[] declaredMethods = cls1.getDeclaredMethods();

八. Method相关信息的获取

8.1 method.invoke(“类对象”, “参数”) 执行方法

⏹执行无参方法

// 从方法List中过滤出方法名为queryInfo的方法
Optional<Method> methodQueryInfo = Arrays.stream(methods).filter(method -> "queryInfo".equals(method.getName())).findAny();
if (methodQueryInfo.isPresent()) {// 获取类中的方法Method method = methodQueryInfo.get();// 👉👉👉无传参,执行该方法,并且获取到返回值Object invokeResult = method.invoke(form1);System.out.println(invokeResult);
}

⏹执行一个参数的方法

// 对象中的printInfo方法被重载,因此此处调用的是只有一个参数的printInfo方法
Method method = cls1.getMethod("printInfo", String.class);
method.invoke(form1, "贾飞天");

⏹执行多个参数的方法

// 通过指定方法名称和参数类型的方法来获取Method对象(注意: 如果方法名称不存在或参数类型不正确的话,会报错,不会返回null)
Method method = cls1.getMethod("printInfo", String.class, String.class);
method.invoke(form1, "msg1", "msg2");

8.2 Method注解

8.2.1 method.isAnnotationPresent(注解.class)

  • 判断该注解是否存在于Method上

8.2.2 method.getAnnotation(注解.class)

  • 获取方法上标记的注解
import javax.validation.constraints.NotNull;
import java.lang.reflect.Method;// 获取方法上标记的NotNull注解,从而获取注解上标记的值
NotNull methodAnnotation = printInfoTwoParamMethod.getAnnotation(NotNull.class);
System.out.println(methodAnnotation.message());

8.3 method.getReturnType()

  • 获取该方法的返回值类型
Class<?> returnType = printInfoTwoParamMethod.getReturnType();
System.out.println(returnType.getName());  // java.math.BigDecimal

8.4 method.getParameterCount()

  • 获取方法中参数的数量
int parameterCount = printInfoTwoParamMethod.getParameterCount();
System.out.println(parameterCount);  // 2

8.5 method.getParameterTypes()

  • 获取方法中参数的类型
Class<?>[] parameterTypes = printInfoTwoParamMethod.getParameterTypes();
Arrays.stream(parameterTypes).map(Class::getName).forEach(System.out::println);
// java.lang.String 
// java.lang.String

8.6 执行private方法

  • method.canAccess():判断该方法是否可访问
  • method.setAccessible(): 控制该方法是否可访问
// 获取本类所有的访问权限的方法(private方法也会被获取)
Method[] declaredMethods = cls1.getDeclaredMethods();
// 将private方法getNum从方法中过滤出来
Optional<Method> declaredMethod = Arrays.stream(declaredMethods).filter(method -> "getNum".equals(method.getName())).findAny();
if (declaredMethod.isPresent()) {// 获取到该类上的private方法Method method = declaredMethod.get();// 检查该方法是否可以访问if (!method.canAccess(form1)){// 忽略检查,使private方法可以访问method.setAccessible(true);}// 执行私有方法Object invokeResult = method.invoke(form1, 10);System.out.println("通过反射执行之后得到的值为:" + invokeResult);  // 20
}