实例理解Java反射机制

反射(Reflect)

背景

学习过好几遍的反射了,但总是过一段又忘了,不知道该怎么使用,特此总结下来,并手撸代码加深印象,感觉这样很快就掌握了。

什么是反射?如何理解反射?

反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。

Reflection(反射)是被视为动态语言的关键(本身仍为静态语言,可以说是准动态语言),反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

图示正常方式与反射方式的区别

在这里插入图片描述

如何看待动态语言和静态语言?

动态语言

是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。

静态语言

与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++。

Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。

Java的动态性让编程的时候更加灵活!

扫描二维码关注公众号,回复: 11504384 查看本文章

反射的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时查看一个类的信息(成员变量、方法、注解、实现的接口、构造器、泛型、修饰符、继承关系、内部类等)
  • 在运行时调用任意一个对象的成员变量和方法
  • 生成动态代理

理解Class类并获取Class的实例

Class类简介

  • Class本身也是一个类
  • Class 对象只能由系统建立对象
  • 一个加载的类在JVM 中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个Class 实例所生成
  • 通过Class可以完整地得到一个类中的所有被加载的结构
  • Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象

获取Class的方式

  1. 调用某个类的class属性来获取该类对应的Class对象。例如Person.class将会返回Person类对应的Class对象
  2. 使用Class类forName()静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名(必须添加完整包名)。
  3. 调用某个对象的getClass()方法,该方法是java.lang.Object类中的一个方法,所以所有Java对象都可以调用该方法,该方法将会返回该对象所属类对应的Class对象。
  4. 使用类的加载器:ClassLoader

推荐使用第一种方式(直接调用类的class属性)获取Class对象

优势如下:

  1. 代码更安全,程序在编译阶段就可以检查需要访问的Class对象是否存在。
  2. 程序性能更高,因为这种方式无须调用方法,所以性能更好。

但如果我们只有一个字符串, 例如“java.lang. String”,如果需要获取该字符串对应的Class对象,则只能使用第二种方
式了,使用Class的forName方法获取Class对象时,该方法可能抛出一个ClasNotFoundException异常

代码测试获取Class对象

MyAnnotation注解Person接口Producer类为通用的,后续还会使用

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "Annotation测试";

}
/**
 * 测试反射的接口
 */
public interface Person {
    //吃饭
    void eat(String food);
}
/**
 * 功能描述:测试反射的JavaBean
 * 生产商类
 *
 * @author RenShiWei
 * Date: 2020/6/19 9:16
 **/
@MyAnnotation("反射获取类注解信息")
public class Producer implements Person {

    @MyAnnotation("生产商姓名")
    private String name;

    int age;

    public int id;
    
    //生产的商品map
    public Map<String,String> productMap=new HashMap<>();

    public Producer () {
    }

    private Producer ( String name, int age, int id ) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

    //get和set方法
    public String getName () {
        return name;
    }

    public void setName ( String name ) {
        this.name = name;
    }

    public int getAge () {
        return age;
    }

    public void setAge ( int age ) {
        this.age = age;
    }

    public int getId () {
        return id;
    }

    public void setId ( int id ) {
        this.id = id;
    }

    //生产产品
    @MyAnnotation
    public String produce ( String product ) {
        return "正在生产产品:" + product;
    }

    //查看产品
    void showProducts () {
        System.out.println("正在查看产品");
    }

    //实现接口的方法
    @Override
    public void eat ( String food ) {
        System.out.println("正在吃:" + food);
    }

    //内部类
    class Inner{}
    
