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

相关文章
|
12天前
|
Java 数据处理 数据安全/隐私保护
Java处理数据接口方法
Java处理数据接口方法
20 1
|
29天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
48 4
|
2月前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
50 17
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
86 4
|
1月前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
97 2
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
23 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
19 2
|
2月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
22 1
|
2月前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
26 0
[Java]反射
|
1月前
|
Java Spring
JAVA获取重定向地址URL的两种方法
【10月更文挑战第17天】本文介绍了两种在Java中获取HTTP响应头中的Location字段的方法:一种是使用HttpURLConnection,另一种是使用Spring的RestTemplate。通过设置连接超时和禁用自动重定向,确保请求按预期执行。此外,还提供了一个自定义的`NoRedirectSimpleClientHttpRequestFactory`类,用于禁用RestTemplate的自动重定向功能。