Java中的反射原理,为什么要使用反射以及反射使用场景

什么是反射

反射是框架的灵魂

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

在java中获取字节文件的方式有三种

  1. 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
  2. Object(对象) ——> getClass();
  3. 通过Class类的静态方法:forName(String className)(常用)
 		//方法一Class<CarEntity> carEntityClass0 = CarEntity.class;//方法二CarEntity carEntity =new CarEntity();Class carEntityClass1 =carEntity.getClass();//方法三Class carEntityClass2 = Class.forName("com.example.demo3.Entity.CarEntity");//判断获取到同一个类的Class对象是否是同一个System.out.println(carEntityClass0 == carEntityClass1);System.out.println(carEntityClass1 == carEntityClass2);System.out.println(carEntityClass0 == carEntityClass2);

上面的例子得到的结果,是三个true,由此我们得到了第一个定理:
在运行期间,一个类,只有一个Class对象产生

三种方式常用第三种,第一种需要导入类的包,依赖太强,不导包就抛编译错误。第二种对象都有了还要反射干什么。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法(框架中都是用的第三种)。

好,现在我们得到了Class对象了,又有什么用呢,Class对象是什么呢,能做什么呢?

在此之前我们先了解一下正常情况下我们new一个对象的时候,jvm底层做了什么事情。

首先要搞明白一件事情,jvm能读懂我们的java代码吗?不能!

那jvm是靠读取什么东西来运行程序的呢?.class文件!
请放大看下图。。。。

也就是说,我们现在可以不通过JVM的编译直接获取到jvm运行时需要的Class对象!
也就是说!我们是不是可以通过对Class对象进行修改而改变CarEntity这个类原本在jvm里运行的逻辑!从而达到一系列不可告人的目的呢?

没错,我们可以,这就像同桌张三把作业给我让我帮忙交给老师,然后我直接把他的作业全部撕了然后告诉老师(JVM):张三这个崽种没做作业!(这是后面要讲的代理模式)。在当前的反射篇章我们可以理解为,我可以得到张三的作业的所有答案,然后我拿着自己用!

好,例子来了,顺便我们熟悉一下Class对象的常用API,面试的时候就可以装逼了

先看看我们的实体类是什么样子的

	//一个public 属性public String name;//一个private 属性private String price;//一个public 构造方法public CarEntity(String name, String price) {this.name = name;this.price = price;}//一个private 构造方法private CarEntity(String name){this.name = name;}//以下全都是public 的GET,SET方法public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPrice() {return price;}public void setPrice(String price) {this.price = price;}

