编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

java中的反射 java中的反射机制使用

gowuye 2024-04-04 11:57 10 浏览 0 评论

一、什么是反射

谈java反射前我们先来说说物理界的“反射”,第一次见反射这个词语,估计还是从初中物理中看到的,我们先来看看物理界中反射的定义。

我们可以细读这一句:在分界面上改变传播方向又返回原来物质的现象。

从这句话我们可以得知,通过反射我么可以获取物质的一些属性与特质,同然,在java中反射也具有这样的功能。

java中的反射是指在运行过程中,对任意一个类,都能知道类的所有属性与方法;对任意一个对象,能够调用它任意一个方法与属性;这种动态获取信息和动态调用对象的方法就叫做java语言的反射机制

接下来代码演示:

//正常调用
ZhangSan zhangSan = new ZhangSan();
zhangSan.setAge(30);
zhangSan.setNickName("法外狂徒");
System.out.println("ZhangSan:"+zhangSan);

//使用反射调用
Class c = Class.forName("pojo.ZhangSan");
Method setAge = c.getMethod("setAge", Integer.class);
Constructor constructor = c.getConstructor();
Object o = constructor.newInstance();
setAge.invoke(o,18);
Method getAge = c.getMethod("getAge");
System.out.println("ZhangSan:"+getAge.invoke(o));

查看输出演示:

上面两段代码产生的效果是一样的,不同是正常调用的这段代码是直接new对象,而反射调用是用类反射调用。

所以什么是反射?

反射是在运行时知道要操作的类是什么,并且在运行时获取类的完整构造,并调用相应方法。

可能这时有小伙伴就要问了,我直接正常调用他不香吗,为啥要废大力气去用反射。

八哥其实也有这样的疑惑,当我百思不得其解时,望向了窗外的一缕反射过来的阳光,原来反射他就是一面镜子,不用管本体在哪,只要由镜子反射过来就可以了,我不用刻意去寻找本体,大道至简,突然想起了马斯克说的一切皆归于物理。


二、为什么要用反射

现在我们说说为啥要用到反射,反射的好处什么。我们先来讲讲跟反射相关的技术点,最开始我们学数据库连接jdbc的时候就用到过。

先看看没有用反射的数据库连接方式

方式一:

//1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());

//2.建立连接
//方法一 参数一:协议+访问数据库,参数二:用户名,参数三:密码
connection = DriverManager.getConnection("jdbc:mysql://localhost/student", "root", "password");

//3.创建statement,跟数据库打交道一定需要这个对象
st = connection.createStatement()

再来看看用反射方法实现数据库连接的

方式二:

//获取properties中的url
String url = prop.getProperty("jdbc.url");
//获取用户名
String username = prop.getProperty("jdbc.username");
//获取密码
String password = prop.getProperty("jdbc.password");

从上面的对比我们就可以看出两种方式的区别。

方式一需要在业务代码层面输入用户名和密码,一旦有配置的变动与修改需要自己去修改代码,然后重新发版上线,这种方法不方便而且成本高。试想一下如果员工A离职了,员工B接受A的代码shi山,如果配置都是在业务代码层面的,B去查找修改时会很不方便。

方式二就显得比较优雅一点,将配置与代码解耦合,所有的配置写在properties文件里,这样如果有配置变动,我们只需要在properties里修改配置就行了。


三、java中用到的反射

在java中很多地方用到了反射。比如动态代理与spring的事务底层都用到了反射。

spring事务基本原理:

spring事务本质是数据库对事务的的支持,没数据库事务支持,Spring无法提供事务功能。

以前我们纯jdbc操作的时候如果用到事务,可按照如下步骤进行:

  1. 获取连接 Connection con=DriverManager.getConnection();

  2. 开启事务 con.setAutoCommit(true/false);

  3. 执行CRUD

  4. 提交事务回滚 con.commit();

  5. 关闭连接 conn.close();

后来交给spring进行事务管理后,不用写步骤2与4的代码,而是由Spring自动完成。Spring是怎么在CRUD前后开启与关闭事务的呢?下面简单介绍下:

  1. 配置文件开启注解驱动,相关类与方法通过注解 @Transactional 标识。

  2. spring启动会解析相关bean,此时查看相关注解类与方法,并且为这些类与方法生成代理,根据@Transactional 相关参数进行配置

  3. 真正数据库层的事务提交与回滚通过binlog或者redo log实现。


声明式事务:

Spring支持声明式事务,使用注解选择需要使用事务的方法,使用@Transactional注解在方法上表明方法需要事务支持,基于AOP的实现操作。

AOP代理的两种实现:

  • jdk是代理接口,私有方法不会存在接口里,因此不会拦截到。

  • cglib是子类,private方法不会出现在子类,不会被拦截。


