深入了解Java中的反射机制(reflect)
作者:无声编码器 发布时间:2022-06-22 06:34:18
Java的反射机制允许我们对一个类的加载、实例化、调用方法、操作属性的时期改为在运行期进行,这大大提高了代码的灵活度。但在运行期进行反射操作会消耗额外的资源与性能,所以要适度使用。
JVM(Java虚拟机)加载一个类有以下几种方式:
1、执行代码时,需要用到某个类,例如:Person p = new Person(); 时,这时候JVM 会加载 Person.class 。
2、通过反射机制中的:Class.forName(String className) 方法以字符串的形式加载指定的类,此方法只能寻找环境变量中配置的类路径中指定的类。
3、通过类加载器 ClassLoader 来加载指定的类,类加载器可以额外指定环境变量中没有指定的类路径,并从中寻找指定的类进行加载。
除了第一种方式外,剩下的两种都是基于反射机制动态的加载一个类,加载类的过程就是让 JVM 读取该类对应的 class 文件。当 JVM 读取一个类的 class 文件后,会实例化一个 Class 类的实例用于保存加载的这个类的信息。并且每个被加载的类只会进行一次加载过程,这意味着每个被 JVM 加载的类都会在 JVM 内部以一个 Class 类的实例进行保存,所以每个类有且只有一个 Class 类的实例与之对应。Class 也称为类对象,每个实例用于表示 JVM 加载的一个类,通过它可以获取其表示的类的相关信息,比如类的名字、有哪些属性、构造器以及所有方法,并且通过 Class 还可以实例化其表示的类。
Class 类 与 Method 类:
Class 类:Class 类的实例表示正在运行的Java应用程序中的类和接口。Class 类没有公共构造函数,类对象是由Java虚拟机在加载类时自动构造的,通过调用类加载器中的defineClass方法来构造。
Method 类:Method 类是反射API中一个重要的类,其每一个实例表示某个类的一个具体方法,所反映的方法可以是类方法或实例方法(包括抽象方法)。通过 Method 可以获取到其表示的方法的相关信息,如方法名、返回值类型、参数类型、访问修饰符等。并且也可以通过 Method 类动态调用其表示的方法。
方法实例
public static Class<?> forName(String className)
throws ClassNotFoundException
描述:
返回与具有给定字符串名称的类或接口关联的Class对象。
参数:
className -- 所需类的完全限定名称。
返回值:
具有指定名称的类的Class对象。
注意:
如果找不到类,抛出 ClassNotFoundException 异常。
public class Person {
public String name;
private Integer code;
public Person() {
System.out.println("无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
System.out.println(aClass);
}
}
// 程序运行结果如下:
// class Person
public T newInstance()
throws InstantiationException, IllegalAccessException
描述:
创建由该 Class 对象表示的类的新实例。该方法调用当前 Class 所表示的类的无参构造方法,所以该类必须有无参构造方法。
参数:
无
返回值:
由该 class 表示的类的新分配的实例。
注意:
如果类或其无参构造函数不可访问,抛出 IllegalAccessException 异常。
如果该类表示抽象类、接口、数组类、基元类型或void;或者如果该类没有无参构造函数;或者如果实例化由于某些其他原因而失败,抛出 InstantiationException 异常。
public class Person {
public String name;
private Integer code;
public Person() {
System.out.println("调用了无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
Person person = (Person)aClass.newInstance();
System.out.println(person);
}
}
// 程序运行结果如下:
// 调用了无参构造方法
// Person@29453f44
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
描述:
返回一个构造函数对象,该对象反映由该Class对象表示的类的指定公共构造函数。
参数:
parameterTypes -- Class对象的数组,这些对象按声明的顺序标识构造函数的形式参数类型。
返回值:
与指定的parameterTypes匹配的公共构造函数的Constructor对象。
注意:
如果找不到匹配的方法,抛出 NoSuchMethodException 异常。
如果访问被拒绝,抛出 SecurityException 异常。
public class Person {
public String name;
private Integer code;
public Person(String name) {
this.name = name;
System.out.println("调用了有参构造方法");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
Constructor constructor = aClass.getConstructor(String.class);
Person person = (Person)constructor.newInstance("阿刚");
System.out.println(person.name);
}
}
// 程序运行结果如下:
// 调用了有参构造方法
// 阿刚
// Class 类
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
描述:
获取当前 Class 所表示的类定义的指定名字及参数列表的方法。
参数:
name -- 方法的名称。
parameterTypes -- 一组Class对象,这些对象按声明的顺序标识方法的形式参数类型。
返回值:
与指定的名称和参数匹配的此类的方法的Method对象。
注意:
如果找不到匹配的方法,抛出 NoSuchMethodException 异常。
如果名称为null, 抛出 NullPointerException 异常。
如果访问被拒绝,抛出 SecurityException 异常。
// Method 类
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
描述:
在具有指定参数的指定对象上调用此 method 对象表示的基础方法。如果基础方法是静态的,则会忽略指定的 obj 参数,它可能为 null。
参数:
obj -- 如果通过该方法调用的是成员方法,因为成员方法属于对象,那么调用该方法时,使用该参数传递成员方法所属对象。如果过该方法调用的是静态方法,可以传递null。
args -- 方法的实际参数,若该方法无参,传入 null 即可。
注意:
如果此Method对象正在强制执行Java语言访问控制,并且底层方法不可访问,抛出 IllegalAccessException 异常。
如果方法是实例方法,并且指定的对象参数不是声明底层方法(或其子类或实现者)的类或接口的实例;或者如果实际参数和形式参数的数量不同;或者如果原始参数的展开转换失败;或者如果在可能的展开之后,无法通过方法调用转换将参数值转换为相应的形式参数类型; 抛出 IllegalArgumentException 异常。
如果基础方法抛出异常,则抛出 InvocationTargetException 异常。
如果指定的对象为null,并且该方法是实例方法,则抛出 NullPointerException 异常。
public class Person {
public String name;
private Integer code;
public Person() {
System.out.println("调用了无参构造方法");
}
public Person(String name) {
this.name = name;
System.out.println("调用了有参构造方法");
}
public static String happy(){
return "哈哈";
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
Object person = aClass.newInstance();
// Method是反射API中一个重要的类,其每一个实例表示某个类的具体方法
// 调用 setName 方法
Method setMethod = aClass.getDeclaredMethod("setName",String.class);
setMethod.invoke(person,"阿全");
// 调用 getName 方法
Method getMethod = aClass.getDeclaredMethod("getName",null);
System.out.println(getMethod.invoke(person,null));
// 调用了静态方法
Method happyMethod = aClass.getDeclaredMethod("happy",null);
System.out.println(happyMethod.invoke(null,null));
}
}
// 程序运行结果如下:
// 调用了无参构造方法
// 阿全
// 哈哈
来源:https://juejin.cn/post/7234817882903019579
猜你喜欢
- Android:4.4.4一、应用场景在Android设备上,现在我们外接了一个USB转串口的设备,设备节点是/dev/ttyUSB0:#
- FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化
- 实现系统重启的APK需要system的权限,在AndroidManifest.xml中增加android:sharedUserId=&quo
- 本文实现android系统照相机的调用来拍照项目的布局相当简单,只有一个Button:<RelativeLayout xmlns:an
- 对于生成的sql语句 自动加上单引号的情况mybatis是这样的,如果表的字段跟系统字段冲突,写sql语句的时候必须得加上单引号,这样才会区
- 本文实例为大家分享了Android Camera实现可复用相机组件的具体代码,供大家参考,具体内容如下若自己的应用需要使用camera,有两
- 一、需求描述拼图是一款益智类经典游戏了,本游戏学习了一些前辈们的经验,整体来说讲,将图片用切图工具进行切割,监听用户手指滑动事件,当用户对凌
- 作者:sparkdev出处:http://www.cnblogs.com/sparkdev/注意,本文所说的断点续传特指 HTTP 协议中的
- 本文实例讲述了Java基于解释器模式实现定义一种简单的语言功能。分享给大家供大家参考,具体如下:一 模式定 * 释器模式:就是给定一个语言的文
- 从今天开始写关于C#的系列文章,本篇文章主要讲解C#中的委托使用。委托其实就是一种数据类型,和int,string是一样的概念。如果要把一个
- 前言之前写了一个博客是关于使用SpringBoot使用validation-api实现参数校验,当时使用的注解都是validation-ap
- Java实现按行读取大文件String file = "F:" + File.separator + "a.t
- 本文实例为大家分享了JFinal使用ajaxfileupload实现图片上传预览的具体代码,供大家参考,具体内容如下1.前端jsp页面核心代
- 本文实例为大家分享了TextView绘制背景的方法,供大家参考,具体内容如下效果:实现流程:1.初始化:对画笔进行设置mPaintIn =
- 需求: 给定一个URL地址, 例如: http://www.cncounter.com/tools/shorturl.php, 解析对应的I
- 单点登录(SSO):SSO是指在多个应用系统中个,用户只需要登陆一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应
- Android 7.0系统在运行应用的时候,对权限做了诸多限制,normal, dangerous, signature, signatur
- 1、接口:接口与抽象类一样,也是表示某种规则,一旦使用了该规则,就必须实现相关的方法。对于C#语言而言,由于只能继承自一个父类,因此若有多个
- 本文实例讲述了Android编程调用Camera和相册功能。分享给大家供大家参考,具体如下:xml:<LinearLayout xml
- Android Dialog 对话框 1、Dialog介绍 2、AlertDialog的基本使用 3、自定义对话框 Custom Dialo