反射调用方法 | 带你学《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面向对象编程文章查看此处

相关文章
|
10天前
|
Java
Java——方法的引用
方法引用允许将已有方法作为函数式接口的实现。使用“::”符号,需具备函数式接口,被引用的方法须存在且参数和返回值需与抽象方法一致。其分类包括:静态方法引用(类::方法名)、成员方法引用(对象::方法名、this::方法名、super::方法名)和构造方法引用(类名::new)。方法引用提高了代码的简洁性和可读性,减少了样板代码。
27 13
Java——方法的引用
|
10天前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
34 9
Java——反射&枚举
|
6天前
|
Java
java基础(12)抽象类以及抽象方法abstract以及ArrayList对象使用
本文介绍了Java中抽象类和抽象方法的使用,以及ArrayList的基本操作,包括添加、获取、删除元素和判断列表是否为空。
11 2
java基础(12)抽象类以及抽象方法abstract以及ArrayList对象使用
|
2天前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
11 4
|
4天前
|
安全 Java API
Java根据URL获取文件内容的实现方法
此示例展示了如何安全、有效地根据URL获取文件内容。它不仅展现了处理网络资源的基本技巧,还体现了良好的异常处理实践。在实际开发中,根据项目需求,你可能还需要添加额外的功能,如设置连接超时、处理HTTP响应码等。
30 4
|
5天前
|
安全 Java
java调用方法
java调用方法
18 4
|
6天前
|
存储 安全 Java
扫盲java基础-反射(一)
扫盲java基础-反射(一)
|
6天前
|
Java
扫盲java基础-反射(二)
扫盲java基础-反射(二)
|
6天前
|
Java 索引
java基础扫盲-String类常用的方法
java基础扫盲-String类常用的方法
|
存储 SQL Java
Java反射读取注解信息
Java反射读取注解信息
66 0
下一篇
无影云桌面