Java中的反射

反射

Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机, Java 仍是企业和开发人员的首选开发平台。
    

课程内容的介绍

1. 反射相关的概念
2. 反射的基本操作

一、反射相关的概念

1.什么是反射
反射即反向探知,有点像考古学家根据发掘的物品来探知以前的事情。

Java 中的反射指的是程序在运行状态中
1. 对于给定的一个类 (Class) 对象,可以获取到这个类 (Class) 对象的所有的属性和方法。
2. 对于给定的一个对象 (new XXXClassName<? extends Object>), 都能够调用它的任意一个属性和方法。
   
这种动态获取类的内容以及动态调用对象的方法和属性的机制,就叫做 Java 的反射机制。
  
Java反射的优缺点:
优点:
1. 增加程序的灵活性,避免将固有的逻辑程序写死在代码里面。
2. 代码简洁,可读性增强,可提高代码的复用率。
缺点:
1. 相较于直接调用在量大的情况下反射性能下降厉害。
2. 内部暴露和安全隐患。
    

2.Class的组成
一个 Class 实例包含的内容有哪些呢?

我们在程序运行的时候获取到 Class 类型,我们要根据 Class 类型来获取相关的内容。
    

二、Class的基本操作

1.怎么获取Class对象
package com.bobo.reflection;public class ReflectionDemo01 {/*** 获取Class对象的方式* @param args*/public static void main(String[] args) throws ClassNotFoundException {// 获取Person对应的Class对象Class<Person> class1 = Person.class;System.out.println(class1);Class class2 = Class.forName("com.bobo.reflection.Person");System.out.println(class2);// 还可以通过 Person对象中的getClass方法获取Person p = new Person();Class<? extends Person> class3 = p.getClass();System.out.println(class3);// 系统提供的一些类型获取 Class对象Class<String> stringClass = String.class;Class<Integer> integerClass = int.class;Class<int[]> aClass = int[].class;System.out.println(stringClass);System.out.println(integerClass);System.out.println(aClass);Class<double[]> aClass1 = double[].class;System.out.println(aClass1);// 获取包装类对应的Class对象Class<Integer> integerClass1 = Integer.class;Class<Integer> type = Integer.TYPE;// 我要获取void 没有返回结果的 Class类型Class<Void> type1 = Void.TYPE;Class<Void> voidClass = Void.class;System.out.println(integerClass1);System.out.println(type);System.out.println(type1);System.out.println(voidClass);}
}
输出结果:
class com.bobo.reflection.Person
class com.bobo.reflection.Person
class com.bobo.reflection.Person
class java.lang.String
int
class [I
class [D
class java.lang.Integer
int
void
class java.lang.Void
2.Class对象中的常用方法
2.1 getName
获取当前类型的全类路径名称。
  
2.2 newInstance()
通过无参构造方法获取对应的实例对象,如果无参构造方法被覆盖的话,会抛出NoSuchMethodException: com.bobo.reflection.Student.() 异常。
    
2.3 getSuperclass()
获取当前类型的父类,如果没有显示的继承父类,那么返回的是 Object。
    
2.4 getInterfaces()
获取当前类型实现的所有的接口。
package com.bobo.reflection;import java.util.Arrays;public class ReflectionDemo02 {/*** 反射中的常用方法* @param args*/public static void main(String[] args) throws IllegalAccessException, InstantiationException {// 获取一个Student的类对象Class<Student> studentClass = Student.class;// getName()  完整包名+类名System.out.println(studentClass.getName());// 通过类型获取一个Student对象 newInstance() 调用的是无参的构造方法// 如果没有无参的构造方法那么会抛 NoSuchMethodException: com.bobo.reflection.Student.<init>() 异常Student student = studentClass.newInstance();System.out.println(student);// 获取当前类对象的父类对象Class<? super Student> superclass = studentClass.getSuperclass();System.out.println(superclass);System.out.println(superclass.getSuperclass());// 获取当前类型实现的接口Class<?>[] interfaces = studentClass.getInterfaces();System.out.println(Arrays.toString(interfaces));}
}
输出结果:
com.bobo.reflection.Student
static code .... 
com.bobo.reflection.Student@6d311334
class com.bobo.reflection.Person
class java.lang.Object
[interface com.bobo.reflection.InterfaceDemo01, interface com.bobo.reflection.InterfaceDemo02]
2.5 获取属性
Field getField(String name)
//返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。
Field[] getFields()
//返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。
Field getDeclaredField(String name)
//返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。
Field[] getDeclaredFields()
//返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。
package com.bobo.reflection;import java.lang.reflect.Field;public class ReflectionDemo03 {/*** 反射获取 属性的方法* @param args*/public static void main(String[] args) {Class<Student> studentClass = Student.class;// 获取相关的属性方法 Class中的每一个属性会被封装会一个Field对象// getFields() 获取当前类型和父类中的所有的public权限的字段Field[] fields = studentClass.getFields();for(Field field:fields){System.out.println(field.getName());}System.out.println("---------");// getDeclaredFields() 表示的获取当前类中的所有的 属性,包括私有的Field[] declaredFields = studentClass.getDeclaredFields();for (Field field:declaredFields){System.out.println(field.getName());}}
}
针对属性的操作: Field 的操作
package com.bobo.reflection;import java.lang.reflect.Field;public class ReflectionDemo04 {/*** 反射获取 属性的方法* @param args*/public static void main(String[] args) throws Exception{Class<Student> studentClass = Student.class;// 获取Student对象Student student = studentClass.newInstance();student.gender = "男";// 通过类型获取gender属性Field gender = studentClass.getDeclaredField("gender");System.out.println(gender.getName());// 获取对应的访问权限修饰符 1表示 public 2表示 private 4 表示 protectedSystem.out.println(gender.getModifiers());// 获取或设置属性的信息System.out.println(gender.get(student));// 修改属性值gender.set(student,"女");System.out.println(gender.get(student));// 操作私有属性Field stuNum = studentClass.getDeclaredField("stuNum");// 在反射中是不允许直接操作私有属性的,如果一定要操作必须放开权限stuNum.setAccessible(true); // 允许对私有属性的操作System.out.println(stuNum.get(student));// 修改私有属性的信息stuNum.set(student,10001);System.out.println(stuNum.get(student));// 养成好的习惯,操作属性完成后,把权限关闭stuNum.setAccessible(false);}
}
输出结果:
gender
s1
id
---------
stuNum
schoolName
className
gender
s1
2.6 获取方法
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
// 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象。
Method[] getDeclaredMethods()
// 返回包含一个数组 方法对象反射的类或接口的所有声明的方法,通过此表示 类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
Method getMethod(String name, 类<?>... parameterTypes)
//返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 类对象。
Method[] getMethods()
//返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
案例代码
package com.bobo.reflection;import java.lang.reflect.Method;public class ReflectionDemo05 {/*** 反射 获取相关方法* @param args*/public static void main(String[] args) {// 获取Student的类对象Class<Student> studentClass = Student.class;// 获取相关的方法 getMethod获取当前类及父类中的所有的共有的方法Method[] methods = studentClass.getMethods();for (Method method :methods){System.out.println(method.getName());}System.out.println("----");// getDeclaredMethods 获取的是当前类中的所有的方法 包括 privateMethod[] declaredMethods = studentClass.getDeclaredMethods();for(Method method:declaredMethods){System.out.println(method);}}
}
Method 的操作
package com.bobo.reflection;import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;public class ReflectionDemo06 {/*** Method对象* @param args*/public static void main(String[] args) throws Exception{Class<Student> studentClass = Student.class;//  获取特定的 方法 sayMethod say = studentClass.getDeclaredMethod("say", String.class);// 方法的调用  方法属性普通方法,那么我们要通过对象类调用Student student = new Student();// 第一个参数 要调用哪个对象的say方法  第二个参数 是一个参数列表  调用方法的实际参数Object obj = say.invoke(student,"bobo");System.out.println(obj);// 私有方法的调用Method eat = studentClass.getDeclaredMethod("eat");// 调用私有的方法,我们需要放开权限eat.setAccessible(true);Object obj1 = eat.invoke(student);System.out.println(obj1);// 调用完成后记得收回权限eat.setAccessible(false);// 获取方法的返回值类型System.out.println(say.getReturnType());System.out.println(eat.getReturnType());// 获取方法显示抛出的异常Class<?>[] exceptionTypes = say.getExceptionTypes();System.out.println(Arrays.toString(exceptionTypes));// 获取方法声明的参数Parameter[] parameters = say.getParameters();for (Parameter parameter : parameters){// Parameter封装的是 属性的对象System.out.println(parameter.getName()+ " " +parameter.getModifiers() + " " + parameter.toString() );}}
}
2.7 获取构造方法
Constructor<T> getConstructor(类<?>... parameterTypes)
返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
Constructor<?>[] getConstructors()
返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 类对象。
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数。
Constructor<?>[] getDeclaredConstructors()
返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组 类 。
package com.bobo.reflection;import java.lang.reflect.Constructor;
import java.util.Arrays;public class ReflectionDemo07 {/*** 反射中的构造方法* @param args*/public static void main(String[] args) {Class<Student> studentClass = Student.class;// 获取对应的构造器 getConstructors 获取的是当前类中的所有的public构造器Constructor<?>[] constructors = studentClass.getConstructors();for(Constructor constructor:constructors){System.out.println(constructor.getName() + " " + Arrays.toString(constructor.getParameters()));}System.out.println("-----------------");// 获取当前类中的所有的 构造方法 包括private 修饰的Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();for(Constructor constructor:declaredConstructors) {System.out.println(constructor.getName()+ " " + Arrays.toString(constructor.getParameters()));}}
}
Constructor 操作
package com.bobo.reflection;import java.lang.reflect.Constructor;
import java.util.Arrays;public class ReflectionDemo08 {/*** 反射 构造器的操作* @param args*/public static void main(String[] args) throws Exception {Class<Student> studentClass = Student.class;// 一个构造器Constructor<Student> c = studentClass.getDeclaredConstructor(Integer.class);System.out.println(c.getName());System.out.println(c.getModifiers());System.out.println(c.getParameterCount());// 操作private修饰的构造方法 我们同样需要放开权限c.setAccessible(true);// 通过构造器创建实例对象Student s = c.newInstance(1009);// 操作完成后同样需要关闭权限c.setAccessible(false);System.out.println(s);// 获取构造方法显示抛出的异常Class<?>[] exceptionTypes = c.getExceptionTypes();System.out.println(Arrays.toString(exceptionTypes));}
}
2.8 静态属性和静态方法操作
package com.bobo.reflection;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;public class ReflectionDemo09 {/*** 反射 静态属性和静态方法的调用* @param args*/public static void main(String[] args) throws Exception {Class<Student> studentClass = Student.class;// 静态属性的操作Field s1 = studentClass.getDeclaredField("s1");System.out.println(s1.get("s1"));s1.set(null,"hahaha");System.out.println(s1.get("s1"));// 静态方法的调用Method fun1 = studentClass.getDeclaredMethod("fun1");fun1.invoke(null);}
}

三、单例的漏洞

我们之前介绍过单例的使用,保证一个类只有一个实例存在,但是我们将了反射后发现,私有的构造器也能够被获取到,进而可以创建出很多个实例对象,这显然和我们的期望不一致。那么针对这个漏洞,我们应该怎么办呢?
Bug 还原
  
单例代码
package com.bobo.reflection;public class SingletonTest {// 声明一个静态的 单例属性private static SingletonTest instance;// 私有化构造器private SingletonTest(){System.out.println("构造方法执行了....");if(instance != null){throw new RuntimeException("实例已经创建了,不允许再创建了....");}}// 对外提供一个静态的共有的方法来获取单例对象public static SingletonTest getInstance(){if(instance == null){synchronized (SingletonTest.class){if(instance == null){instance = new SingletonTest();}}}return instance;}
}
测试代码
package com.bobo.reflection;import java.lang.reflect.Constructor;public class ReflectionDemo11 {/*** 反射 静态代码块的执行* @param args*/public static void main(String[] args) throws Exception {SingletonTest i1 = SingletonTest.getInstance();System.out.println(i1);SingletonTest i2 = SingletonTest.getInstance();System.out.println(i2);// 通过反射的方式来获取对象  获取私有的构造器Constructor<SingletonTest> c = SingletonTest.class.getDeclaredConstructor();c.setAccessible(true); //放开权限 破坏了单例的设计SingletonTest i3 = c.newInstance();SingletonTest i4 = c.newInstance();c.setAccessible(false);System.out.println(i3);System.out.println(i4);}
}
输出结果
com.bobo.reflection.SingletonTest@4554617c // 正常获取
com.bobo.reflection.SingletonTest@4554617c // 正常获取
com.bobo.reflection.SingletonTest@74a14482 // 反射获取
com.bobo.reflection.SingletonTest@1540e19d // 反射获取
我们发现造成这个 bug 的根本原因是 private 的构造方法多次执行了,那么我们就只需要在私有构造方法中添加逻辑即可。
  

如果要创建多个就会抛异常,从而不能成功。
  

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

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

相关文章

HarmonyOS4.0从零开始的开发教程12给您的应用添加弹窗

HarmonyOS&#xff08;十&#xff09;给您的应用添加弹窗 概述 在我们日常使用应用的时候&#xff0c;可能会进行一些敏感的操作&#xff0c;比如删除联系人&#xff0c;这时候我们给应用添加弹窗来提示用户是否需要执行该操作&#xff0c;如下图所示&#xff1a; 弹窗是一种…

AI全栈大模型工程师(二十八)如何做好算法备案

互联网信息服务算法 什么情况下要备案&#xff1f; 对于B2B业务&#xff0c;不需要备案。 但在B2C领域&#xff0c;一切要视具体情况而定。 如果我们自主训练大型模型&#xff0c;这是必要的。 但如果是基于第三方模型提供的服务&#xff0c;建议选择那些已获得备案并且具有较大…

Python脚本打包

一.Windows操作系统 Python脚本打包 1.cmd窗口执行如下指令&#xff1a;pip install pyinstaller C:\Users\ZhuQing>pip install pyinstaller2.执行以下指令验证pyinstaller是否安装成功&#xff08;pyinstaller&#xff09; C:\Users\ZhuQing>pyinstaller3.被打包程序…

frp配置内网穿透步骤

frp配置内网穿透步骤 1.环境准备1.1 云服务器1.2 frp包 2. frp安装2.1 server服务端设置2.2 客户端配置 实现目标通过云服务器ip:8080访问内网电脑启动的web项目localhost:8080 1.环境准备 1.1 云服务器 服务器安装centos7.9, 安全组入口方向开通 7500 7000 8080 8060端口 …

DPDK是什么?DPDK网卡更有优势吗?

近年来&#xff0c;随着数字化的推进&#xff0c;上云成为企业数字化建设的重要指标&#xff0c;用云程度持续深入。可以说&#xff0c;云时代已经来临。 应云而生的DPDK 云时代的一个典型特征&#xff0c;是数据的高速增长。据华为GIV数据&#xff0c;预计2025年全球数据量将…

【力扣】2.两数相加

2.两数相加 这是第二题&#xff0c;还行豁~。 题解&#xff1a; 首先就是对题目的理解。这里你要知道两链表中数字的排列都是逆序的&#xff0c;也就是说示例一中2-4-3他原本的数字应该是342。同理可得下面链表的意思&#xff0c;二者相加所得到的结果也是逆序的&#xff0c;…

基于Java8构建Docke镜像

基于Java8构建Docke镜像 搜索java8安装包 docker search java8 --no-trunc &#xff0c; --no-trunc展开描述信息 选择拉取 docker pull docker.io/mykro/java8-jre&#xff0c;为了减少磁盘占用&#xff0c;选择jre版本基础镜像 在宿主机创建文件夹iot&#xff0c;并把所需…

python笔记(1)安装环境

1&#xff0c;官网下载自己电脑位数的安装包 https://www.python.org/downloads/windows/ install时勾选中add to path&#xff0c;把路径自动添加到环境变量 安装pycharm就不讲了 安装后选中自己的python安装包 file-> setting->project:yourprojectname ->pyt…

FastAPI之请求头

请求头 FastAPI是一个现代、快速&#xff08;高性能&#xff09;、异步的Python Web框架&#xff0c;用于构建RESTful APIs。它基于标准的Python类型提示&#xff0c;并且可以生成交互式的API文档。 在本教程中&#xff0c;我们将学习如何使用FastAPI处理请求头&#xff08;H…

【详解优先级队列(堆)】

目录 堆的概念 堆的性质 堆的存储方式 堆的创建 堆的向下调整 向下过程(以小堆为例) 向下过程(以大堆为例) 建堆的时间复杂度O(n) 堆的插入与删除 堆的插入 向上调整建堆的时间复杂度O(nlogn) 堆的删除 常见习题 常用接口介绍 PriorityQueue的特性 Pri…

成功的云转型之路需要考虑的基本因素

云计算如今已经变得无处不在&#xff0c;并显著影响着日常生活的各个方面。然而&#xff0c;重要的是要注意云计算技术是不断发展的。最近向远程工作的转变促使企业加快数字化转型&#xff0c;更多地采用云计算服务。 即使在新冠疫情消退之后&#xff0c;云计算技术的采用也获得…

在虚拟机的Windows操作系统中:通过Jar方式若依项目,以及在外部的访问!

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Windows》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有…

IDEA之设置主题风格为eclipse风格

设置IDEA的主题风格为eclipse风格&#xff0c;步骤如下: 1.选择File->Settings 2.选择 Plugins 3.搜索 eclipse theme&#xff0c;注意是红框里的&#xff0c;点击 install 下载后就会自动设置这个主题 4.你也可以去修改主题&#xff0c;选择 Appearance&#xff0c;设置th…

jdk+zookeeper+kafka 搭建kafka集群

环境资源包&#xff1a; jdk-8u341-linux-x64.tar.gz kafka_2.12-2.2.0.tgz zookeeper-3.4.14.tar.gz 一、安装jdk 因为kafka需要Java环境&#xff0c;所以优先配置jdk环境&#xff0c;若已经配置了java环境&#xff0c;此步骤可以忽略 [rootVM-120-2-centos ~]# tar -xvf j…

对比SPI、UART、I2C通信的区别与应用

SPI、UART、I2C通信是常用的数字通信协议&#xff0c;它们在不同的场景下有不同的应用。下面&#xff0c;我将分别介绍它们的特点、区别与应用。 SPI通信 SPI通信是一种串行同步通信协议&#xff0c;它的全称为“Serial Peripheral Interface”。SPI通信是一种单主多从的通信方…

【FPGA/verilog -入门学习6】verilog频率计数器

需求 在使能信号控制下&#xff0c;计算输入脉冲的每两个上升沿之间的时钟周期数并输出&#xff0c;即输出脉冲频率的计数值 输入信号 周期性脉冲信号&#xff1a;需要做检测的脉冲频率信号 使能信号&#xff1a;高电平进行频率计数&#xff0c;低电平清零计数器 输出信号 计数…

【UE】制作物体逐渐溶解消失并且可以复原的效果

效果 步骤 1. 新建一个工程&#xff0c;创建一个Basic关卡&#xff0c;添加第三人称游戏和初学者内容包资源到内容浏览器 2. 找到并打开初学者内容包中椅子的材质“M_Chair” 将混合模式改为“已遮罩” 在材质图表中添加如下节点 此时我们就可以通过参数“FadeAmount”来控制…

Debian openmediavault 自建Nas系统共享,raid5与btrfs文件系统无损原数据扩容

一、适用环境 1、企业自有物理专业服务器&#xff0c;一些敏感数据不外流时&#xff0c;使用openmediavault自建NAS系统&#xff1b; 2、在虚拟化环境中自建NAS系统&#xff0c;用于内网办公&#xff0c;或出差外网办公时&#xff0c;企业内的文件共享&#xff1b; 3、虚拟化环…

AutoGen多代理对话项目示例和工作流程分析

在这篇文章中&#xff0c;我将介绍AutoGen的多个代理的运行。这些代理将能够相互对话&#xff0c;协作评估股票价格&#xff0c;并使用AmCharts生成图表。 我们创建对话的目的是要求代理分析特定公司的股票价格&#xff0c;并制作股票价格图表。 为了实现这一目标&#xff0c;…

Unity | Shader基础知识(第一集:unity中最简单的shader)

一、unity的shader unity写的shader并不是真正意义上的shader。 简单解释&#xff1a;真正的shader语言写起来还是麻烦的&#xff0c;unity希望大家写起来简单一点&#xff0c;于是在原来的基础上&#xff0c;给大家优化了一个语言&#xff0c;叫shaderLab&#xff0c;所以我…