反射调用方法 | 带你学《Java语言高级特性》之八十六

简介: 本节通过之前的案例介绍了反射调用构造方法和普通方法,实现反射实例化对象,并通过反射来获取类之中的全部方法。

上一篇:反射获取类结构信息 | 带你学《Java语言高级特性》之八十五
【本节目标】
本节通过之前的案例介绍了反射调用构造方法和普通方法,实现反射实例化对象,并通过反射来获取类之中的全部方法。

反射调用构造方法

在一个类中除了有继承的关系外,最为重要的操作就是类中的结构处理了,而类中的结构首先需要观察的就是构造方法的使用问题,实际上在之前通过反射实例化对象的时候就已经接触到构造方法的问题了:
实例化方法替代:clazz.getDeclaredConstructor().newInstance()
所有类的构造方法的获取都可以直接通过Class类来完成,该类中定义有如下的几个方法:
获取所有构造方法:
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
获取指定构造方法:
public Constructor<T> getConstructor​() throws SecurityException
获取所有构造方法:
public Constructor<?>[] getConstructors()throws SecurityException
获取指定构造方法:
public Constructor<T> getConstructor​(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

范例:修改Person类的定义
AbstractBase:

public abstract class AbstractBase {
    public AbstractBase() {}
    public AbstractBase(String msg) {}
}

Person:

public class Person extends AbstractBase implements  IChannelService,IMessageService {
    public Person() {}
    public Person(String name, int age) {
}

范例:获取构造
JavaAPIDemo

public class JavaAPIDemo {
    public static void main(String[] args) {
        Class<?> cls = Person.class;//获取指定类的Class对象
        Constructor<?>[] constructors = cls.getDeclaredConstructors();  //获取全部构造
        for (Constructor<?> cons : constructors) {
            System.out.println(cons);
        }
    }
}

//执行结果:public cn.mldn.vo.Person()
//public cn.mldn.vo.Person(java.lang.String,int)

此时获取的是类中的全部构造方法,但是也可以获取一个指定参数的构造。例如:现在的Person类之中有两个构造方法:
修改Person:

public class Person extends AbstractBase implements  IChannelService,IMessageService {
    private String name;
    private int age;
    public Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "姓名:" + this.name + "、年龄:" + this.age;
    }
}

此时调用Person类中的有参构造方法进行Person类对象实例化,此时必须指明要调用的构造,而后通过Constructor类中提供的实例化方法操作:
public T newInstance​(Object... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException

范例:调用指定构造实例化对象

import java.lang.reflect.Constructor;

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Person.class;
        Constructor<?> constructor = cls.getConstructor(String.class, int.class);
        Object obj = constructor.newInstance("小强", 78);
        System.out.println(obj);  //姓名:小强、年龄:78
    }
}

虽然程序代码本身允许开发者调用有参构造,但是如果从实际的开发角度出发,所有使用反射的类中最好使用无参构造,因为这样的实例化可以达到统一性。

反射调用普通方法

在进行反射处理的时候也可以通过反射来获取类之中的全部方法,但是需要提醒的是,如果想通过反射调用这些方法,必须有一个前提条件:类之中要提供实例化对象。
在Class类中提供了如下的操作可以获取方法对象:

获取全部方法:
public Method[] getMethods() throws SecurityException
获取指定方法:
public Method getMethod​(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
获取本类全部方法:
public Method[] getDeclaredMethods() throws SecurityException
获取本类指定方法:
public Method getDeclaredMethod​(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
范例:获取全部方法

import java.lang.reflect.Method;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Person.class;
        {
            Method methods [] = cls.getMethods();//获取全部方法(包括父类中的方法)
            for (Method met : methods){
                System.out.println(met);
            }
        }
        System.out.println("---------------难以忘怀的愚人节的分割线-----------")
        {  // 获取本类方法
            Method methods [] = cls.getDeclaredMethods();
            for (Method met : methods){
                System.out.println(met);
        }

        }
    }

执行结果:
image.png
但是需要注意的是,这时的方法信息的获取是依靠Method类提供的toString()方法完成的,很多时候也可以由用户来拼凑方法信息的展示形式。
范例:自定义方法信息显示

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Person.class;  // 获取指定类的Class对象
        Method methods[] = cls.getMethods();
        for (Method met:methods){
            int mod=met.getModifiers();//修饰符
            System.out.print(Modifier.toString(mod)+" ");
            System.out.print(met.getReturnType().getName()+" ");
            System.out.print(met.getName()+"(");
            Class<?> params [] = met.getParameterTypes();//获取参数类型
            for (int x = 0; x < params.length; x ++) {
                System.out.print(params[x].getName() + " " + "arg-" + x);
                if(x < params.length - 1) {
                    System.out.println(",");
                }
            }
            System.out.print(")");
            class<?> exp [] = met.getExceptionTypes();
            if(exp.length > 0) {
                System.out.print("throws");
            }
            for(int x = 0 ; x < exp.length ; x ++) {
                System.out.print(exp[x].getName());
                if(x < exp.length - 1) {
                    System.out.println(",");
                }
            }
            System.out.println();  //换行
        }
    }
}