    @Override
    public String toString () {
        return "Producer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}

测试获取Class对象

public static void main ( String[] args ) {
        System.out.println("**************测试获取Class的对象******************");
        System.out.println("----方式一:调用类的class属性获取----");
        Class<Producer> clazz1 = Producer.class;
        System.out.println(clazz1);

        System.out.println("---方式二:通过Class类的静态方法forName()获取----");
        Class<?> clazz2=null;
        try {
            clazz2 = Class.forName("reflectiontest.Producer");
            System.out.println(clazz2);
        } catch (ClassNotFoundException e) {
            System.out.println("没有通过全限类名找到此类,不能使用反射获取Class对象");
            e.printStackTrace();
        }

        System.out.println("---方式三:调用对象的getClass()方法(此方法为java.lang.Object的方法)获取---");
        Producer producer=new Producer();
        Class<? extends Producer> clazz3 = producer.getClass();
        System.out.println(clazz3);

        System.out.println("---方式四:通过类加载器ClassLoader获取---");
        ClassLoader classLoader=ReflectionTest.class.getClassLoader();
        Class<?> clazz4=null;
        try {
            clazz4 = classLoader.loadClass("reflectiontest.Producer");
            System.out.println(clazz4);
        } catch (ClassNotFoundException e) {
            System.out.println("没有通过全限类名找到此类,不能使用反射获取Class对象");
            e.printStackTrace();
        }
        System.out.println("对比四种方式获取的Class对象是否是同一个");
        System.out.println(clazz1==clazz2);
        System.out.println(clazz1==clazz3);
        System.out.println(clazz1==clazz4);
}

结果:

**************测试获取Class的对象******************
----方式一:调用类的class属性获取----
class reflectiontest.Producer
---方式二:通过Class类的静态方法forName()获取----
class reflectiontest.Producer
---方式三:调用对象的getClass()方法(此方法为java.lang.Object的方法)获取---
class reflectiontest.Producer
---方式四:通过类加载器ClassLoader获取---
class reflectiontest.Producer
对比四种方式获取的Class对象是否是同一个
true
true
true

如何从Class中获取类的信息?

获取构造器的4种方式

构造器 描述
Connstructor getConstructor(Class<?>… parameterTypes) 返回此Class对象所表示的类的指定的public构造器
Constructor<?>[] getConstructors() 返回此Class对象所表示的类的所有public 构造器。
Constructor getDeclaredConstructor(Class<?>… parameterTypes) 返回此Class对象所表示的类的指定构造器,与构造器的访问级别无关
Constructor<?>[] getDeclaredConstructors() 返回此Class对象所表示的类的所有构造器,与构造器的访问级别无关

获取方法的4种方式

方法 描述
Method getMethod(String name, Class<?>… parameterTypes) 返回此Class对象所表示的类的指定public方法
Method[] getMethods() 返回此Class对象所表示的类的所有public方法
Method getDeclaredMethod(String name, Class<?>… parameterTypes) 返回此Class对象所表示的类的指定方法,与方法的访问级别无关
Method[] getDeclaredMethods() 返回此Class对象所表示的类的全部方法,与方法的访问级别无关

获取属性的4种方式

方法 描述
Field getField(String name) 返回此Class对象所表示的类的指定的public属性( Field)
Field[] getFields() 返回此Class对象所表示的类的所有public属性(Field)
Field getDeclaredField(String name) 返回此Class对象所表示的类的指定属性( Field) ,与属性的访问级别无关。
Field] getDeclaredFields() 返回此Class对象所表示的类的全部属性(Field) ,与属性的访间级别无关

获取注释的3种方式

方法 描述
A getAnnotation(Class annotationClass) 试图获取该Class对象所表示类上.指定类型的注释;如果该类型的注释不存在则返回null
Annotation[] getAnnotations() 返回此元素上存 在的所有注释
Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注释

获取内部类:

方法 描述
Class<?>[ getDeclaredClasses() 返回该Class对象所对应类里包含的全部内部类

获取外部类

方法 描述
Class<?> getDeclaringClass() 返回该Class对象所对应类所在的外部类

获取继承的父类后者所实现的接口

方法 描述
Class<?>[] getInterfaces() 返回该Class对象对应类所实现的全部接口
int getModifiers() 返回此类或接口的所有修饰符
修饰符由public. protected、private、final、static、abstract等对应的常量组成
返回的整数应使用Modifier工具类的方法来解码,才可以获取真实的修饰符。
Package getPackage() 获取此类的包
String getName() 以字符串形式返回此Class 对象所表示的类的名称
String getSimpleName() 以字符串形式返回此Class 对象所表示的类的简称
Class<? super T> getSuperclass() 返回该Class 所表示的类的超类对应的Class对象

判断该类是否为接口、枚举、注释类型等

方法 描述
boolean isAnnotation() 返回此Class 对象是否表示一个注释类型( 由@interface定义)
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判断此Class对象,上是否使用了Annotation注释修饰
boolean isAnonymousClass() 返回此Class 对象是否是一个匿 名类
boolean isArray() 返回此Class 对象是否表示一个数组类
boolean isEnum() 返回此Class 对象是否表示一个枚举(由enum关键字定义)
boolean isInterface() 返回此Class 对象是否表示一一个接口( 使用interface定义)
boolean isInstance(Object obj) 判断obj是否是此Class对象的实例,该方法可以完全代替instanceof操作符

代码测试获取类的信息

MyAnnotation注解Person接口Producer类还采用上文的。

public static void main ( String[] args ) throws Exception {
        Class<Producer> clazz = Producer.class;
        System.out.println("************测试获取类的信息****************");
        System.out.println("---测试获取Class对象的全部构造器---");
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> c : constructors) {
            System.out.println(c);
        }

        System.out.println("---测试获取Class对象的全部为public的构造器---");
        Constructor<?>[] publicConstructors = clazz.getConstructors();
        for (Constructor<?> c : publicConstructors) {
            System.out.println(c);
        }

        System.out.println("---测试获取全部方法---");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println(m);
        }

