Java-反射

本文介绍了Java反射机制的概念、作用,以及如何通过反射实现动态加载类和调用方法。详细讲解了Class类、Executable类、Constructor类、Method类、Field类和Parameter类的使用,并提供了代码示例来展示如何操作类、方法、字段和参数。同时,讨论了反射的优缺点,如性能影响和安全性问题。
摘要由CSDN通过智能技术生成


前言

为什么要学习反射?

  • 从语言的设计角度来考虑,反射使 Java 具备动态性,我们可以让程序在运行期才确定执行的结果,在不修改源码的情况下来扩展功能或者是控制程序

  • Java 是一门面向对象的语言,封装是面向对象的一个特性,它允许抽象的类把自己的数据和方法只让可信的类或者对象进行操作,对不可信的进行信息隐藏(private 修饰),而反射能够使我们去操作这些私有的变量和方法

  • 反射是 Java 的灵魂,没有反射,甚至 Spring 的那些框架也不复存在,学习反射是为了之后去读一些框架的底层源码更容易理解

比如有这里有一个需求,要求你通过读取配置文件的方式实现调用指定类的方法,你会如何去实现:

在这里插入图片描述

如果不使用反射,那么在编写代码的时候就会发现, config.properties 文件中的内容不确定的情况下,我们无法通过 new 的方式去创建具体的某一个对象,从而调用该对象的指定方法,但是通过反射就能很轻易的解决这一问题,代码如下:

public class Test {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        // 读取配置文件
        properties.load(new FileInputStream("src\\config.properties"));
        // 获取类路径
        String classpath = properties.getProperty("classpath");
        // 获取类方法
        String method = properties.getProperty("method");
        // 通过反射获取类的字节码对象
        Class<?> clazz = Class.forName(classpath);
        // 通过字节码对象获取对象实例
        Object instance = clazz.newInstance();
        // 通过类的字节码对象获取方法对象
        Method m = clazz.getMethod(method);
        // 调用方法
        m.invoke(instance);
    }
}

测试如下:

在这里插入图片描述

这样就能做到只需要改变外部的配置文件 config.properties 就能在不改变源码的情况下,去控制我们想要执行的程序,完成了解耦,同时这也符合 开闭原则

以上内容简单介绍了一下我们为什么要学习反射,并且通过一个简单的案例入门,接下来就是正文部分了。


一、概述

Java 的反射(reflection)机制 是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言关键

对于一个字节码文件 .class,它里面记录着许多的信息,Java 在将 .class 字节码文件载入时,JVM 将产生一个 java.lang.Class 对象代表 .class 字节码文件,从 Class 对象中可以获得类的完整结构信息(构造方法、成员变量、成员方法等等),这就是反射机制的核心。

反射原理图:

在这里插入图片描述

反射机制是 Java 实现动态语言的关键,也就是通过反射实现类动态加载的。

  • 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
  • 动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖

我们利用反射可以完成:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时得到任意一个类所具备的成员变量和方法
  • 在运行时调用任意一个对象的成员变量和方法
  • 生成动态代理

尽管反射机制带来了极大的灵活性,但也是有缺点的,不能滥用:

  • 性能问题:Java 反射机制中包含了一些动态类型,所以 JVM 虚拟机不能够对这些动态代码进行优化,因此反射操作的效率比正常操作效率低很多
  • 安全限制:使用反射通常需要程序的运行没有安全方面的限制,如果一个程序对安全性要求很高的话,不建议使用
  • 程序健壮性:反射会打破面向对象封装的特性,允许代码执行一些通常不允许的操作,所以可能会导致意料之外的后果

二、反射相关类

反射机制所需的类主要有 java.lang 包中的 Class 类 和 java.lang.reflect 包中的 Constructor 类、Field 类、Method 类和Parameter 类。


1. Class类

Class 类是一个比较特殊的类,它是反射机制的基础,Class 类的对象表示正在运行的 Java 程序中的类或接口,每个类被加载之后,系统都会为该类生成一个对应的 Class 对象。Class 类没有公共构造方法,其对象是 JVM 在加载类时通过调用类加载器中的 defineClass() 方法创建的,因此不能显式地创建一个 Class 对象。通过 Class 对象就可以访问到 JVM 中该类的信息,一旦类被加载到 JVM 中,同一个类将不会被再次载入。被载入 JVM 的类都有一个唯一标识就是该类的全名,即包括包名和类名。

