概述
什么是反射机制?
Java 反射机制是指 Java 程序在运行时可以动态获取类的信息、创建对象、调用以及修改对象的属性和方法的机制。Java 反射机制提供了运行时检查 Java 类型信息的能力,让 Java 程序可以通过获取本身的信息。
具体的,反射机制为我们提供了以下功能:
- 在运行时动态获取类的信息
- 在运行时动态创建对象
- 在运行时判断任意对象的任意属性或方法是否存在
- 在运行时直接访问和调用对象的任意属性和方法,包括私有的属性和方法
反射机制的优缺点
优点
- 因为 Java 反射机制可以在运行时获取类的信息,因此我们不需要在编译时就知道类的信息
- 因为 Java 反射机制可以运行时创建对象,因此我们不需要在编译时就知道对象的类型
- 因为可以在运行时调用对象的属性和方法,因此我们可以在运行时动态改变对象的行为
基于这些优点,利用好反射,可以大幅降低程序的耦合度。
缺点
- 因为反射机制是动态操作类或对象,所以它的运行效率相对较低,不如直接 new 对象、直接调用属性或方法。
- 因为反射机制可以直接调用对象的私有属性或方法,因此会打破 Java 的封装性,存在安全隐患。
对于反射机制带来的性能问题:
- 避免不必要的反射操作,特别是在性能关键代码段
- 如果必须频繁使用反射,可以考虑将反射的结果进行缓存,避免重复使用反射
- 使用成熟的反射框架,比如 Spring FrameWork
反射的应用场景
- 动态代理:因为无法确定需要代理的类,因此需要使用反射动态的获取。
- 配置文件的加载:比如 Spring 就是用了反射机制来读取和解析配置文件,从而实现 DI 和 AOP 功能的。
- RPC 框架:PRC 框架通过动态的生成类,然后再调用的方法。
反射机制相关 API
1、java.lang.Class(核心)
这个 API 代表了 Java 中的类(类型),包括接口、类、数组、枚举、注解等,通过 Class 对象可以获取到类的信息。
2、java.lang.reflect.Method
这个 API 代表了 Java 类中的方法,通过 Method 对象,我们可以动态的操作目标对象的任何方法。Method 对象可以通过 Class 对象获取。
一个 Method 对象对应一个类的一个方法
3、java.lang.reflect.Filed
这个 API 代表了 Java 类中的属性,通过 Field 对象,我们可以动态的操作目标对象的任何属性。Method 对象可以通过 Class 对象获取。
一个 Field 对象对应一个类的一个属性
4、java.lang.reflect.Constructor
这个 API 代表了 Java 类中的构造器,通过 Constructor 对象,我们可以动态创建对象。Constructor 对象可以通过 Class 对象获取。
一个 Constructor 对象对应一个类的一个构造器
使用反射机制
Class
获取 Class 对象
使用反射机制,我们首先要获取到 Class 对象。Class 对象可以通过四种方式获取:
- 类.class
Class<String> strClass = String.class;
- 推荐使用
- Class.forName(“全限定目标类名”)
Class<?> strClass = Class.forName("java.lang.String");
- 对象.getClass()
- 先创建一个 String 对象
String s = "Hello";
然后获取 String 类对应的 Class 对象Class<? extends String> strClass = s.getClass();
- 先创建一个 String 对象
对于包装类的 Class 对象获取方式有些特殊除了使用上述的方式获取其对应的 Class 对象外,还可以使用 TYPE
属性来获取,比如:Class<Integer> integer = Integer.TYPE
。
通过包装类的 TYPE
属性获取到的 Class
对象,包装类对应基本数类型的 Class 对象,只是被强转为了包装类型的 Class 对象,Integer 源码是这样的:
再点进 Class.getPrimitiveClass() 看看:
获取 Class 对象示例代码
/**
* 获取 Class 对象得方式
*/
public class GetClassDemo {
public static void main(String[] args) {
// 方式 1
Class<String> strClass1 = String.class;
System.out.println("strClass1 ==> " + strClass1);
try {
// 方式 2
Class<?> strClass2 = Class.forName("java.lang.String");
System.out.println("strClass2 ==> " + strClass2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 方式 3
String s = "Hello";
Class<? extends String> strClass3 = s.getClass();
System.out.println("strClass3 ==> " + strClass3);
System.out.println("==========================");
// 对于包装类
Class<Integer> integerClass1 = Integer.class;
System.out.println("integerClass1 ==> " + integerClass1);
try {
Class<?> integerClass2 = Class.forName("java.lang.Integer");
System.out.println("integerClass2 ==> " + integerClass2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Integer i = 1;
Class<? extends Integer> integerClass3 = i.getClass();
System.out.println("integerClass3 ==> " + integerClass3);
Class<Integer> integerClass4 = Integer.TYPE;
System.out.println("integerClass4 ==> " + integerClass4);
}
}
获取类的信息
Class 常用方法
有了 Class
对象之后,我们就可以获取类的信息了。在此之前先看看 Class
都为我们提供了哪些操作类的方法:
方法 | 参数 | 作用 | 说明 |
---|---|---|---|
getName() | 无 | 获取类名的全限定名称, 比如: java.lang.String | |
getModifiers() | 无 | 获取类的修饰符列表的信息 | 1. 返回的是一个 int 数据2. 通常和 Modifier.toString() 一起使用 |
getSuperclass() | 无 | 获取父类对应的 Class 对象 | |
getInterfaces() | 无 | 获取实现的接口的 Class 对象 | 返回的是 Class[] 对象,每个元素对应一个接口 |
isAnnotationPresent() | Class<? extends Annotation> | 判断类是否被某个注解标注 | 1. 参数是指定注解对应的 Class 对象 2. 这个方法在对自定义注解的处理上会很有用 |
getDeclaredField() | String | 获取被指定的、直接在当前类中声明的属性对应的 Field 对象 | 1. 参数是对应属性的名称 2. 返回一个 Field 对象3. 不会获取到从父类中继承的属性,除非在该类中有显示的重新声明 |
getDeclaredFields() | 无 | 获取直接在当前类中声明的属性对应的 Field 对象 | 1. 返回的是一个 Field[] ,Field 后面说明2. 不会获取到从父类中继承的属性,除非在该类中有显示的重新声明 |
getField() | String | 获取类中被指定的、可访问的属性对应的 Field 对象 | 1. 参数是对应属性的名称 2. 返回的是一个 Field ,Field 后面说明3. 在父类中定义的属性也可以获取到 |
getFields() | 无 | 获取类中可访问的属性对应的 Field 对象 | 1. 返回的是一个 Field[] ,Field 后面说明2. 在父类中定义的属性也可以获取到 |
getDeclaredMethod() | 1. String 2. Class<?>... | 获取直接在类中声明、指定的方法对应的 Method 对象 | 1. 第一个参数:方法名称 2. 第二个参数:目标方法参数列表中各个参数的类型 3. 返回的是一个 Method ,Method 后面说明4. 不会获取到从父类中继承的方法,除非对该方法进行重写 |
getDeclaredMethods() | 无 | 获取直接在类中声明的方法对应的 Method 对象 | 1. 返回的是一个 Method[] ,Method 后面说明2. 不会获取到从父类中继承的方法,除非对该方法进行重写 |
getMethods() | 1. String 2. Class<?>... | 获取类中可访问的、指定的方法对应的 Method 对象 | 1. 参数参考 getDeclaredMethod() 2. 返回的是一个 Method ,Method 后面说明3. 在父类中定义的方法也可以获取到 |
getMethods() | 无 | 获取类中可访问的方法对应的 Method 对象 | 1. 返回的是一个 Method[] ,Method 后面说明2. 在父类中定义的方法也可以获取到 |
getDeclaredConstructor() | Class<?>... | 获取类的对应的构造器对应的 Constructor 对象 | 不传参数,获取的是无参构造器 |
getDeclaredConstructors() | 无 | 获取类的所有的构造器对应的 Constructor 对象 | 返回的是一个 Constructor[] ,Constructor 后面说明 |
getConstructors() | Class<?>... | 获取类的对应的、可访问的构造器对应的 Constructor 对象 | 不传参数,获取的是无参构造器 |
getConstructors() | 无 | 获取类的可访问的构造器对应的 Constructor 对象 | 返回的是一个 Constructor[] ,Constructor 后面说明 |
示例代码
自定义 3 个注解
@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EmptyAnnotation {}
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EmptyAnnotation2 {}
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EmptyAnnotation3 {}
在 Team.java 中定义用于反射的目标类
@EmptyAnnotation
public final class Temp extends Empty implements Once {
@EmptyAnnotation2
public int field1 = 10;
private final int field2 = 20;
public String field3 = "Hello";
private static final String FIELD4 = "World";
private List<String> field5;
public Temp() {
}
private Temp(List<String> list) {
field5 = list;
}
public final void method1() {
System.out.println("method1 被调用");
}
public static int method2() {
System.out.println("method2 被调用");
return 1;
}
private String method3() {
System.out.println("method3 被调用");
return "Hello";
}
@EmptyAnnotation3
public String method4(String name, Integer age) {
System.out.println("name = " + name + " age = " + age);
return "I am method5";
}
@Override
public String toString() {
return "Temp{" +
"field1=" + field1 +
", field2=" + field2 +
", field3='" + field3 + '\'' +
", field5=" + field5 +
'}';
}
}
interface Once{}
class Empty{
private void x() {}
}
在 TempClassDemo.java 中编写具体反射代码,使用前面列出的方法,查看效果
/**
* 使用 Class 操作类
*/
public class TempClassDemo {
public static void main(String[] args) {
getInfo();
}
/**
* 获取类的信息
*/
public static void getInfo() {
Class<Temp> tempClass = Temp.class; // 获取 Temp 类的 Class 对象
System.out.println("================= 获取类名称 =================");
String name = tempClass.getName();
System.out.println("类名 ==> " + name);
System.out.println("============================================\n");
System.out.println("============= 获取修饰符相关信息 ==============");
int modifiers = tempClass.getModifiers();
String modifiersStr = Modifier.toString(modifiers);
String result = String.format("修饰符 id: %d, 修饰符名称: %s", modifiers, modifiersStr);
System.out.println(result);
System.out.println("============================================\n");
System.out.println("=============== 获取继承的父类 ===============");
Class<? super Temp> superclass = tempClass.getSuperclass();
System.out.println("父类 ==> " + superclass.getName());
System.out.println("============================================\n");
System.out.println("=============== 获取实现的接口 ===============");
Class<?>[] interfaces = tempClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println("接口 ==> " + anInterface.getName());
}
System.out.println("============================================\n");
System.out.println("============== 判断是否有指定注解 ==============");
boolean annotationPresent = tempClass.isAnnotationPresent(EmptyAnnotation.class);
boolean annotationPresent2 = tempClass.isAnnotationPresent(EmptyAnnotation2.class);
System.out.println("hasOverrideAnnotation: " + annotationPresent);
System.out.println("annotationPresent: " + annotationPresent2);
System.out.println("============================================\n");
System.out.println("=============== 获取类的所有属性 ==============");
Field[] declaredFields = tempClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("属性 ==> " + declaredField.getName());
}
System.out.println("============================================\n");
System.out.println("============== 获取类的可访问属性 ==============");
Field[] fields = tempClass.getFields();
for (Field field : fields) {
System.out.println("属性 ==> " + field.getName());
}
System.out.println("=============================================\n");
System.out.println("=============== 获取类的所有方法 ==============");
Method[] declaredMethods = tempClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("方法 ==> " + declaredMethod.getName());
}
System.out.println("=============================================\n");
System.out.println("============== 获取类的可访问方法 ==============");
Method[] methods = tempClass.getMethods();
for (Method method : methods) {
System.out.println("方法 ==> " + method.getName());
}
System.out.println("=============================================\n");
System.out.println("============== 获取类的所有构造器 ==============");
Constructor<?>[] declaredConstructors = tempClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("构造器 ==> " + declaredConstructor.getName());
}
System.out.println("=============================================\n");
System.out.println("============== 获取类的可访问构造器 ==============");
Constructor<?>[] constructors = tempClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("构造器 ==> " + constructor.getName());
}
System.out.println("=============================================\n");
System.out.println("================= 反射机制创建对象 =================");
try {
Temp temp = tempClass.newInstance();
System.out.println(temp.field1);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("=================================================");
}
}
打印信息:
================= 获取类名称 =================
类名 ==> com.guyi.capricerecord.once.Temp
============================================
============= 获取修饰符相关信息 ==============
修饰符 id: 17, 修饰符名称: public final
============================================
=============== 获取继承的父类 ===============
父类 ==> com.guyi.capricerecord.once.Empty
============================================
=============== 获取实现的接口 ===============
接口 ==> com.guyi.capricerecord.once.Once
============================================
============== 判断是否有指定注解 ==============
hasOverrideAnnotation: true
annotationPresent: false
============================================
=============== 获取类的所有属性 ==============
属性 ==> field1
属性 ==> field2
属性 ==> field3
属性 ==> FIELD4
属性 ==> field5
============================================
============== 获取类的可访问属性 ==============
属性 ==> field1
属性 ==> field3
=============================================
=============== 获取类的所有方法 ==============
方法 ==> toString
方法 ==> method3
方法 ==> method2
方法 ==> method4
方法 ==> method1
=============================================
============== 获取类的可访问方法 ==============
方法 ==> toString
方法 ==> method2
方法 ==> method4
方法 ==> method1
方法 ==> wait
方法 ==> wait
方法 ==> wait
方法 ==> equals
方法 ==> hashCode
方法 ==> getClass
方法 ==> notify
方法 ==> notifyAll
=============================================
============== 获取类的所有构造器 ==============
构造器 ==> com.guyi.capricerecord.once.Temp
构造器 ==> com.guyi.capricerecord.once.Temp
=============================================
============== 获取类的可访问构造器 ==============
构造器 ==> com.guyi.capricerecord.once.Temp
=============================================
================= 反射机制创建对象 =================
10
=================================================
进程已结束,退出代码为 0
通过反射机制创建对象
我们可以直接通过 Class 对象的 newInstance()
方法来调用对应 class 的无参构造器来实例化一个对象,无论这个无参构造器被什么访问修饰修饰,都可以被调用。
由于这个方法已经被弃用,这里不做说明。
Field
获取 Filed 对象
Field
对象的获取方式已经在如何通过 Class
获取类的信息中展示了两种,这里汇总并作补充:
假设有一个 Class
对象 clazz
:
clazz.getField(String name)
- 如果目标类中不存在
name
属性,或者这个属性是不允许被访问的,那么会抛NoSuchFieldException
异常。
- 如果目标类中不存在
clazz.getFields()
clazz.getDeclaredField(String name)
- 如果目标类中不存在
name
属性,那么会抛NoSuchFieldException
异常。
- 如果目标类中不存在
clazz.getDeclaredFields()
使用 Field 对象
Field 常用方法
我们还是先看看 Field
为我们提供了哪些方法用来操作属性:
方法 | 参数 | 作用 | 说明 |
---|---|---|---|
getName() | 无 | 获取属性名称 | |
getModifiers() | 无 | 获取属性的修饰符列表的信息 | 1. 返回的是一个 int 数据2. 通常和 Modifier.toString() 一起使用 |
getType() | 无 | 获取属性的数据类型 | |
isAnnotationPresent() | Class<? extends Annotation> | 判断属性是否被某个注解标注 | 1. 参数是指定注解对应的 Class 对象 2. 这个方法在对自定义注解的处理上会很有用 |
get() | Object obj | 获取指定对象对应的属性的值 | 返回的是 Object 对象,使用时需要注意类型转换 |
set() | Object obj Object value | 给 obj 对象的对应属性赋值 |
对于获取属性值,Field 还提供了其他的方法,比如:
- getInt(Object obj)
- getLong(Object obj)
- getBoolean(Object obj)
- …
这些方法可以返回值都是基本数据。
类似的,对于设置属性值,Field 也提供了单独对基本数据类型的属性赋值的方法:
- setInt(Object obj, int i)
- setLong(Object obj, long l)
- …
这些方法实际会将传入的数据装箱为包装类。
示例代码
以 getField()
为例
/**
* 使用 Field 操作类的属性
*/
public class TempFieldDemo {
public static void main(String[] args) {
Class<Temp> tempClass = Temp.class;
Field field = null;
try {
field = tempClass.getField("field1");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
System.out.println("================= 获取属性名称 =================");
System.out.println("方法名 ==> " + field.getName());
System.out.println("==============================================\n");
System.out.println("================= 获取属性修饰符 =================");
int modifiersNum = field.getModifiers();
String modifiersStr = Modifier.toString(modifiersNum);
String result = String.format("修饰符 id: %d, 修饰符名称: %s", modifiersNum, modifiersStr);
System.out.println(result);
System.out.println("===============================================\n");
System.out.println("================= 获取属性类型 =================");
Class<?> type = field.getType();
System.out.println("属性类型 ==> " + type.getName());
System.out.println("==============================================\n");
System.out.println("================= 判断属性是否被某个注解标注 =================");
boolean hasAnnotationPresent = field.isAnnotationPresent(EmptyAnnotation2.class);
System.out.println("该属性被 AnnotationPresent 标注 ==> " + hasAnnotationPresent);
boolean hasEmptyAnnotation = field.isAnnotationPresent(EmptyAnnotation.class);
System.out.println("该属性被 hasEmptyAnnotation 标注 ==> " + hasEmptyAnnotation);
System.out.println("=========================================================\n");
// 实例化一个 Temp 对象
Temp temp = new Temp();
System.out.println("================= 获取属性值 =================");
try {
Object o = field.get(temp);
Integer o1 = (Integer) o;
System.out.println("temp.field1 = " + o1);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("============================================\n");
System.out.println("================= 设置属性值 =================");
try {
System.out.println("【使用反射赋值前】temp.field = " + temp.field1);
field.set(temp, 100);
System.out.println("【使用反射赋值后】temp.field = " + temp.field1);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("============================================\n");
}
}
打印信息
================= 获取属性名称 =================
方法名 ==> field1
==============================================
================= 获取属性修饰符 =================
修饰符 id: 1, 修饰符名称: public
===============================================
================= 获取属性类型 =================
属性类型 ==> int
==============================================
================= 判断属性是否被某个注解标注 =================
该属性被 AnnotationPresent 标注 ==> true
该属性被 hasEmptyAnnotation 标注 ==> false
=========================================================
================= 获取属性值 =================
temp.field1 = 10
============================================
================= 设置属性值 =================
【使用反射赋值前】temp.field = 10
【使用反射赋值后】temp.field = 100
============================================
进程已结束,退出代码为 0
用 getDeclaredField()
打破封装,无视 final
关键字
package com.guyi.capricerecord.reflection;
import com.guyi.capricerecord.once.EmptyAnnotation;
import com.guyi.capricerecord.once.EmptyAnnotation2;
import com.guyi.capricerecord.once.Temp;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 使用 Field 操作类的属性
*/
public class TempFieldDemo {
public static void main(String[] args) {
Class<Temp> tempClass = Temp.class;
Field field = null;
// 实例化一个 Temp 对象
Temp temp = new Temp();
System.out.println("================= 打破封装, 无视 final =================");
try {
field = tempClass.getDeclaredField("field2");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
int modifiers = field.getModifiers();
System.out.println("team.field2 的修饰符: " + Modifier.toString(modifiers));
// 操作访问受限的属性
field.setAccessible(true);
try {
System.out.println("访问到私有属性 ==> temp.field2 = " + field.get(temp));
field.set(temp, 100);
System.out.println("无视 final ==> temp.field2 = " + field.get(temp));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("======================================================\n");
}
}
Method
获取 Method 对象
Method
对象的获取方式已经在如何通过 Class
获取类的信息中展示过了,这里汇总一下:
假设有一个 Class
对象 clazz
:
clazz.getMethod(Class<?>... parameterTypes)
clazz.getMethods()
clazz.getDeclaredMethod(Class<?>... parameterTypes)
clazz.getDeclaredMethods()
对于 getMethod()
和 getDeclareMethods()
的参数说明:
- 第一个参数
String name
:目标方法的方法名 - 第二个参数
Class<?>... parameterTypes
:是一个不定长参数,传入的值是目标方法参数列表中各个参数的类型
使用 Method 对象
常用方法
我们还是先看看 Method
为我们提供了哪些方法来操作其他类或对象的方法
方法 | 参数 | 作用 | 说明 |
---|---|---|---|
getName() | 无 | 获取方法名称 | |
getModifiers() | 无 | 获取方法的修饰符列表信息 | 1. 返回的是一个 int 数据2. 通常和 Modifier.toString() 一起使用 |
getParameterTypes() | 无 | 获取各个参数的类型列表 | |
getReturnType() | 无 | 获取方法返回值类型 | |
isAnnotationPresent() | Class<? extends Annotation> | 判断方法是否被某个注解标注 | 1. 参数是指定注解对应的 Class 对象 2. 这个方法在对自定义注解的处理上会很有用 |
getAnnotation() | Class<? extends Annotation> | 获取方法上指定的注解对应的类型 | 1. 如果方法上有指定的注解,那么会返回指定注解的类型,否则返回空 2. 可以利用这个方法的返回值是否为 null 判断方法上是否有某个注解 |
invoke() | 1. Object obj 2. Object... args | 调用 obj 对象的目标方法 | 1. 个人认为, 这个是 Method 最重要的方法2. 第一个参数:目标对象,即你调用的是这个对象的目标方法 3. 第二个参数:是一个不定长参数,是被反射机制传给目标方法的参数值 |
示例代码
/**
* 使用 Method 操作类的方法
*/
public class TempMethodDemo {
public static void main(String[] args) {
Class<Temp> tempClass = Temp.class;
Method method = null;
try {
// 获取 Method 对象
method = tempClass.getMethod("method4", String.class, Integer.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.println("================= 获取方法名称 =================");
String name = method.getName();
System.out.println("方法名称 ==> " + name);
System.out.println("==============================================\n");
System.out.println("================= 获取方法的修饰符列表 =================");
int modifiers = method.getModifiers();
String modifierListName = Modifier.toString(modifiers);
System.out.println("方法 " + name + " 的修饰符 id: " + modifiers + " 修饰符列表: " + modifierListName);
System.out.println("====================================================\n");
System.out.println("================= 获取形参列表 =================");
Class<?>[] parameterTypes = method.getParameterTypes();
int length = parameterTypes.length;
for (int i = 0; i < length; i++) {
System.out.println("第 " + i + " 参数的类型是: " + parameterTypes[i].getTypeName());
}
System.out.println("==============================================\n");
System.out.println("================= 获取方法的返回值类型 =================");
Class<?> returnType = method.getReturnType();
System.out.println("方法 " + name + " 的返回值类型: " + returnType.getTypeName());
System.out.println("====================================================\n");
System.out.println("================= 判断方法上是否有某个注解 =================");
boolean hasEm3 = method.isAnnotationPresent(EmptyAnnotation3.class);
System.out.println("方法 method3 是否有 EmptyAnnotation3: " + hasEm3);
boolean hasEm2 = method.isAnnotationPresent(EmptyAnnotation2.class);
System.out.println("方法 method3 是否有 EmptyAnnotation2: " + hasEm2);
// 也可以通过 getAnnotation() 方法的返回值来判断, 这里简单演示
if (method.getAnnotation(EmptyAnnotation3.class) == null) {
System.out.println("方法 method3 上没有 EmptyAnnotation3 注解");
} else {
System.out.println("方法 method3 上有 EmptyAnnotation3 注解");
}
System.out.println("=======================================================\n");
System.out.println("================= 获取方法上的注解 =================");
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("method4 上有: " + annotation.annotationType());
}
System.out.println("=================================================\n");
System.out.println("================= 调用方法 =================");
Temp temp = new Temp();
try {
Object invokeResult = method.invoke(temp, "张三", 20);
System.out.println("通过反射调用 method4 方法的结果: " + invokeResult);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("==========================================\n");
}
}
打印信息
================= 获取方法名称 =================
方法名称 ==> method4
==============================================
================= 获取方法的修饰符列表 =================
方法 method4 的修饰符 id: 1 修饰符列表: public
====================================================
================= 获取形参列表 =================
第 0 参数的类型是: java.lang.String
第 1 参数的类型是: java.lang.Integer
==============================================
================= 获取方法的返回值类型 =================
方法 method4 的返回值类型: java.lang.String
====================================================
================= 判断方法上是否有某个注解 =================
方法 method3 是否有 EmptyAnnotation3: true
方法 method3 是否有 EmptyAnnotation2: false
方法 method3 上有 EmptyAnnotation3 注解
=======================================================
================= 获取方法上的注解 =================
method4 上有: interface com.guyi.capricerecord.once.EmptyAnnotation3
=================================================
================= 调用方法 =================
name = 张三 age = 20
通过反射调用 method4 方法的结果: I am method5
==========================================
进程已结束,退出代码为 0
Constructor
获取 Constructor 对象
这里将获取 Constructor
进行汇总,假设有一个 Class
对象 clazz
:
clazz.getConstructors()
clazz.getConstructor(Class<?>... parameterTypes)
clazz.getDeclaredConstructors()
clazz.getDeclaredConstructor(Class<?>... parameterTypes)
对于 getConstructor()
和 getDeclaredConstructor()
的参数说明:
- 是一个不定长参数
- 传入的值是目标构造器参数列表中各个参数的类型
使用 Constructor 对象
对于 Constructor
,我认为只需要知道可以利用 newInstance()
方法来创建目标对象即可。
示例代码:
/**
* Constructor 的使用
*/
public class TempConstructorDemo {
public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Temp> tempClass = Temp.class;
Constructor<Temp> constructor = null;
try {
constructor = tempClass.getDeclaredConstructor(List.class);
constructor.setAccessible(true); // 打破封装
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 利用反射机制实例化对象
Temp temp = constructor.newInstance(new ArrayList<String>());
System.out.println(temp.field1);
}
}
总结
下面出现的 “反射 API 对象” 指:
- Field 对象
- Method 对象
- Constructor 对象