Java动态代理

具体有如下四步骤:

  1. 实现invocationHandler接口创建自己的调用处理器

  2. 通过Proxy类指定ClassLoader对象与interface创建动态代理类

  3. 反射机制获得动态代理类构造函数,唯一参数类型调用处理器接口类型。

  4. 构造函数创建动态代理类实例,构造时调用处理器对象作为参数传入。

CGLIB代理

  • cglib封装了asm,运行期间动态生成class

  • cglib用于AOP,jdk的proxy基于接口,cglib没限制。


原理区别

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

  1. 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP

  1. 如果目标对象实现了接口,可以强制使用CGLIB实现AOP

  1. 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如果是类内部方法直接不是走代理,这个时候可以通过维护一个自身实例的代理。


相关推荐

爱上开源之golang入门至实战第四章-切片(Slice)

前言Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可...

Go语言入门必知教程-切片

切片是一种灵活的和可扩展的数据结构,用于实现和管理数据集。切片由多个元素组成,所有元素都是相同类型的。切片是动态数组的一部分,可以根据需要进行增长和收缩。与数组一样,切片也可以索引。切片具有容量和长度...

Go语言基础-切片

切片是什么?切片是Go语言的一种数据结构。和数组相似,不过切片可以在它的结尾增加更多的元素。这样可变长度在实际编程中更为有用。声明切片切片的声明和数组也很相似,只是声明切片时不需要指定大小。例:va...

5分钟掌握GO中切片的基本使用方法

最近Golang越来越火,不少小伙伴都纷纷开始学习Golang,但对于原先为C++或者JAVA的同学,用习惯了数据、list、vector等,会对Go的切片slice不习惯,下面整理出go中slice...

揭秘 Go 切片(Slice)的秘密

当向切片添加新参数时,底层数组会发生什么变化?它会扩展以容纳更多元素吗?在这篇文章中,我们将深入探讨切片的内部工作原理,以及如何利用这些知识来进行更好的内存管理和性能优化。具体而言,我们将探索Go...

【Go语言slice详解】深入掌握Go语言中的slice类型及常用操作!

Go语言中的slice(切片)是一种非常方便的数据结构,可以动态地增加或减少其元素数量,且可以访问底层数组的任意一个子序列。本文将对Go语言中的slice进行详细的讲解。Slice的定义在Go语言中,...

掌握GO中的Slice,这就够了

最近Golang越来越火,不少小伙伴都纷纷开始学习Golang,但对于原先为C++或者JAVA的同学,用习惯了数据、list、vector等,会对Go的切片slice不习惯,下面整理出go中slice...

golang2021面向对象(26)Go语言类型内嵌和结构体内嵌

结构体可以包含一个或多个匿名(或内嵌)字段,即这些字段没有显式的名字,只有字段的类型是必须的,此时类型也就是字段的名字。匿名字段本身可以是一个结构体类型,即结构体可以包含内嵌结构体。?可以粗略地将这个...

2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内

2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内的指针方法列表?以下代码应该返回{"S1":["M1","M2"],"S...

Go语言文件和目录操作

文件和目录操作概述一、文件和目录操作概述在计算机中,文件和目录是存储数据的重要方式。在Go语言中,我们可以使用os和io/ioutil包提供的函数和结构体来进行文件和目录操作。本文将详细介绍Go语言中...

跟我一起学习go语言(五)golang中结构体的初始化方法

1、自定义一个结构体typeVertexstruct{X,Yfloat64}2、初始化方法-指针:rect1:=new(Vertex)rect2:=&Vertex...

Go复合数据类型:结构体

一种通用的、对实体对象进行聚合抽象的能力,在Go中,提供这种聚合抽象能力的类型是结构体类型,也就是struct。自定义一个新类型在Go中,我们自定义一个新类型一般有两种方法。第一种是类型定义...

Go语言基础:方法

导读在阅读本文章前,假定你具备如下能力:?已掌握结构体1.方法1.1方法的概念在理解程序中方法的概念时,我们先看看现实中的一些情况,这样相对比较好理解一些。在农村的朋友可能会知道,在医疗落后的情况...

为什么 Go 语言 struct 要使用 tags

在Go语言中,struct是一种常见的数据类型,它可以用来表示复杂的数据结构。在struct中,我们可以定义多个字段,每个字段可以有不同的类型和名称。除了这些基本信息之外,Go还提供了s...

一文带你掌握掌握 Golang结构体与方法

1.Golang结构体的概念及定义结构体是Golang中一种复合类型,它是由一组具有相同或不同类型的数据字段组成的数据结构。结构体是一种用户自定义类型,它可以被用来封装多个字段,从而实现数据的...

取消回复欢迎 发表评论: