Java 反射常用方法
参考资料
- Java反射系列–方法大全
- Java反射(通俗易懂)
- 【小家java】Java反射机制中Class.getXXX()和Class.getDeclaredXXX()的使用区别和注意事项
- 【小家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()
- 获取本类(不包含父类)的所有修饰符的属性,包括
private
和protected
。
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
}