阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

调用方法

267次阅读
没有评论

共计 3921 个字符,预计需要花费 10 分钟才能阅读完成。

我们已经能通过 Class 实例获取所有 Field 对象,同样的,可以通过 Class 实例获取所有 Method 信息。Class类提供了以下几个方法来获取Method

  • Method getMethod(name, Class...):获取某个 publicMethod(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有 publicMethod(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

我们来看一下示例代码:

// reflection
public class Main {public static void main(String[] args) throws Exception {Class stdClass = Student.class;
        // 获取 public 方法 getScore,参数为 String:
        System.out.println(stdClass.getMethod("getScore", String.class));
        // 获取继承的 public 方法 getName,无参数:
        System.out.println(stdClass.getMethod("getName"));
        // 获取 private 方法 getGrade,参数为 int:
        System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));
    }
}

class Student extends Person {public int getScore(String type) {return 99;
    }
    private int getGrade(int year) {return 1;
    }
}

class Person {public String getName() {return "Person";
    }
}

上述代码首先获取 StudentClass实例,然后,分别获取 public 方法、继承的 public 方法以及 private 方法,打印出的 Method 类似:

public int Student.getScore(java.lang.String)
public java.lang.String Person.getName()
private int Student.getGrade(int)

一个 Method 对象包含一个方法的所有信息:

  • getName():返回方法名称,例如:"getScore"
  • getReturnType():返回方法返回值类型,也是一个 Class 实例,例如:String.class
  • getParameterTypes():返回方法的参数类型,是一个 Class 数组,例如:{String.class, int.class}
  • getModifiers():返回方法的修饰符,它是一个int,不同的 bit 表示不同的含义。

调用方法

当我们获取到一个 Method 对象时,就可以对它进行调用。我们以下面的代码为例:

String s = "Hello world";
String r = s.substring(6); // "world"

如果用反射来调用 substring 方法,需要以下代码:

// reflection
import java.lang.reflect.Method;

public class Main {public static void main(String[] args) throws Exception {// String 对象:
        String s = "Hello world";
        // 获取 String substring(int)方法,参数为 int:
        Method m = String.class.getMethod("substring", int.class);
        // 在 s 对象上调用该方法并获取结果:
        String r = (String) m.invoke(s, 6);
        // 打印调用结果:
        System.out.println(r); // "world"
    }
}

注意到 substring() 有两个重载方法,我们获取的是 String substring(int) 这个方法。思考一下如何获取 String substring(int, int) 方法。

Method 实例调用 invoke 就相当于调用该方法,invoke的第一个参数是对象实例,即在哪个实例上调用该方法,后面的可变参数要与方法参数一致,否则将报错。

调用静态方法

如果获取到的 Method 表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以 invoke 方法传入的第一个参数永远为 null。我们以Integer.parseInt(String) 为例:

// reflection
import java.lang.reflect.Method;

public class Main {public static void main(String[] args) throws Exception {// 获取 Integer.parseInt(String)方法,参数为 String:
        Method m = Integer.class.getMethod("parseInt", String.class);
        // 调用该静态方法并获取结果:
        Integer n = (Integer) m.invoke(null, "12345");
        // 打印调用结果:
        System.out.println(n);
    }
}

调用非 public 方法

和 Field 类似,对于非 public 方法,我们虽然可以通过 Class.getDeclaredMethod() 获取该方法实例,但直接对其调用将得到一个 IllegalAccessException。为了调用非 public 方法,我们通过Method.setAccessible(true) 允许其调用:

// reflection
import java.lang.reflect.Method;

public class Main {public static void main(String[] args) throws Exception {Person p = new Person();
        Method m = p.getClass().getDeclaredMethod("setName", String.class);
        m.setAccessible(true);
        m.invoke(p, "Bob");
        System.out.println(p.name);
    }
}

class Person {
    String name;
    private void setName(String name) {this.name = name;
    }
}

此外,setAccessible(true)可能会失败。如果 JVM 运行期存在 SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager 可能不允许对 javajavax开头的 package 的类调用setAccessible(true),这样可以保证 JVM 核心库的安全。

多态

我们来考察这样一种情况:一个 Person 类定义了 hello() 方法,并且它的子类 Student 也覆写了 hello() 方法,那么,从 Person.class 获取的 Method,作用于Student 实例时,调用的方法到底是哪个?

// reflection
import java.lang.reflect.Method;

public class Main {public static void main(String[] args) throws Exception {// 获取 Person 的 hello 方法:
        Method h = Person.class.getMethod("hello");
        // 对 Student 实例调用 hello 方法:
        h.invoke(new Student());
    }
}

class Person {public void hello() {System.out.println("Person:hello");
    }
}

class Student extends Person {public void hello() {System.out.println("Student:hello");
    }
}

运行上述代码,发现打印出的是Student:hello,因此,使用反射调用方法时,仍然遵循多态原则:即总是调用实际类型的覆写方法(如果存在)。上述的反射代码:

Method m = Person.class.getMethod("hello");
m.invoke(new Student());

实际上相当于:

Person p = new Student();
p.hello();

练习

利用反射调用方法。

下载练习

小结

Java 的反射 API 提供的 Method 对象封装了方法的所有信息:

通过 Class 实例的方法可以获取 Method 实例:getMethod()getMethods()getDeclaredMethod()getDeclaredMethods()

通过 Method 实例可以获取方法信息:getName()getReturnType()getParameterTypes()getModifiers()

通过 Method 实例可以调用某个对象的方法:Object invoke(Object instance, Object... parameters)

通过设置 setAccessible(true) 来访问非 public 方法;

通过反射调用方法时,仍然遵循多态原则。

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计3921字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7978971
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
如何安装2026年最强个人助理ClawdBot、完整安装教程

如何安装2026年最强个人助理ClawdBot、完整安装教程

如何安装 2026 年最强个人助理 ClawdBot、完整安装教程 一、前言 学不完,根本学不完!近期,一款名...
星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛 NAS-11:咪咕视频订阅部署全攻略 前言 在家庭影音系统里,NAS 不仅是存储中心,更是内容...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

  星哥带你玩飞牛 NAS-16:不再错过公众号更新,飞牛 NAS 搭建 RSS 对于经常关注多个微...
自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个 AI 智能体 — 跟创业大佬对话 前言 智能体(Agent)已经成为创业者和技术人绕...
12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...
支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare 也瘫了连监控都挂,根因藏在哪? 最近两天的互联网堪称“故障...
颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

  颠覆 AI 开发效率!开源工具一站式管控 30+ 大模型 ApiKey,秘钥付费 + 负载均衡全...