【反射机制】Java中的反射机制,使用反射机制创建对象、访问属性、方法、构造方法等
这篇文章主要是整理了Java中的反射机制,包括:反射机制概念、反射机制访问构造方法、反射机制访问普通方法、反射机制访问属性,反射机制访问修饰符。
目录
一、反射机制概念
二、反射机制使用
(1)加载Class类对象的几种方式
(2)准备测试类
(3)反射访问属性
(4)反射访问方法
(5)反射访问构造方法
(6)反射创建对象
(7)反射访问私有属性或方法
三、反射机制的应用
四、反射机制优缺点
(1)优点
(2)缺点
文章包含的源代码地址如下:
本篇文章涉及的案例代码在Gitee仓库,点击【反射机制案例代码】可以查看。
一、反射机制概念
什么是反射???
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。
在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
- Java中的反射机制,简单理解就是可以在程序运行的过程中,获取到某个类的内部结构信息,例如:类名称、属性、方法、构造方法等,并且可以动态的创建某个具体的对象实例的能力。
二、反射机制使用
(1)加载Class类对象的几种方式
我们在使用反射机制之前,第一步就是需要加载Class类对象,只有获取到Class类对象之后,我们才能根据Class类对象去访问相应类的内部结构信息,比如:属性、方法、构造方法、类名称、修饰符等等内容。
获取Class类对象一般有如下几种方式:
- 第一种方式:通过类的class属性获取Class类对象
/**
** 语法格式:
** Class<?> clazz = 类名称.class;
*/
public class ClassDemo {public static void main(String[] args) {// 1、类名称.class 获取Class类对象Class<String> clazz = String.class;// 输出看看效果System.out.println(clazz);}
}
- 第二种方式:通过对象的getClass()方法获取Class类对象
/**** 语法格式:* Class<?> clazz = 对象名称.getClass();*/
public class ClassDemo {public static void main(String[] args) {// 2、对象.getClass() 获取Class类对象String str = "";Class<? extends String> clazz2 = str.getClass();// 输出看看效果System.out.println(clazz2);}
}
- 第三种方式:通过Class.forName()获取Class类对象
/*** 语法格式:* Class<?> clazz = Class.forName("这里写类的全限定名称");* 类的全限定名称:包名称 + 类名称*/
public class ClassDemo {public static void main(String[] args) throws ClassNotFoundException {// 3、Class.forName() 获取Class类对象// 这种方式需要处理异常,因为根据包名称可能找不到类Class<?> clazz = Class.forName("java.lang.String");// 输出看看结果System.out.println(clazz);}
}
(2)准备测试类
为了测试反射机制获取类的内部结构信息,我们创建两个测试类,分别是:Person和Student类,并且Student类继承自Person,源代码大致如下。
- Person类代码
public class Person {// 属性private String priVal;String defVal;protected String proVal;public String pubVal;// 父类构造方法private Person(String priVal, String defVal, String proVal){}Person(String defVal){}protected Person(String proVal, String defVal){}public Person(){}// 方法private void test01(){}void test02(){}protected void test03(){}public void test04(){}
}
- Student类代码
public class Student extends Person {// 子类属性private String stuPriVal;String stuDefVal;protected String stuProVal;public String stuPubVal;// 子类构造方法private Student(String stuPriVal, String stuDefVal, String stuProVal){}Student(String stuDefVal){}protected Student(String stuProVal, String stuDefVal){}public Student(){}public Student(String name, Integer id){}// 子类方法private void subTest01(){System.out.println("Student类中的private私有方法");}void subTest02(){}protected void subTest03(){}{System.out.println("调用了Student类中的subTest04()方法,方法参数是:" + name);}
}
(3)反射访问属性
前面我们获取到了Class类对象之后,就可以通过Class类对象,去操作类的内部结构信息。
Field对象
- Java中将类中每个属性都封装成了一个【Field】对象,并且提供了一些获取这些属性的方法。
- Field属性,可以是当前类中的属性,也可以是父类中的属性。
反射机制获取类中的属性(Field对象):
- getFields(): 获取当前类、父类中的所有public属性。
- getDeclaredFields(): 获取当前类中的所有属性。
- getField(String name): 获取当前类、父类中指定名称的一个public属性(如果不是public属性,则会抛出异常)。
- getDeclaredField(String name): 获取当前类中指定名称的一个属性。
下面通过代码来看下这四个方法的具体使用。
public class FieldDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取类的属性// getFields(): 获取当前类、父类中的所有public方法Field[] fields = clazz.getFields();System.out.println("===== getFields(): 获取当前类、父类中的所有public方法 =====");for (Field field : fields) {System.out.println(""+field);}System.out.println();// getDeclaredFields(): 获取当前类中的所有方法Field[] declaredFields = clazz.getDeclaredFields();System.out.println("===== getDeclaredFields(): 获取当前类中的所有方法 =====");for (Field declaredField : declaredFields) {System.out.println(declaredField);}System.out.println();// getField(String name): 获取当前类、父类中指定名称的一个public属性System.out.println("===== getField(String name): 获取当前类、父类中指定名称的一个属性 =====");Field pubVal = clazz.getField("pubVal"); // 父类public属性System.out.println(pubVal);Field stuPubVal = clazz.getField("stuPubVal"); // 子类public属性System.out.println(stuPubVal);System.out.println();// getDeclaredField(String name): 获取当前类中指定名称的一个属性System.out.println("===== getDeclaredField(String name): 获取当前类中指定名称的一个属性 =====");Field stuPriVal = clazz.getDeclaredField("stuPriVal"); // 子类private属性System.out.println(stuPriVal);}
}
上面代码的运行结果如下所示:
通过反射机制,我们获取到了类中的属性,那要如何给属性赋值呢???
Java中提供了如下方法,用于属性赋值和获取属性值:
- set(Object obj,Object newValue)方法:用于属性赋值。参数obj表示实例对象,newValue表示赋值后的值。
- get(Object obj)方法:用于获取属性值。参数obj表示实例对象。
上面两种方式,只能给【非private修饰】的属性进行赋值操作,对于private的属性,不能直接操作,如何操作private属性,请看本篇文章的第(7)部分。
通过反射机制给属性赋值、获取属性值:
public class FieldDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建类对象Student student = (Student) clazz.newInstance();// 3、获取属性Field field = clazz.getDeclaredField("stuProVal");// 属性赋值field.set(student, "通过反射机制给属性赋值");// 获取属性值Object value = field.get(student);System.out.println(value);}
}
程序运行结果如下所示:
(4)反射访问方法
反射机制获取类中的方法(Method对象):
- getMethods(): 获取当前类、父类中所有的public方法。
- getDeclaredMethods(): 获取当前类中的所有方法。
- getMethod(String name, Class<?> paramType): 获取当前类、父类中一个指定方法名称的public方法(如果类中没有指定的方法,则会抛出异常)。
- getDeclaredMethod(String name, Class<?> paramType): 获取当前类中一个指定方法名称的方法(如果类中没有指定的方法,则会抛出异常)。
下面通过代码演示反射机制获取类中方法:
public class MethodDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取类中方法// getMethods(): 获取当前类、父类中所有的public方法Method[] methods = clazz.getMethods();System.out.println("===== getMethods(): 获取当前类、父类中所有的public方法 =====");for (Method method : methods) {System.out.println(method);}System.out.println();// getDeclaredMethods(): 获取当前类中的所有方法Method[] declaredMethods = clazz.getDeclaredMethods();System.out.println("===== getDeclaredMethods(): 获取当前类中的所有方法 =====");for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}System.out.println();// getMethod(String name, Class<?> paramType): 获取当前类、父类中一个指定方法名称的public方法System.out.println("===== getMethod(String name, Class<?> paramType): 获取当前类、父类中一个指定方法名称的public方法 =====");// 方法没有参数,则设置null即可Method test04 = clazz.getMethod("test04", null);System.out.println("父类中public方法: "+test04);// 有参数,则传递参数类型Method subTest04 = clazz.getMethod("subTest04", String.class);System.out.println("子类中public方法: "+subTest04);System.out.println();// getDeclaredMethod(String name, Class<?> paramType): 获取当前类中一个指定方法名称的方法System.out.println("===== getDeclaredMethod(): 获取当前类中一个指定方法名称的方法 =====");Method subTest01 = clazz.getDeclaredMethod("subTest01", null);System.out.println("当前类中私有方法: "+subTest01);}
}
上面代码最终运行结果如下图所示:
上面介绍了如何通过反射机制获取类中的方法,方法获取之后,那么要如何调用方法呢???
反射调用方法步骤如下:
- 获取Class类对象
- 通过Class创建一个实例对象
- 通过Class获取需要调用的Method对象
- 通过Method对象的invoke()进行方法调用
反射机制调用方法代码:
public class MethodDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建实例对象// 这里先默认通过构造方法创建实例对象,后面会继续介绍如何创建对象Student student = (Student) clazz.newInstance();// 3、获取需要调用的方法Method method = clazz.getDeclaredMethod("subTest04", String.class);// 调用invoke(Object obj, Object... args)方法, obj表示实例对象,args表示调用方法的参数Object ret = method.invoke(student, "这是一个方法参数");System.out.println("方法的返回值是:" + ret);}
}
程序运行结果如下所示:
invoke(Object obj, Object... args)方法:
- 参数obj:实例对象,因为我们调用方法需要知道调用哪个具体实例对象的方法。
- 参数args:方法参数,这是我们调用那个方法需要的参数值。
(5)反射访问构造方法
反射机制提供了如下四个方法,用于获取类的构造方法:
- getConstructors(): 获取当前类中所有public的构造方法。
- getDeclaredConstructors(): 获取当前类中的所有构造方法(不限制修饰符)。
- getConstructor(Class... args): 获取当前类中指定的参数个数的public构造方法(如果没有指定的构造方法,会抛出异常)。
- getDeclaredConstructor(Class... args): 获取当前类中指定参数个数的构造方法(修饰符不限制、如果没有指定的构造方法,会抛出异常)。
下面给出演示代码:
public class ConstructorDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {// 1、创建 Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取构造方法// getConstructors(): 获取当前类中所有public的构造方法System.out.println("===== getConstructors(): 获取当前类中所有public的构造方法 =====");Constructor<?>[] constructors = clazz.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor);}System.out.println();// getDeclaredConstructors(): 获取当前类中的所有构造方法System.out.println("===== getDeclaredConstructors(): 获取当前类中的所有构造方法 =====");Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor);}System.out.println();// getConstructor(Class... args): 获取当前类中指定的参数个数的public构造方法System.out.println("===== getConstructor(Class... args): 获取当前类中指定参数个数的public构造方法 =====");// 获取指定参数的构造方法Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);System.out.println(constructor);System.out.println();// getDeclaredConstructor(Class... args): 获取当前类中指定参数个数的构造方法(修饰符不限制)System.out.println("===== getDeclaredConstructor(Class... args): 获取当前类中指定参数个数的构造方法(修饰符不限制) =====");Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(String.class);System.out.println(declaredConstructor);}
}
代码运行结果如下图所示:
(6)反射创建对象
在前面,我们调用方法的时候,创建了一个实例对象,这里我们介绍一下通过反射机制如何创建一个对象。
创建对象,本质上就是通过new关键字,然后根据不同的构造方法创建对象实例。
反射机制中,提供了如下两种方式创建对象实例:
- 第一种方式:调用【newInstance()】方法(本质上是通过无参构造方法创建对象)
- 第二种方式:首先获取有参构造方法,然后通过有参构造方法去调用【newInstance(Object... args)】方法(通过有参构造方法创建对象)。
- 第一种方式:无参构造方法创建对象
public class InstanceDemo {public static void main(String[] args) throws ClassNotFoundException,InstantiationException, IllegalAccessException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、通过 newInstance() 创建对象// 通过 Student 类的无参构造方法创建对象Student student = (Student) clazz.newInstance();System.out.println(student);}
}
注意:这种创建对象的方式,要求对应的类中具有无参构造方法,如果没有无参构造方法,则会创建失败。
- 第二种方式:首先获取有参构造方法,然后通过有参构造方法去调用【newInstance(Object... args)】方法
第一种方式创建对象是有限制条件的,类必须具备无参构造方法,否则无法创建,这里在介绍一下通过有参构造方法创建对象。
public class InstanceDemo {public static void main(String[] args) throws ClassNotFoundException,InstantiationException, IllegalAccessException,NoSuchMethodException, InvocationTargetException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取有参构造方法Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, String.class);// 通过有参构造方法创建对象Student student = (Student) constructor.newInstance("参数1", "参数2");System.out.println(student);}
}
以上,就是通过反射机制创建对象的两种方式。
(7)反射访问私有属性或方法
setAccessible(boolean flag)方法。
我们前面介绍了通过反射获取属性、获取方法,但是反射对于私有属性、私有方法,是不能直接调用的。
- 反射机制访问私有属性
下面举个例子,我们直接操作私有的属性或者方法,然后查看运行结果:
public class AccessPrivateDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建对象Student student = (Student) clazz.newInstance();// 3、获取私有属性Field field = clazz.getDeclaredField("stuPriVal");// 给私有属性重新赋值field.set(student, "私有属性赋值新值");System.out.println("赋值后的值:" + field.get(student));}
}
程序运行之后,可以发现,控制台报错了,如下所示:
可以发现报错提示中,会出现了如下内容:
上面意思,大致就是:不能够访问private修饰符的类成员。
反射机制中,我们不能直接访问私有的成员、私有的方法,需要在调用之前,解除方法的安全性检查,这样我们就可以操作私有属性、私有方法了。
解除私有属性和方法的安全性检查:
- setAccessible(boolean flag):解除或者开启安全性检查。true表示解除安全性检查。
我们在访问私有属性之前,调用【setAccessible()】方法,再次查看结果。
public class AccessPrivateDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建对象Student student = (Student) clazz.newInstance();// 3、获取私有属性Field field = clazz.getDeclaredField("stuPriVal");// 解除安全性检查field.setAccessible(true); // true表示解除安全性检查// 给私有属性重新赋值field.set(student, "私有属性赋值新值");System.out.println("赋值后的值:" + field.get(student));}
}
程序运行结果如下所示:
- 反射机制访问私有方法
访问私有方法案例代码:
public class AccessPrivateDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException,NoSuchMethodException, InvocationTargetException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建对象Student student = (Student) clazz.newInstance();// 3、获取私有方法Method method = clazz.getDeclaredMethod("subTest01", null);// 解除安全性检查method.setAccessible(true);// 调用方法Object ret = method.invoke(student, null);System.out.println("方法返回值:" + ret);}
}
程序运行结果如下所示:
以上,就是通过反射机制访问私有属性或者方法。
三、反射机制的应用
反射机制在很多地方都被使用到了,比如下面这些场景都采用反射机制实现的。
- JDBC获取数据库连接:通过反射机制加载数据库驱动程序。
- Spring中的IOC容器:根据xml配置文件的bean标签,然后采用反射机制创建实例对象。
- MyBatis中mapper接口执行SQL语句:动态代理中使用反射机制调用目标对象方法。
- AOP动态代理:动态代理中就需要通过反射机制创建对象。
- 等等。。。
四、反射机制优缺点
(1)优点
- 反射机制提高了程序的可扩展性、灵活性。
- 降低了程序的耦合性。
(2)缺点
- 反射机制会破环面向对象的封装性,因为通过反射可以访问private私有属性或方法。
- 反射机制会降低程序的运行效率。
以上,就是我个人对反射机制相关内容的总结,包括:获取类对象、反射机制访问属性、方法、构造方法、访问私有成员、以及反射机制的应用场景和优缺点。
【反射机制】Java中的反射机制,使用反射机制创建对象、访问属性、方法、构造方法等相关推荐
- java为何重复调用方法_通过反射调用Java中的getter:重复调用它的最快方法是什么(在性能和可伸缩性方面)?...
小编典典 您可以使用MethodHandle.其Javadoc写道: 使用Lookup API中的工厂方法,可以将Core Reflection API对象表示的任何类成员转换为行为等效的方法句柄.例 ...
- java实现分发_关于JAVA中事件分发和监听机制实现的代码实例
[实例简介] 关于JAVA中事件分发和监听机制实现的代码实例,绝对实用代码,有说明. [实例截图] [核心代码] JavaEventDispatch ├── bin │ └── com │ └ ...
- Java基础-Java中的内存分配与回收机制
Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二. 转载于:https://www.cnblogs.com/yinzhengji ...
- 关于JAVA中事件分发和监听机制实现的代码实例-绝对原创实用
转载:http://blog.csdn.net/5iasp/article/details/37054171 谢谢博主 ======================================== ...
- 转:Java中子类是否可以继承父类的static变量和方法而呈现多态特性
原文地址:Java中子类是否可以继承父类的static变量和方法而呈现多态特性 静态方法 通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法,关于static方法,声明 ...
- java整型转换为数组_基于java中byte数组与int类型的转换(两种方法)
java中byte数组与int类型的转换,在网络编程中这个算法是最基本的算法,我们都知道,在socket传输中,发送.者接收的数据都是 byte数组,但是int类型是4个byte组成的,如何把一个整形 ...
- Java中url传递中文参数取值乱码的解决方法
Java中url传递中文参数取值乱码的解决方法 参考文章: (1)Java中url传递中文参数取值乱码的解决方法 (2)https://www.cnblogs.com/liwenjuan/p/3211 ...
- JAVA中的多线程(八):线程的优先级和yield方法
JAVA中的多线程(八):线程的优先级和yield方法 优先级代表着抢资源的频率 所有线程默认优先级是5 yield()临时释放线程的执行权 1 class Demo implements Runna ...
- java中给对象的List集合去重的几种方法(Lambda)
java中给对象的List集合去重的几种方法 前言 一.lambda表达式的去重方式 二.Stream API中的collect去重方法 三.Stream API 中的distinct方法去重 前言 ...
- Java中的反射和Java中的访问修饰符
什么是反射? ①在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性 ②对于任何一个对象,我们都能够对它的方法和属性进行调用 总而言之:它反射Java语言中的一种机制,通过这种机制可以动 ...
最新文章
- android消息池,回转寿司你一定吃过!——Android消息机制(构造)
- BOM的window对象的属性及其方法
- java常见的报错_Java中常见的错误有哪些?
- 关于Oracle RAC节点间免密码策略
- qs.parse和qs.stringify
- 商户网站使用第三方支付的大致原理和实现
- 12.4scrum report
- 算法训练营 重编码_参加编码训练营之前要考虑的7件事
- 电机入门之路系列1--减速步进电机的原理
- linux的grub界面退出,linux退出 grub
- php 随机生成ip
- 根据列值删除Pandas中的DataFrame行
- RestTemplate 了解和学习
- 如何在CentOS/RedHat下实现根据源码包创建rpm包
- 送你一份有态度的红包封面!
- oracle中外键的使用方法,Oracle数据库中外键的相关操作整理
- 【学习笔记】尚硅谷大数据项目之Flink实时数仓---数据采集
- 在uniapp中配置并colorui及阿里图标
- cuda10.0及其驱动纯净卸载(笔记)
- php计算器源码,php 简单计算器