类图:

在这里插入图片描述

在 Java 中程序获得 Class 对象有如下 5 种方式:

  1. 使用 Class 类的静态方法 forName(String className)
String className = "com.xxx.xxx.Xxx";
Class<?> clazz = Class.forName(className);
  1. 用类名调用该类的 class 属性来获得该类对应的 Class 对象,基本数据(int、long、short 等)也可以通过这种方式获取 Class 对象,即 类名.class
Class<Dog> dogClass = Dog.class;
Class<Integer> integerClass = int.class;
  1. 用对象调用 getClass() 方法来获得该类对应的 Class 对象,即对象.getClass()
Dog dog = new Dog();
Class<?> dogClass = dog.getClass();
  1. 通过类加载器获取 Class 对象
Dog dog = new Dog();
ClassLoader classLoader = dog.getClass().getClassLoader();
Class<?> aClass = classLoader.loadClass("com.xxx.xxx.Xxx");
  1. 基本数据类型对应的包装类可以通过 .TYPE 得到 Class 类对象
Class<Integer> integerClass = Integer.TYPE;

常用方法:

常用方法功能说明
public Package getPackage()返回 Class 对象所对应类的存放路径
public static Class<?> forName(String className)返回名称为 className 的类或接口的 Class 对象
public String getName()返回 Class 对象所对应类的 包.类名 形式的全名
public String getSimpleName()获取简单类名
public native Class<? super T> getSuperclass()返回 Class 对象所对应的父类的 Class 对象
public Class<?>[] getInterfaces()返回 Class 对象所对应类实现的所有接口
public Annotation[] getAnnotations()以数组的形式返回该程序元素上的所有注解
public Constructor<?>[] getConstructors()返回 Class 对象所对应类的指定参数列表的 public 构造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回 Class 对象所对应类的指定参数列表的构造方法,与访问权限无关
public Constructor<?>[] getDeclaredConstructors()返回 Class 对象所对应类的所有构造方法,与访问权限无关
public Field getField(String name)返回 Class 对象所对应类的名为 name 的 public 成员变量
public Field[] getFields()返回 Class 对象所对应类的所有 public 成员变量
public Field[] getDeclaredFields()返回 Class 对象所对应类的所有成员变量,与访问权限无关
public Method getMethod(String name, Class<?>… parameterTypes)返回 Class 对象所对应类的指定参数列表的 public 方法
public Method[] getMethods()返回 Class 对象所对应类的所有 public 成员方法
public Method[] getDeclaredMethods()返回 Class 对象所对应类的所有成员方法,与访问权限无关
public T newInstance()创建 Class 类对应的实例类对象,已过时

因为反射是建立在 Class 对象上的,所以对于类的加载还是需要了解的,这里我就不再赘述了,可以借鉴JVM-类的加载机制 这篇博客简单的认识一下。


反射机制中除了上面介绍的 java.lang 包中的 Class 类之外,还需要 java.lang.reflect 包中的 Executable 类、Field 类和Parameter 类。Executable 抽象类派生了 ConstructorMethod 两个子类。

2. Executable 类

java.lang.reflect.Executable 类提供了大量方法用来获取参数、修饰符或注解等信息,其常用方法如下表所示:

常用方法功能说明
public Parameter[] getParameters()返回所有形参存入数组 Parameter[ ] 中
public int getParameterCount()返回参数的个数
public abstract Class<?>[] getParameterTypes()按声明顺序以 Class 数组的形式返回各参数的类型
public abstract int getModifiers()返回整数表示的修饰符所对应的常量,默认修饰符(0)、public(1)、private(2)、protected(4)、static(8)、final(16)
public boolean isVarArgs()判断是否包含数量可变的参数

3. Constructor 类

java.lang.reflect.Constructor 类是 java.lang.reflect.Executable 类的直接子类,用于表示类的构造方法。通过 Class 对象的getConstructors() 方法可以获得当前运行时类的构造方法,其常用方法如下表所示:

常用方法功能说明
public String getName()返回构造方法的名字
public T newInstance(Object … initargs)使用由此 Constructor 对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例
public void setAccessible​(boolean flag)如果该构造方法的权限为 private,默认不允许通过反射 newInstance() 方法创建对象,如果先执行该方法,并将入口参数设置为 true,则允许创建
public Annotation[] getAnnotations()以数组的形式返回该程序元素上的所有注解

4. Method 类

java.lang.reflect.Method 类是 java.lang.reflect.Executable 类的直接子类,用于封装成员方法的信息,调用 Class对象的getMethod() 方法或 getMethods() 方法可以获得当前运行时类的指定方法或所有方法,其常用方法如下表所示:

常用方法功能说明
public String getName()返回方法的名称
public Class<?> getReturnType()以 Class 对象的形式返回当前方法的返回值类型
public Object invoke(Object obj, Object… args)利用给定参数列表执行指定对象 obj 中的方法
public void setAccessible​(boolean flag)启动或者禁用安全检查的开关,参数为 true 时表示取消访问检查,提高反射的效率
public int getModifiers()获取该属性对应的修饰符值:默认修饰符(0)、public(1)、private(2)、protected(4)、static(8)、final(16)
public Class<?>[] getParameterTypes()返回一个 Class 对象的数组,表示由该对象表示的可执行文件的声明顺序的形式参数类型
public Annotation[] getAnnotations()以数组的形式返回该程序元素上的所有注解
public Parameter[] getParameters()返回一个 Parameter对象的数组,表示由该对象表示的底层可执行文件的所有参数
public Type[] getGenericParameterTypes()返回一个 Type对象的数组, Type以声明顺序表示由该对象表示的可执行文件的形式参数类型
public Type getGenericReturnType()返回一个 Type对象,它表示由该表示的方法的正式返回类型 方法对象

5. Field 类

java.lang.reflect.Field 类用于封装成员变量信息,调用 Class对象的 getField() 方法或 getFields() 可以获得当前运行时类的指定成员变量或所有成员变量,其常用方法如下表所示:

常用方法功能说明
public String getName()返回成员变量的名称
public Xxx getXxx()返回成员变量的值,其中 Xxx 代表基本类型,如果成员变量是引用类型,则直接使用 get(Object obj) 方法
void setXxx(Object obj,Xxx val)设置成员变量的值,其中 Xxx 代表基本类型,如果成员变量是引用类型,则直接使用 set(Object obj,Object val) 方法
public Class<?> getType返回当前成员变量的类型
public void setAccessible​(boolean flag)启动或者禁用安全检查的开关,参数为 true 时表示取消访问检查,提高反射的效率
public int getModifiers()获取该属性对应的修饰符值:默认修饰符(0)、public(1)、private(2)、protected(4)、static(8)、final(16)
public Annotation[] getAnnotations()以数组的形式返回该程序元素上的所有注解

6. Parameter 类

java.lang.reflect.Parameter 类是参数类,每个 Parameter 对象代表方法的一个参数,该类中提供了许多方法来获取参数信息,下表给出了该类的常用方法:

常用方法功能说明
public int getModifiers()返回参数的修饰符
public String getName()返回参数的形参名
public Type getParametcrizedType()返回带泛型的形参类型
public Class <?>getType()返回形参类型
public boolean isVarArgs()判断该参数是否为可变参数
public boolean isNamePresent()判断.class文件中是否包含方法的形参名信息

三、代码示例

Describe.java

import java.lang.annotation.*;

/**
 * 自定义描述注解
 */
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER,ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Describe {
    String desc();
}

Person.java

@Describe(desc="人类")
public class Person {

    @Describe(desc="姓名")
    private String name;
    @Describe(desc="年龄")
    protected int age;
    @Describe(desc="性别")
    boolean grand;
    @Describe(desc="身高")
    public double high;

    @Describe(desc="无参构造")
    public Person() {}

    @Describe(desc="有参构造")
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    }

    @Describe(desc="走路")
    private void walk() {
        System.out.println("正在走路...");
    }

    @Describe(desc="睡觉")
    protected void sleep() {
        System.out.println("正在睡觉...");
    }

    @Describe(desc="说话")
    public void talk() {
        System.out.println("正在说话...");
    }

    @Describe(desc="吃饭")
    void eat() {
        System.out.println("正在吃饭...");
    }
}

