Java 反射机制

概述

什么是反射机制?

Java 反射机制是指 Java 程序在运行时可以动态获取类的信息、创建对象、调用以及修改对象的属性和方法的机制。Java 反射机制提供了运行时检查 Java 类型信息的能力,让 Java 程序可以通过获取本身的信息。
具体的,反射机制为我们提供了以下功能:

  1. 在运行时动态获取类的信息
  2. 在运行时动态创建对象
  3. 在运行时判断任意对象的任意属性或方法是否存在
  4. 在运行时直接访问和调用对象的任意属性和方法,包括私有的属性和方法

反射机制的优缺点

优点
  1. 因为 Java 反射机制可以在运行时获取类的信息,因此我们不需要在编译时就知道类的信息
  2. 因为 Java 反射机制可以运行时创建对象,因此我们不需要在编译时就知道对象的类型
  3. 因为可以在运行时调用对象的属性和方法,因此我们可以在运行时动态改变对象的行为

基于这些优点,利用好反射,可以大幅降低程序的耦合度。

缺点
  1. 因为反射机制是动态操作类或对象,所以它的运行效率相对较低,不如直接 new 对象、直接调用属性或方法。
  2. 因为反射机制可以直接调用对象的私有属性或方法,因此会打破 Java 的封装性,存在安全隐患。

对于反射机制带来的性能问题:

  1. 避免不必要的反射操作,特别是在性能关键代码段
  2. 如果必须频繁使用反射,可以考虑将反射的结果进行缓存,避免重复使用反射
  3. 使用成熟的反射框架,比如 Spring FrameWork

反射的应用场景

  1. 动态代理:因为无法确定需要代理的类,因此需要使用反射动态的获取。
  2. 配置文件的加载:比如 Spring 就是用了反射机制来读取和解析配置文件,从而实现 DI 和 AOP 功能的。
  3. 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();

对于包装类的 Class 对象获取方式有些特殊除了使用上述的方式获取其对应的 Class 对象外,还可以使用 TYPE 属性来获取,比如:Class<Integer> integer = Integer.TYPE
通过包装类的 TYPE 属性获取到的 Class 对象,包装类对应基本数类型的 Class 对象,只是被强转为了包装类型的 Class 对象,Integer 源码是这样的:
image.png
再点进 Class.getPrimitiveClass() 看看:
image.png

获取 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);
    }

}

image.png

获取类的信息

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. 返回的是一个 FieldField 后面说明
3. 在父类中定义的属性也可以获取到
getFields()获取类中可访问的属性对应的 Field 对象
1. 返回的是一个 Field[]Field 后面说明
2. 在父类中定义的属性也可以获取到
getDeclaredMethod()
1. String
2. Class<?>...
获取直接在类中声明、指定的方法对应的 Method 对象
1. 第一个参数:方法名称
2. 第二个参数:目标方法参数列表中各个参数的类型
3. 返回的是一个 MethodMethod 后面说明
4. 不会获取到从父类中继承的方法,除非对该方法进行重写
getDeclaredMethods()获取直接在类中声明的方法对应的 Method 对象
1. 返回的是一个 Method[]Method 后面说明
2. 不会获取到从父类中继承的方法,除非对该方法进行重写
getMethods()
1. String
2. Class<?>...
获取类中可访问的、指定的方法对应的 Method 对象
1. 参数参考 getDeclaredMethod()
2. 返回的是一个 MethodMethod 后面说明
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");
    }
}

image.png

Method

获取 Method 对象

Method 对象的获取方式已经在如何通过 Class获取类的信息中展示过了,这里汇总一下:
假设有一个 Class 对象 clazz:

  • clazz.getMethod(Class<?>... parameterTypes)
  • clazz.getMethods()
  • clazz.getDeclaredMethod(Class<?>... parameterTypes)
  • clazz.getDeclaredMethods()

对于 getMethod()getDeclareMethods() 的参数说明:

  1. 第一个参数 String name:目标方法的方法名
  2. 第二个参数 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 对象

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值