这种代码只需要清楚可以根据反射获取方法的结构即可,不需要过多深入了解,但在Method类中有一个致命的重要方法:
public Object invoke​(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException

在Person类里面为name属性追加有setter、getter方法。

public class Person extends AbstractBase implements  IChannelService,IMessageService {
    private String name;
    private int age;
    public Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    // 其他操作代码略
}

需要通过反射机制来实现Person类之中的setter与getter方法的调用处理。
范例:在不导入指定类开发包的情况下实现属性的配置

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("cn.mladn.vo.Person"); //获取指定类的Class对象
        // String attribute = "name"; //要操作的类属性
        String value = "小强子";  //要设置的属性内容
        //1.任何情况下如果要想保存类中的属性或者调用类中的方法都必须保证存在有实例化对象,既然不允许导入包,那么就反射实例化
        Object obj = cls.getDeclaredConstructor().newInstance();  //调用无参构造实例化
        //2.如果要想进行方法的调用,那么一定要获取方法的名称
        String setMethodName = "setName";  //方法名称 
        Method method = cls.getDeclaredMethodsetMethodName, String.class);   //获取指定的方法
        method.invoke(obj, value);  //等价于:Person对象.setName(value);
        String getMethodName="getName";
        method=cls.getDeclaredMethod(getMethodName);   //getter没有参数
        System.out.println(getMethod.invoke(obj););  //等价于:Person对象.getName();
    } 
}

利用此类操作整体的形式上不会有任何明确的类对象产生,一切都是依靠反射机制处理的,这样的处理避免了与某一个类耦合问题。

想学习更多的Java的课程吗?从小白到大神,从入门到精通,更多精彩不容错过!免费为您提供更多的学习资源。
本内容视频来源于阿里云大学

下一篇:反射调用成员 | 带你学《Java语言高级特性》之八十七
更多Java面向对象编程文章查看此处

相关文章
|
8月前
|
JSON Java API
【干货满满】分享京东API接口到手价,用Java语言实现
本示例使用 Java 调用京东开放平台商品价格及优惠信息 API,通过商品详情和促销接口获取到手价(含优惠券、满减等),包含签名生成、HTTP 请求及响应解析逻辑,适用于比价工具、电商系统集成等场景。
|
6月前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
412 18
|
6月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
242 4
|
6月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
286 4
|
7月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
222 11
|
6月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
384 5
|
7月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
7月前
|
存储 Java Apache
Java语言操作INI配置文件策略
以上步骤展示了基本策略,在实际项目中可能需要根据具体需求进行调整优化。例如,在多线程环境中操作同一份配置时需要考虑线程安全问题;大型项目可能还需考虑性能问题等等。
290 15
|
8月前
|
算法 Java
Java语言实现链表反转的方法
这种反转方法不需要使用额外的存储空间,因此空间复杂度为,它只需要遍历一次链表,所以时间复杂度为,其中为链表的长度。这使得这种反转链表的方法既高效又实用。
604 0
|
8月前
|
JSON Java API
【干货满满】分享拼多多API接口到手价,用Java语言实现
本方案基于 Java 实现调用拼多多开放平台商品详情 API,通过联盟接口获取商品到手价(含拼团折扣与优惠券),包含签名生成、HTTP 请求及响应解析逻辑,适用于电商比价、导购系统集成。