Employee.java

import java.math.BigDecimal;

/**
 * 员工类
 */
@Describe(desc="员工类")
public class Employee extends Person {

    @Describe(desc="公司名称")
    public String companyName;
    @Describe(desc="公司地址")
    public String companyAddress;
    @Describe(desc="薪资")
    BigDecimal salary;
    @Describe(desc="职位")
    private String post;
    @Describe(desc="部门")
    protected String dept;

    @Describe(desc="无参构造")
    public Employee() {}

    @Describe(desc="有参构造")
    public Employee(String companyName,String companyAddress) {
        this.companyName = companyName;
        this.companyAddress = companyAddress;
    }

    @Describe(desc="私有有参构造")
    private Employee(String post) {
        this.post = post;
    }

    @Describe(desc="工作")
    private void work() {
        System.out.println("正在工作...");
    }

    @Describe(desc="摸鱼")
    public void touchFish() {
        System.out.println("正在摸鱼...");
    }

    @Describe(desc="加班")
    protected void extraWork() {
        System.out.println("正在加班...");
    }

    @Describe(desc="开会")
    void meeting(String withWho) {
        System.out.println("正在和"+withWho+"开会...");
    }

    @Describe(desc="上交工资")
    public String handInSalary() {
        System.out.println("上交工资...");
        return salary==null?"0":salary.toString();
    }

    @Override
    public String toString() {
        return "Employee{" +
                "companyName='" + companyName + '\'' +
                ", companyAddress='" + companyAddress + '\'' +
                ", salary=" + salary +
                ", post='" + post + '\'' +
                ", dept='" + dept + '\'' +
                '}';
    }
}

Demo.java

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.math.BigDecimal;

public class Demo {
    public static void main(String[] args) throws Exception {
        classApi();
        constructorApi();
        fieldApi();
        methodApi();
        parameterApi();
    }

