Java反射API:Class对象、Constructor、Method与Field操作(三)

目录

一、Method对象详解

Method对象的定义与获取

Method对象的核心方法与应用

获取方法相关信息

处理重载方法

使用Method进行动态方法调用的实战案例

二、Field对象操作

Field对象的定义与获取

Field对象的重要方法与应用

使用Field实现动态字段访问与修改的示例


一、Method对象详解

Method对象的定义与获取

在Java反射API中,java.lang.reflect.Method类代表类或接口中声明的一个方法。Method对象封装了方法的完整信息,包括方法名、返回类型、参数类型、异常类型、访问修饰符等,以及用于执行方法的invoke()方法。

获取Method对象主要有以下两种方式:

通过Class对象的getMethods()方法获取:此方法返回当前类及其父类中所有public方法的Method对象数组,包括继承自Object类和接口的方法。

Class<?> clazz = SomeClass.class;
Method[] methods = clazz.getMethods();

通过Class对象的getDeclaredMethods()方法获取:此方法返回当前类中所有声明(包括private、protected、default和public)的方法的Method对象数组,但不包括父类或接口的方法。

Method[] declaredMethods = clazz.getDeclaredMethods();

Method对象的核心方法与应用

调用方法:invoke()

Method类的invoke()方法是其最核心的功能,用于在给定的对象上调用该方法,接受两个参数:一个是目标对象(对于静态方法,可以传入null),另一个是方法参数列表(可以是数组形式)。

Method method = clazz.getMethod("methodName", paramTypes...);
Object result = method.invoke(targetObject, methodArgs...);

获取/设置方法访问权限:setAccessible()

当方法为非public且需要在反射中调用时,可以使用setAccessible(true)来忽略Java语言访问检查,允许对私有、受保护、包访问权限的方法进行访问和调用。

method.setAccessible(true);

获取方法相关信息

  • 获取方法返回类型method.getReturnType() 返回Class<?>对象表示方法的返回类型。
  • 获取方法参数类型method.getParameterTypes() 返回Class<?>[]数组表示方法参数类型。
  • 获取方法异常类型method.getExceptionTypes() 返回Class<?>[]数组表示方法声明抛出的异常类型。
  • 获取方法修饰符method.getModifiers() 返回整型值表示方法的访问权限修饰符(如publicprivate等),可通过Modifier类的静态方法进行解析。

处理重载方法

当类中存在同名但参数列表不同的重载方法时,可以通过Class.getMethod(String name, Class<?>... parameterTypes)方法精确指定方法名和参数类型来获取特定的Method对象。如果不确定方法参数类型,可能需要遍历getMethods()getDeclaredMethods()返回的所有Method对象,根据方法名和参数类型进行筛选。

使用Method进行动态方法调用的实战案例

假设有一个Calculator类,包含两个重载的add方法:

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

动态调用这两个方法的示例代码如下:

public class MethodDemo {
    public static void main(String[] args) throws Exception {
        Calculator calculator = new Calculator();

        // 调用int add(int, int)
        Method addMethodInt = Calculator.class.getMethod("add", int.class, int.class);
        System.out.println(addMethodInt.invoke(calculator, 3, 5));  // 输出:8

        // 调用double add(double, double)
        Method addMethodDouble = Calculator.class.getMethod("add", double.class, double.class);
        System.out.println(addMethodDouble.invoke(calculator, 3.5, 5.5));  // 输出:9.0
    }
}

二、Field对象操作

Field对象的定义与获取

在Java反射API中,Field对象代表类或接口中声明的一个字段(成员变量)。它包含了关于字段的各种元数据,如名称、类型、访问修饰符、注解等,并提供了访问和修改字段值的方法。

获取Field对象主要有以下两种方式:

通过Class对象的getFields()方法:此方法返回一个包含当前类及其所有父类中所有公有字段(包括继承自超类的公有字段)的Field数组。这些字段无需被public修饰符标记,但必须对调用者可见。

Class<?> clazz = MyClass.class;
Field[] publicFields = clazz.getFields();

通过Class对象的getDeclaredFields()方法:此方法返回一个包含当前类所有声明的字段(不论访问修饰符)的Field数组,包括私有(private)、受保护(protected)和包访问权限(默认无修饰符)的字段,但不包括从超类继承的字段。

Field[] declaredFields = clazz.getDeclaredFields();

Field对象的重要方法与应用

访问/修改字段值:

get(Object obj):获取给定对象obj上对应Field所表示字段的值。需要传入一个实例对象,因为字段是对象的属性。

Object fieldValue = field.get(instance);

set(Object obj, Object value):设置给定对象obj上对应Field所表示字段的值为value

field.set(instance, newValue);

设置访问权限:

setAccessible(boolean accessible):允许或禁止访问私有、受保护的字段。当accessible设置为true时,即使字段原本是私有的,也可以通过反射进行访问或修改。这对于实现某些高级的元编程或框架功能非常有用,但应谨慎使用,以免破坏封装性和安全性。

field.setAccessible(true); // 允许访问私有字段

获取字段类型、修饰符、注解等信息:

getType():返回字段的Class对象,表示该字段的类型。

Class<?> fieldType = field.getType();

getModifiers():返回字段的访问修饰符位掩码,可以使用Modifier类的静态方法判断具体的修饰符(如publicprivatestaticfinal等)。

int modifiers = field.getModifiers();
boolean isPublic = Modifier.isPublic(modifiers);

getAnnotations():返回该字段上所有注解组成的数组。

Annotation[] annotations = field.getAnnotations();

getAnnotation(Class<T> annotationClass):返回该字段上指定类型的注解,如果不存在则返回null

MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);

使用Field实现动态字段访问与修改的示例

以下是一个使用Field对象动态访问和修改对象字段值的完整示例:

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class FieldExample {

    public static void main(String[] args) throws Exception {
        MyClass instance = new MyClass();

        // 获取类的Class对象
        Class<MyClass> clazz = MyClass.class;

        // 获取所有声明的字段
        Field[] fields = clazz.getDeclaredFields();

        // 遍历字段并打印相关信息
        for (Field field : fields) {
            System.out.println("Field Name: " + field.getName());
            System.out.println("Field Type: " + field.getType().getName());
            System.out.println("Modifiers: " + Modifier.toString(field.getModifiers()));

            // 设置访问权限,以便访问私有字段
            field.setAccessible(true);

            // 获取字段值
            Object fieldValue = field.get(instance);
            System.out.println("Field Value: " + fieldValue);

            // 修改字段值(假设字段为String类型)
            String newValue = "New Value";
            field.set(instance, newValue);

            // 再次获取修改后的值
            fieldValue = field.get(instance);
            System.out.println("Updated Field Value: " + fieldValue);

            System.out.println("------------------------");
        }
    }

    static class MyClass {
        private String myPrivateField = "Original Value";
        protected int myProtectedField = 123;
        public boolean myPublicField = true;
    }
}

这段代码首先获取MyClassClass对象,然后通过getDeclaredFields()方法获取所有声明的字段。接着遍历这些字段,设置它们为可访问,获取并打印字段值,修改字段值,再次获取并打印修改后的值。此示例展示了如何使用Field对象进行动态的字段访问与修改。

  • 30
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值