好!开始测试!

    public static void main(String[] args) throws Exception {//获取CarEntity的Class对象Class carEntityClass = Class.forName("com.example.demo3.Entity.CarEntity");System.out.println("获取所有的Public的成员变量");Field[] field = carEntityClass.getFields();for (Field field1 : field) {System.out.println(field1.getName());}System.out.println("获取所有的的成员变量,不管你是Public,Private,Protected还是Default ");Field[] field01 = carEntityClass.getDeclaredFields();for (Field field1 : field01) {System.out.println(field1.getName());}}

看看结果是什么

获取所有的Public的成员变量
name
获取所有的的成员变量,不管你是Public,Private,Protected还是Default 
name
price

好,再来一个

        System.out.println("获取所有的Public的构造方法");Constructor[] constructors = carEntityClass.getConstructors();for (Constructor constructor1 : constructors) {System.out.println(constructor1);}System.out.println("获取所有的的构造方法,不管你是Public,Private,Protected还是Default ");Constructor[] constructors01 = carEntityClass.getDeclaredConstructors();for (Constructor constructor1 : constructors01) {System.out.println(constructor1);}

结果:

获取所有的Public的构造方法
public com.example.demo3.Entity.CarEntity(java.lang.String,java.lang.String)
获取所有的的构造方法,不管你是Public,Private,Protected还是Default 
public com.example.demo3.Entity.CarEntity(java.lang.String,java.lang.String)
private com.example.demo3.Entity.CarEntity(java.lang.String)

发现了没?我们现在只需要一个类的全路径,我们就可以掌握这个类的所有情况!

上面的例子我们也发现了Class对象的APi的规律,只要加了Declared的Get方法,我们就能够“非法”地获取到这个类的编写者本来不愿意公布出来的属性!

当然我们还可以获取到这个类的所有普通方法:

        System.out.println("获取所有的方法");Method[] methods = carEntityClass.getMethods();for (Method method : methods) {System.out.println(method.getName());}
获取所有的方法
getName
setName
getPrice
setPrice
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll

我们再继续深入一点点,大家耐心看。

我们先给我们的Car类补上刚刚忘掉的无参构造方法

public CarEntity() {}

然后开始我们的测试(是干嘛呢?通过反射调用目标类的方法!)

 //获取CarEntity的Class对象Class<?> carEntityClass = Class.forName("com.example.demo3.Entity.CarEntity");//通过Class对象获取到具体的CarEntity实例(需要无参构造方法!!!!)CarEntity carEntity = (CarEntity)carEntityClass.newInstance();System.out.println("获取SetName方法");//第一个参数:方法名称,第二个参数:方法形参的类型Method method = carEntityClass.getDeclaredMethod("setName",String.class);//第一个参数,对象类型carEntity,第二个参数是我这里调用方法时传的参数method.invoke(carEntity,"张三");System.out.println("获取getName方法");Method method2 = carEntityClass.getDeclaredMethod("getName",null);String name = (String) method2.invoke(carEntity,null);System.out.println(name);
获取SetName方法
获取getName方法
张三

我们现在居然只通过一个类的路径,获取到了这个类的所有信息,并且还能调用他的所有方法。

现在是不是大概明白了,为什么一开始说反射是框架的灵魂。举个最简单的例子,Spring的注解式事务是怎么实现的?? 现在我们大概可以猜猜了(只是猜想):

  1. 通过注解,我们在项目启动的时候可以获取所有打了注解的类或方法
  2. 通过反射,我们可以获取类的所有信息或方法的所有信息
  3. 通过反射,我们可以在方法的前后加上事务回滚相关的代码,然后通过上面例子中的invoke方法调用目标方法
  4. 这个过程我不需要知道你这些类或方法是干嘛的,你的一切与我无关

框架就是这样诞生的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/309174.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用C语言函数求x^y-------(C每日一编程)

编写函数,计算x^y&#xff08;x,y都是整数&#xff09;。 参考代码&#xff1a; int fun(int x, int y) {int k 1, i;for (i 1; i < y; i)k k * x;return k; } int main() {int x, y;scanf("%d%d", &x, &y);printf("%d", fun(x, y));retur…

Leetcode算法系列| 10. 正则表达式匹配

目录 1.题目2.题解C# 解法一&#xff1a;分段匹配法C# 解法二&#xff1a;回溯法C# 解法三&#xff1a;动态规划 1.题目 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。 1.‘.’ 匹配任意单个字符 2.‘.’ 匹配任意单个字…

JavaSE语法之十二:Object类

文章目录 一、概念二、获取对象信息三、对象比较equals方法四、hashcode方法 一、概念 Object是Java默认提供的一个类。Java里面除了Object类&#xff0c;所有的类都是存在继承关系的&#xff0c;默认会继承Object父类&#xff0c;即所有的类的对象都可以使用Object的引用进行…

算法分析与设计基础

一、绪论 1.算法的概念及特征 1.1 定义&#xff1a; 算法是指求解某个问题或是某类问题的一系列无歧义的指令&#xff0c;也就是说&#xff0c;对于符合一定规范的输入&#xff0c;能够在有限时间内获得所要求的输出。 1.2 特征&#xff1a; 输入&#xff1a;算法中的各种运…

最新版 BaseRecyclerViewAdapterHelper4:4.1.2 最简单的QuickViewHolder用法,最简洁的代码,复制可用

为了照顾新手&#xff0c;尽量详细&#xff0c;高手勿喷&#xff01;&#xff01;&#xff01; 怕麻烦的话可以直接下载源码&#xff1a;https://download.csdn.net/download/ERP_LXKUN_JAK/88678044?spm1001.2014.3001.5503 先看文件结构&#xff0c;是不是很简单 AndroidSt…

用anaconda下载安装pytorch1.8.2+cudatoolkit11.1

用anaconda下载安装pytorch1.8.1cudatoolkit11.1 设置清华镜像下载&#xff1a; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda con…

小程序面试题 | 17.精选小程序面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【2023】通过docker安装hadoop以及常见报错

&#x1f4bb;目录 1、准备2、安装镜像2.1、创建centos-ssh的镜像2.2、创建hadoop的镜像 3、配置ssh网络3.1、搭建同一网段的网络3.2、配置host实现互相之间可以免密登陆3.3、查看是否成功 4、安装配置Hadoop4.1、添加存储文件夹4.2、添加指定配置4.3、同步数据 5、测试启动5.1…

Linux:apache优化(3)—— 页面缓存时间

作用&#xff1a;通过 mod_expires 模块配置 Apache&#xff0c;使网页能在客户端浏览器缓存一段时间&#xff0c;以避免重复请求&#xff0c;减轻服务端工作压力。启用 mod_expires 模块后&#xff0c;会自动生成页面头部信息中的 Expires 标签和 CacheControl 标签&#xff0…

华为商城秒杀时加密验证 device_data 的算法研究

前言 之前华为商城放出 Mate60 手机时, 想给自己和家人抢购一两台&#xff0c;手动刷了好几天无果后&#xff0c;决定尝试编写程序&#xff0c;直接发送 POST 请求来抢。通过抓包和简单重放发送后&#xff0c;始终不成功。仔细研究&#xff0c;发现 Cookie 中有一个名为 devic…

Solana主流钱包盘点和评测:Phantom,Bitget钱包,Ledger等

Solana绝对是今年加密货币界的大红人&#xff01;大家都在热烈讨论这个项目&#xff0c;想象它会给加密世界的未来带来怎样的变革。是不是觉得新晋的加密爱好者们都很酷&#xff1f;他们正迈出探索这个领域的第一步&#xff0c;寻找合适的钱包。无论是准备长期持有Solana&#…

【第4期】Springboot集成阿里云对象存储OSS+Vue+Iview文件上传组件

本期简介 文件上传是非常常见的功能&#xff0c;本期要实现的功能是将文件存储到阿里云分布式对象存储OSS中&#xff0c;这样做的好处是随便哪里都可以方便的展示出该图片&#xff0c;并且图片以链接形式在客户端浏览器渲染&#xff0c;流量不会经过后台&#xff0c;降低后台压…