    public static void classApi() throws Exception {
        // 获取 Class 对象
        Class<?> clazz = Class.forName("com.mike.reflection.Employee");
        // getPackage:获取 Class 对象所对应类的包信息
        Package aPackage = clazz.getPackage();
        System.out.println("package = " + aPackage.getName());
        // getName:返回 Class 对象所对应类的 `包.类名` 形式的全名
        String name = clazz.getName();
        System.out.println("name = " + name);
        // getSimpleName:获取简单类名
        String simpleName = clazz.getSimpleName();
        System.out.println("simpleName = " + simpleName);
        // getConstructors:获取所有 public 修饰的构造器
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("constructor = " + constructor.getName());
        }
        // getConstructor:获取指定 public 修饰的构造
        Constructor<?> appointConstructor = clazz.getConstructor();
        System.out.println("appointConstructor = " + appointConstructor.getName());
        // getDeclaredConstructors:获取本类所有的构造器
        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("declaredConstructor = " + declaredConstructor.getName());
        }
        // getFields:获取所有 public 修饰的属性,包含本类及父类的
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println("field = " + field.getName());
        }
        // getField:获取指定 public 修饰的属性
        Field appointField = clazz.getField("companyName");
        System.out.println("appointField = " + appointField.getName());
        // getDeclaredFields:获取本类所有属性
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("declaredField = " + declaredField.getName());
        }
        // getDeclaredField:获取本类指定的属性
        Field appointDeclareField = clazz.getDeclaredField("salary");
        System.out.println("appointDeclareField = " + appointDeclareField.getName());
        // getMethods:获取所有 public 修饰的方法,包含本类以及父类的
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println("method = " + method.getName());
        }
        // getMethod:获取指定 public 修饰的方法
        Method appointMethod = clazz.getMethod("talk");
        System.out.println("appointMethod = " + appointMethod.getName());
        // getDeclaredMethods:获取本类中所有的方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("declaredMethod = " + declaredMethod.getName());
        }
        // getDeclaredMethod:指定获取本类的某个方法
        Method appointDeclaredMethod = clazz.getDeclaredMethod("extraWork");
        System.out.println("appointDeclaredMethod = " + appointDeclaredMethod.getName());
        // getSuperclass:返回 Class 对象所对应的父类的 Class 对象
        Class<?> superclass = clazz.getSuperclass();
        System.out.println("superclass = " + superclass.getName());
        // getAnnotations:以数组的形式返回该程序元素上的所有注解
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("annotation = " + annotation);
        }
        // getAnnotation:获取该类上的指定注解
        Describe appointAnnotation = clazz.getAnnotation(Describe.class);
        System.out.println("annotation = " + appointAnnotation.toString());
        // getInterfaces:以 Class[] 的形式返回接口的信息
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println("anInterface = " + anInterface.getName());
        }
        // newInstance:创建 Class 类对应的实例类对象,已过时
        Object instance = clazz.newInstance();
        System.out.println("instance = " + instance);
    }

    public static void constructorApi() throws Exception {
        // 获取 Class 对象
        Class<?> clazz = Class.forName("com.mike.reflection.Employee");

        // 获取无参构造方法  -->  public Employee()
        Constructor<?> noReferenceConstructor = clazz.getConstructor();
        // 获取构造方法的名称
        String noReferenceConstructorName = noReferenceConstructor.getName();
        // 通过无参构造创建实例  ==>  Employee employee = new Employee();
        Object noReferenceInstance = noReferenceConstructor.newInstance();

        // 获取有参构造方法  -->  public Employee(String companyName,String companyAddress)
        Constructor<?> withReferenceConstructor = clazz.getConstructor(String.class, String.class);
        // 通过有参构造方法创建实例  ==>  Employee employee = new Employee("多加辣", "广州");
        Object withReferenceInstance = withReferenceConstructor.newInstance("多加辣", "广州");

        // 获取构造方法上的注解
        Annotation[] annotations = noReferenceConstructor.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("annotation = " + annotation);
        }

        // 获取私有有参构造方法  -->  private Employee(String post)
        Constructor<?> privateWRConstructor = clazz.getDeclaredConstructor(String.class);
        // 如果构造方法的访问权限是 private,是不能直接使用其构造方法的,会抛出 java.lang.IllegalAccessException
        // 需要关闭其安全检查的开关
        privateWRConstructor.setAccessible(true);
        // 通过有参构造方法创建实例  ==>  Employee employee = new Employee("项目经理");
        Object privateWRInstance = privateWRConstructor.newInstance("项目经理");

        System.out.println("privateWRInstance.toString() = " + privateWRInstance.toString());
    }

    public static void fieldApi() throws Exception {
        // 获取 Class 对象
        Class<?> clazz = Class.forName("com.mike.reflection.Employee");
        // 创建实例对象
        Object instance = clazz.newInstance();

        // 获取本类指定的属性
        Field companyNameField = clazz.getField("companyName");// public 修饰
        Field salaryFiled = clazz.getDeclaredField("salary");// 默认修饰符 修饰
        Field deptField = clazz.getDeclaredField("dept");// protected 修饰
        Field postField = clazz.getDeclaredField("post");// private 修饰
        // 获取属性的名称
        String name = deptField.getName();
        // 获取该属性对应的修饰符值:默认修饰符(0)、public(1)、private(2)、protected(4)、static(8)、final(16)
        // 如果是组合关系,则相加起来,例如:public static = 1 + 8 = 9
        int modifiers = deptField.getModifiers();
        System.out.println("modifiers = " + modifiers);
        // 获取当前成员变量的类型
        Class<?> typeClazz = deptField.getType();
        System.out.println("typeClazz = " + typeClazz.getName());
        // 获取成员变量上的注解
        Annotation[] annotations = postField.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("annotation = " + annotation);
        }

        // 设置值
        companyNameField.set(instance,"多加辣科技");
        salaryFiled.set(instance,new BigDecimal(18000));
        deptField.set(instance,"开发部");
        // 如果成员变量是 private 修饰的,则需要关闭其安全检查的开关,否则会抛出 java.lang.IllegalAccessException
        postField.setAccessible(true);
        postField.set(instance,"项目经理");
        
        // 获取属性对应的值
        Object fieldValue = postField.get(instance);
        System.out.println("fieldValue = " + fieldValue);

        System.out.println("instance.toString() = " + instance.toString());
    }

    public static void methodApi() throws Exception {
        // 获取 Class 对象
        Class<?> clazz = Class.forName("com.mike.reflection.Employee");
        // 创建实例对象
        Object instance = clazz.newInstance();

        // 获取指定 public 修饰的方法,本类及父类
        Method touchFishMethod = clazz.getMethod("touchFish");// 本类 public 修饰的方法
        Method talkMethod = clazz.getMethod("talk");// 父类 public 修饰的方法
        Method workMethod = clazz.getDeclaredMethod("work");// 本类 private 修饰的方法
        Method extraWorkMethod = clazz.getDeclaredMethod("extraWork");// 本类 protected 修饰的方法
        Method meetingMethod = clazz.getDeclaredMethod("meeting",String.class);// 本类 默认修饰符 修饰且带参的方法
        Method handInSalaryMethod = clazz.getMethod("handInSalary");// 本类 public 修饰且有返回值的方法

        // 获取方法名称
        String touchFishMethodName = touchFishMethod.getName();
        System.out.println("touchFishMethodName = " + touchFishMethodName);
        // 获取该方法对应的修饰符值:默认修饰符(0)、public(1)、private(2)、protected(4)、static(8)、final(16)
        // 如果是组合关系,则相加起来,例如:public static = 1 + 8 = 9
        int modifiers = workMethod.getModifiers();
        System.out.println("modifiers = " + modifiers);
        // 获取方法的形参类型
        Class<?>[] extraWorkParameterTypes = extraWorkMethod.getParameterTypes();
        for (Class<?> extraWorkParameterType : extraWorkParameterTypes) {
            System.out.println("extraWorkParameterType = " + extraWorkParameterType.getName());
        }
        Class<?>[] meetingParameterTypes = meetingMethod.getParameterTypes();
        for (Class<?> meetingParameterType : meetingParameterTypes) {
            System.out.println("meetingParameterType = " + meetingParameterType.getName());
        }
        // 获取方法返回对象的类对象
        Class<?> talkReturnType = talkMethod.getReturnType();
        System.out.println("talkReturnType = " + talkReturnType.getName());
        Class<?> handInSalaryReturnType = handInSalaryMethod.getReturnType();
        System.out.println("handInSalaryReturnType = " + handInSalaryReturnType);
        // 获取方法上的注解
        Annotation[] annotations = talkMethod.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("annotation = " + annotation);
        }

        // 方法调用
        // 如果方法没有返回值(void),默认返回 null
        Object touchFishInvoke = touchFishMethod.invoke(instance);
        Object talkInvoke = talkMethod.invoke(instance);
        // 如果方法是被 private 修饰,调用前需要关闭其安全检查的开关,否则会抛出 java.lang.IllegalAccessException
        workMethod.setAccessible(true);
        Object workInvoke = workMethod.invoke(instance);
        // 有形参的方法调用
        Object meetingInvoke = meetingMethod.invoke(instance, "小张");
        // 有返回值的方法调用
        Object handInSalaryInvoke = handInSalaryMethod.invoke(instance);
        System.out.println("handInSalaryInvoke = " + handInSalaryInvoke);

    }

    public static void parameterApi() throws Exception {
        // 获取 Class 对象
        Class<?> clazz = Class.forName("com.mike.reflection.Employee");
        // 创建实例对象
        Object instance = clazz.newInstance();

        // 获取本类 默认修饰符 修饰且带参的方法
        Method meetingMethod = clazz.getDeclaredMethod("meeting",String.class);

        // 获取方法的形参
        Parameter[] parameters = meetingMethod.getParameters();
        for (Parameter parameter : parameters) {
            // 获取参数名称
            String name = parameter.getName();
            System.out.println("name = " + name);
            // 获取参数的修饰符
            int modifiers = parameter.getModifiers();
            System.out.println("modifiers = " + modifiers);
            // 获取参数类型
            Class<?> parameterType = parameter.getType();
            System.out.println("parameterType = " + parameterType.getName());
            // 判断该参数是否为可变参
            boolean varArgs = parameter.isVarArgs();
            System.out.println("varArgs = " + varArgs);
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值