深入剖析Java中的反射,由浅入深,层层剥离!
写在开头
之前更新了不少Java的基础知识,比如Java的类、对象、基础类型、关键字、序列化、泛型、值传递等等,今天要上点深度了,来聊一聊Java中的 反射 !
所谓反射,就是在运行时分析、检查和操作类、接口、方法、属性的行为!
简单感受一下反射
在开始详解反射之前,我们先通过一段代码,简单的感受一下反射的魅力!首先,我们已经写了一个Person类,类中有age和name属性,并提供了set/get方法。这时候分别通过正常的实例化对象调用,和反射调用去操作对象的属性值!
【代码示例1】
//Java正射实现
Person person = new Person();
person.setName("JavaBuild-正射");
System.out.println(person.getName());
//Java反射实现
//获取类的class对象
Class<?> classa = Class.forName("com.javabuild.server.pojo.Person");
//通过class获取类的元数据-setName/getName方法
Method setName = classa.getMethod("setName", String.class);
Method getName = classa.getMethod("getName");
//获取默认空构造方法
Constructor constructor = classa.getConstructor();
//通过newInstance()进行实例化
Object o = constructor.newInstance();
//通过invoke方法进行方法调用
setName.invoke(o,"JavaBuild-反射");
System.out.println(getName.invoke(o));
以上为Java正射与反射的对比实现代码。从代码中我们可以看到,正常通过实例化对象后再调用相应方法的正射方式比通过反射的方式代码量要少很多,并且逻辑更加清晰明确。
使用场景
反射被称之为框架的灵魂,在Java中被大量使用在框架、动态代理、注解等场景下;
- 开发框架:Spring、SpringBoot、Mybatis、Hibernate等框架中使用了反射
- 动态代理:在面向切面编程中,需要拦截特定的方法,就会选择动态代理的方式,而动态代理的底层技术就是反射。
- 注解:注解本身只是起到一个标记符的作用,它需要利用反射机制,根据标记符去执行特定的行为。比如@Component注解就声明了一个类为 Spring Bean ,通过@Value注解读取配置文件中的值,这些的底层都是通过反射来实现需求。
实现过程
我们基于上述代码示例1中的反射进行分步分析,彻底搞明白反射的实现与使用!
【步骤一】
通过如下这句代码获取反射类的Class对象
Class<?> classa = Class.forName("com.javabuild.server.pojo.Person");
可别小看这简简单单的一行代码,这里其实涉及到3个知识点,我们来扩展一下。
知识点一:什么是Class对象?
这里提到的Class和之间了解的用来标识类的class关键字并不一样!Class也是一个类,存放在java.lang包中,它的作用是:编译时生成一个类的Class对象,这个对象中包含了类的结构信息,如类名、继承父类、实现的接口、方法、属性等等,Class对象保存在编译后的.class文件中。
在我们new一个对象或者引用静态成员变量时,会将Class对象加载到JVM中,JVM解释器去分析Class对象获取到类的结构信息,创建我们需要的实例对象或者提供静态成员变量的引用值。
因为类的Class对象时存储在class文件中,所以不管实例化多少个对象,都有且仅有一个Class对象!因为Class类对象本身的特性,所以它可以在运行时操作类,这对反射来说无疑是天赐良缘!
知识点二:获取Class对象的几种方式?
1、在已知具体类的情况下
Class person= Person.class;
2、通过Class.forName()传入类的全路径获取,代码示例1中采用该方式
Class classa = Class.forName("com.javabuild.server.pojo.Person");
3、对象实例instance.getClass()获取
Person person = new Person();
Class aClass = person.getClass();
4、通过类加载器xxxClassLoader.loadClass()传入类路径获取
Class aClass = ClassLoader.getSystemClassLoader().loadClass("com.javabuild.server.pojo.Person");
知识点三:java.lang.reflect包中常用的反射类
在java.lang.reflect包中存着几个反射常用的类,大概的罗列如下,注意,Class类其实是放在java.lang中的。
Class:代表一个类或接口,包含了类的结构信息(如名称、构造函数、方法、字段等)。通过 Class 对象,可以获取类的元数据并操作类的实例。
Constructor:代表类的构造方法,用于创建类的实例。
Method:代表类的方法,可以通过它调用类的实例方法。
Field:代表类的字段,可以获取或修改字段的值。
Modifier:包含方法、字段和类的访问修饰符(如 public、private 等)。
【步骤二】
通过Class对象获取构造方法
Constructor constructor = classa.getConstructor();
除了这种获取默认无参构造的方式,获取构造方法还可以通过如下这些方式:
getConstructor():返回反射类的特定 public 构造方法,可以传递参数,参数为构造方法参数对应 Class 对象;缺省的时候返回默认构造方法。
getDeclaredConstructor():返回反射类的特定构造方法,不限定于 public 的。
getConstructors():返回类的所有 public 构造方法。
getDeclaredConstructors():返回类的所有构造方法,不限定于 public 的。
【代码示例2】
Class<?> classa = Class.forName("com.javabuild.server.pojo.Person");
Constructor constructor01 = classa.getConstructor();
System.out.println(constructor);
System.out.println("---------------");
Constructor<?>[] constructors = classa.getConstructors();
for (Constructor<?> constructor02 : constructors) {
System.out.println(constructor02);
}
System.out.println("----------------");
Constructor declaredConstructor = classa.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor);
【控制台输出】
public com.javabuild.server.pojo.Person()
---------------
public com.javabuild.server.pojo.Person()
public com.javabuild.server.pojo.Person(int)
public com.javabuild.server.pojo.Person(int,java.lang.String)
----------------
public com.javabuild.server.pojo.Person(int)
【步骤三】
通过 Constructor 对象初始化反射类对象
//通过newInstance()进行实例化
Object o = constructor.newInstance();
【步骤四】
获取要调用的方法的 Method 对象
//通过class获取类的元数据-setName/getName方法
Method setName = classa.getMethod("setName", String.class);
Method getName = classa.getMethod("getName");
【步骤五】
通过invoke方法进行方法调用
setName.invoke(o,"JavaBuild-反射");
以上即为反射使用的全过程!下面贴一下全量代码。
Person类
public class Person {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//无参构造
public Person() {
}
//一个参数构造
public Person(int age) {
this.age = age;
}
//2个参数构造
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
反射测试类
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//Java正射实现
Person person = new Person();
person.setName("JavaBuild-正射");
System.out.println(person.getName());
//Java反射实现
//获取类的class对象
Class<?> classa = Class.forName("com.javabuild.server.pojo.Person");
//通过class获取类的元数据-setName/getName方法
Method setName = classa.getMethod("setName", String.class);
Method getName = classa.getMethod("getName");
//获取默认空构造方法
Constructor constructor = classa.getConstructor();
//通过newInstance()进行实例化
Object o = constructor.newInstance();
//通过invoke方法进行方法调用
setName.invoke(o,"JavaBuild-反射");
System.out.println(getName.invoke(o));
//获取默认空构造方法
Constructor constructor01 = classa.getConstructor();
System.out.println(constructor);
System.out.println("---------------");
Constructor<?>[] constructors = classa.getConstructors();
for (Constructor<?> constructor02 : constructors) {
System.out.println(constructor02);
}
System.out.println("----------------");
Constructor declaredConstructor = classa.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor);
}
}
输出
JavaBuild-正射
JavaBuild-反射
public com.javabuild.server.pojo.Person()
---------------
public com.javabuild.server.pojo.Person()
public com.javabuild.server.pojo.Person(int)
public com.javabuild.server.pojo.Person(int,java.lang.String)
----------------
public com.javabuild.server.pojo.Person(int)
优缺点
基于上面的内容,我们可以对java中的反射做一个总结吧
优点
1、可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利。
缺点
1、破坏封装:由于反射允许访问私有字段和私有方法,所以可能会破坏封装而导致安全问题。
2、性能开销:由于反射涉及到动态解析,因此无法执行 Java 虚拟机优化,再加上反射的写法的确要复杂得多,所以性能要比“正射”差很多,在一些性能敏感的程序中应该避免使用反射。
深入剖析Java中的反射,由浅入深,层层剥离!的更多相关文章
- 深度剖析java中JDK动态代理机制
https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...
- Java中的反射和注解
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
- java中的反射机制在Android开发中的用处
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...
- 深入剖析Java中的装箱和拆箱
深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱 ...
- 从别人那淘的知识 深入剖析Java中的装箱和拆箱
(转载的海子的博文 海子:http://www.cnblogs.com/dolphin0520/) 深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来 ...
- 浅说Java中的反射机制(二)
写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- java中动态反射
java中动态反射能达到的效果和python的语法糖很像,能够截获方法的实现,在真实方法调用之前和之后进行修改,甚至能够用自己的实现进行特别的替代,也可以用其实现面向切片的部分功能.动态代理可以方便实 ...
- 深入剖析Java中的自动装箱和拆箱过程
深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱 ...
- 第89节:Java中的反射技术
第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...
随机推荐
- java调用本机的命令 如ping、打开文本等
最近接触到用java代码调用主机的命令部分感觉有点意思整理总结一下 环境jdk1.8 操作系统win10,不用引入其他的包jdk自带的api就可以 一.java调用ping命令 import jav ...
- k8s探针详解
一.探针类型 Kubernetes(k8s)中的探针是一种健康检查机制,用于监测Pod内容器的运行状况.主要包括以下三种类型的探针: 1.存活探针(Liveness Probe) 2.就绪探针(Rea ...
- 分享10个高级sql写法
本文主要介绍博主在以往开发过程中,对于不同业务所对应的 sql 写法进行归纳总结而来.进而分享给大家. 本文所讲述 sql 语法都是基于 MySql 8.0+ 博主github地址:http://gi ...
- python之pycharm常见使用技巧
一.ctrl+d:复制
- KVM 核心功能:磁盘虚拟化
1 磁盘虚拟化简介 QEMU-KVM 提供磁盘虚拟化,从虚拟机角度看其自身拥有的磁盘即是实际的物理磁盘.实际上,虚拟机读写的磁盘数据保存在 host 上的物理磁盘. QEMU-KVM 主要有如下几 ...
- pmp考试巩固知识点
1.冲刺评审会是需要相关的干系人参加的,在冲刺评审会上干系人可以审查并澄清角色.责任和管理模式2.采购中的争议,往往找合同和SOW,SOW是对需要采购的详细范围的描述,与供应商在可交付成果方面有争议时 ...
- 国庆学go,完成了博客基本功能,迫不及待的发布上线了
大家好,我是沙漠尽头的狼. 国庆7天,利用带娃之余的空闲时间学习了go,并做了一个不是很完善的博客前台网站. 网站发布地址:https://go.dotnet9.com 源码 边做边上传Github, ...
- [转帖]46岁加入谷歌,51岁发明Go,他的编程原则影响了一大批程序员!
https://www.zhihu.com/tardis/zm/art/551945410?source_id=1005 今年3月,万众瞩目的Go 1.18版本发布,Go终于开始支持泛型了!该版本不仅 ...
- [转帖]JVM 输出 GC 日志导致 JVM 卡住,我 TM 人傻了
https://www.jianshu.com/p/51380e04eab1 最近,我们升级了 Java 17.后来,我们的 k8s 运维团队为了优化我们的应用日志采集, 将我们所有 pod (你可以 ...
- [转帖]tidb的分区表
https://docs.pingcap.com/zh/tidb/v6.5/partitioned-table 分区类型 本节介绍 TiDB 中的分区类型.当前支持的类型包括 Range 分区.Ran ...