        System.out.println("---测试获取指定的方法---");
        Method method = clazz.getMethod("produce", String.class);
        System.out.println(method);

        System.out.println("---测试获取类的全部注解---");
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation a : annotations) {
            System.out.println(a);
        }

        System.out.println("---测试获取元素的注解---\n" + Arrays.toString(clazz.getAnnotationsByType(MyAnnotation.class)));

        System.out.println("---测试获取全部的内部类---");
        Class<?>[] declaringClass = clazz.getDeclaredClasses();
        for (Class<?> inner : declaringClass) {
            System.out.println(inner);
        }

        System.out.println("---测试使用Class的forName的方法获取内部类---");
        System.out.println(Class.forName("reflectiontest.Producer$Inner"));

        //还可以获取很多信息,暂略.....
    }

结果:

************测试获取类的信息****************
---测试获取Class对象的全部构造器---
public reflectiontest.Producer()
private reflectiontest.Producer(java.lang.String,int,int)
---测试获取Class对象的全部为public的构造器---
public reflectiontest.Producer()
---测试获取全部方法---
public java.lang.String reflectiontest.Producer.getName()
public int reflectiontest.Producer.getId()
public void reflectiontest.Producer.setName(java.lang.String)
public void reflectiontest.Producer.setId(int)
public void reflectiontest.Producer.setAge(int)
public java.lang.String reflectiontest.Producer.produce(java.lang.String)
void reflectiontest.Producer.showProducts()
public int reflectiontest.Producer.getAge()
public void reflectiontest.Producer.eat(java.lang.String)
---测试获取指定的方法---
public java.lang.String reflectiontest.Producer.produce(java.lang.String)
---测试获取类的全部注解---
@reflectiontest.MyAnnotation(value=反射获取类注解信息)
---测试获取元素的注解---
[@reflectiontest.MyAnnotation(value=反射获取类注解信息)]
---测试获取全部的内部类---
class reflectiontest.Producer$Inner
---测试使用Class的forName的方法获取内部类---
class reflectiontest.Producer$Inner

反射创建并操作运行时类的对象

Class对象可以获得该类里的成分包括方法(由Method对象表示)、构造器(由Constructor 对象表示)、Field (由Field 对象表示),这三个类都定义在java.lang.reflect 包下,并实现了java.lang.reflect.Member接口。程序可以通过Method对象来执行对应的方法,通过Constructor对象来调用对应的构造器创建对象,能通过Field对象直接访问并修改对象的属性值。

创建对象

  1. 使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newlnstance()方法时实际上是利用默认构造器来创建该类的实例。
  2. 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创
    建该Class对象对应类的实例。通过这种方式可以选择使用某个类的指定构造器来创建实例。

通过第一种方式来创建对象是比较常见的情形(更加通用)。因为在很多JavaEE框架中都需要根据配置文件信息来创建Java对象,从配置文件读取的只是某个类的字符串类名,程序就需要根据该字符串来创建对应的实例,就必须使用反射。

第二种方式:

1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3)通过Constructor实例化对象。

调用方法

当获得某个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或指定方法一这两个方法的返回值是Method对象数组,或者Method对象。每个Method对象对应一个方法,获得Method对象后,程序就可通过该Method来调用对应方法。

之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。

说明:

  1. Object 对应原方法的返回值,若原方法无返回值,此时返回null
  2. 若原方法若为静态方法,此时形参Object obj可为null
  3. 若原方法形参列表为空,则Object[] args为null
  4. 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。

访问属性值

通过Class对象的getFields()或getField(方法可以获取该类所包括的全部Field(属性)或指定Field。通过Field类提供的set()和
get()方法就可以完成设置和取得属性内容的操作。

  • public Field getField(String name)返回此Class对象表示的类或接口的指定的public的Field。
  • public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。

Field提供了如下两组方法来访问属性:

  • getXxx(Object obj): 获取obj对象该Field的属性值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消get后面的Xxx。
  • setXxx(Object obj,Xxx val):将obj对象的该Field设置成val值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消set后面的Xxx。使用这两个方法可以随意地访问指定对象的所有属性,包括private访问控制的属性。

关于setAccessible方法的使用

  • Method和Field、Constructor对象都有setAccessible()方法。
  • setAccessible启动和禁用访问安全检查的开关。
  • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
    • 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
    • 使得原本无法访问的私有成员也可以访问
  • 参数值为false则指示反射的对象应该实施Java语言访问检查

代码示例

MyAnnotation注解Person接口Producer类还采用上文的。

public static void main ( String[] args ) throws Exception {
        System.out.println("*****测试创建运行时类的对象,并通过此对象调用方法和访问属性*****");
        System.out.println("---测试创建运行时类的对象---");
        //获取Class对象
        Class<Producer> clazz = Producer.class;
        //获取构造器,这里先使用默认的空参构造器(也可以使用指定的构造器)
        Constructor<Producer> constructor = clazz.getConstructor();
        //通过调用构造器的newInstance方法创建对象
        Producer producer = constructor.newInstance();
        System.out.println(producer);
        //可以通过这个对象操作数据
        System.out.println("------使用这个对象操作类的属性和方法------");
        producer.setAge(22);
        producer.showProducts();
        System.out.println(producer);

        System.out.println("---测试通过反射调用方法---");
        Method method = clazz.getDeclaredMethod("showProducts");
        method.setAccessible(true);
        //传入的是创建的运行时类的对象
        method.invoke(producer);

        System.out.println("---测试通过反射访问属性---");
        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true);
        field.set(producer,"我叫反射");
        System.out.println(field.get(producer));
        System.out.println(producer);
    }

结果:

*****测试创建运行时类的对象,并通过此对象调用方法和访问属性*****
---测试创建运行时类的对象---
Producer{name='null', age=0, id=0}
------使用这个对象操作类的属性和方法------
正在查看产品
Producer{name='null', age=22, id=0}
---测试通过反射调用方法---
正在查看产品
---测试通过反射访问属性---
Producer{name='我叫反射', age=22, id=0}
我叫反射

操作数组

在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过使用Array来动态地创建数组,操作数组元素等。

Array提供了如下几类方法:

  • static Object newlnstance(Class<?> componentT ype, int... length):创建- -个 具有指定的元素类型、指定维度的新数组。
  • static xxx getXxx(Object array, int index):返回array数组中第index个元素。其中xxx是各种基本数据类型,如果数组元素是引用类型,则该方法变为get(Object array, int index)
  • static void setXxx(Object array, int index, xXXx val):将array数组中第index元素的值设为val。其中xxx是各种基本数据类型,如果数组元素是引用类型,则该方法变成set(Object array,int index, Object val)

代码示例

public static void main ( String[] args ) {
        System.out.println("*******测试反射操作数组********");
        System.out.println("---操作一维数组---");
        //创建数组
        Object arr = Array.newInstance(String.class, 10);
        //赋值
        Array.set(arr, 2, "测试反射");
        Array.set(arr, 4, "测试反射操作数组");
        //获取指定元素的值
        System.out.println(Array.get(arr, 2));
        System.out.println(Array.get(arr, 4));
        System.out.println(Array.get(arr, 6));

        //三维数组其实是数组元素为二维数组的特殊一维数组
        System.out.println("---操作三维数组---");
        Object arr3 = Array.newInstance(String.class, 3, 4, 10);
        //
        System.out.println("------获取index为2的数组元素,应该是一个二维数组------");
        //获取arr3index为2的数组元素,应该是一个二维数组
        Object arrObj = Array.get(arr3, 2);
        //赋值
        Array.set(arrObj,2,new String[]{"反射测试1","反射测试2"});
        //获取arrObj数组的第三个元素,应该是一维数组
        Object anArr = Array.get(arrObj, 3);
        Array.set(anArr,8,"测试一维反射");
        String[][][] cast= (String[][][]) arr3;
        System.out.println(cast[2][3][8]);
        System.out.println(cast[2][2][0]);
        System.out.println(cast[2][2][1]);
    }

结果:

*******测试反射操作数组********
---操作一维数组---
测试反射
测试反射操作数组
null
---操作三维数组---
------获取index为2的数组元素,应该是一个二维数组------
测试一维反射
反射测试1
反射测试2

反射和泛型

在反射中使用泛型,可以避免使用反射的对象需要强制转换类型,从而引起异常。

对比泛型使用前后的差别

public static void main ( String[] args ) throws Exception {
        System.out.println("*******测试反射获取泛型*******");
        System.out.println("---不使用泛型的情况---");
        Person producer = (Producer) getInstance(Producer.class);

        System.out.println("---使用泛型的情况---");
        Person producer2 = getInstance2(Producer.class);

        //false,因为一个是Object类型,一个是Producer类型
        System.out.println(producer == producer2);
    }

    /**
     * 不使用泛型的情况
     */
    public static Object getInstance ( Class clazz ) throws Exception {
        return clazz.getConstructor().newInstance();
    }

    /**
     * 使用泛型的情况
     */
    public static <T> T getInstance2 ( Class<T> clazz ) throws Exception {
        return clazz.getConstructor().newInstance();
    }

结果:

*******测试反射获取泛型*******
---不使用泛型的情况---
---使用泛型的情况---
false

使用反射获取泛型信息

通过指定类对应的Class 对象,程序可以获得该类里包括的所有Ficld, 不管该Field 使用private修饰,还是使用public修饰。获得了Field对象后,就可以很容易地获得该Field的数据类型,即使用如下代码即可获得指定Field的类型:

//获取Field对象f的类型
Class<?> a = f.getType() ;

但通过这种方式只对普通类型的Field 有效。但如果该Field 的类型是有泛型限制的类型,如Map<String , Integer>类型,则不能准确得到该Field的泛型参数。

为了获得指定Field的泛型类型,应先使用如下方法来获取指定Field的泛型类型:

//获得Field实例f的泛型类型
Type gType = f.getGenericType() ;

然后将Type对象强制类型转换为ParameterizedType对象,ParameterizedType 代表被参数化的类型,也就是增加了泛型限制的类型。ParameterizedType 类提供了两个方法: .

  • getRawType(): 返回被泛型限制的类型。
  • getActualTypeArguments(): 返回泛型参数类型。

代码测试

producer类中添加代码:

//生产的商品map
public Map<String,String> productMap=new HashMap<>();

测试:

public static void main ( String[] args ) throws Exception {
		System.out.println("***使用反射获取泛型信息****");
        Class<Producer> clazz = Producer.class;
        Field f = clazz.getDeclaredField("productMap");
        Class<?> a = f.getType();
        System.out.println("获取参数类型" + a);
        Type genericType = f.getGenericType();
        System.out.println("获取泛型参数类型"+genericType);
        if (genericType instanceof ParameterizedType) {
            //将Type强转为ParameterizedType
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            //获取原始类型
            System.out.println("原始类型:" + parameterizedType.getRawType());
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for(Type t:actualTypeArguments){
                System.out.print(t+" ");
            }
        }
}

结果:

*******测试反射获取泛型*******
---不使用泛型的情况---
---使用泛型的情况---
false
***使用反射获取泛型信息****
获取参数类型interface java.util.Map
获取泛型参数类型java.util.Map<java.lang.String, java.lang.String>
原始类型:interface java.util.Map
class java.lang.String class java.lang.String

读取配置文件利用反射创建并操作运行时类的对象

新建配置文件Producer.properties

className=reflectiontest.Producer
methodName=showProducts
name=小明
public static void main ( String[] args ) throws Exception {
        //加载配置文件
        Properties properties = new Properties();
        InputStream is = ReflectionTest6.class.getClassLoader().getResourceAsStream("Producer.properties");
        assert is != null;
        //InputStreamReader将字节流转为字符流(解决乱码问题)
        InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
        properties.load(isr);

        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        String argsType = properties.getProperty("argsType");
        String name = properties.getProperty("name");

        //创建运行时类的对象
        Class<?> clazz = Class.forName(className);
        Producer producer = (Producer) clazz.newInstance();

        Method method = clazz.getDeclaredMethod(methodName);
        method.invoke(producer);
        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true);
        field.set(producer, name);
        System.out.println(producer);

        isr.close();
    }

结果:

正在查看产品
Producer{name='小明', age=0, id=0}

猜你喜欢

转载自blog.csdn.net/qq_42937522/article/details/107160959