一文搞懂反射,还有谁不懂,直接甩给他

Hi,大家好,我是抢老婆酸奶的小肥仔。

反射,在我们日常开发中无时无刻,被大量运用在框架代码和工具代码中,反射可以通俗点讲就是一个类的自我剖析,通过反射可以获取到这个类所有信息,包括:属性,属性值,方法等等。

我们今天来初探下java中的反射,希望对大家有所帮助,开撸!

1、反射概念

Java反射机制:即在运行状态中,任意一个类,都能够知道这个类所有属性和方法;任意一个对象,都能够调用他的方法和属性。

1.1 反射流程

在java中,我们编写的类在编译时,会编译成.class文件,然后通过类加载器加载到JVM中,JVM会每个类创建一个Class对象,而Class对象中会保存每个的信息,例如:方法、属性等。JVM底层提供了一些native方法,让Java类获取到Class对象clz,进而获取到类的属性。

在上图中,可以获取类的对象有三种方式:

  1. 通过Object类中的getClass(),例如:实体先进行构造,然后调用getClass()。
  2. 通过对象的.class属性,即直接使用类名.class既可
  3. 通过Class.forName(),这是通过类名来获取对象,会有异常需要处理。

1.2 优缺点

优点:能够很方便的获取当前类的信息,能够创建灵活代码,更易于实现面向对象

缺点:1、反射需消耗一定的系统资源

2、破坏了封装性,可能会导致一些安全问题。

2、反射常用方法

在java.lang.reflect包下面,我们会看到定义的很多类。在日常开发中,大多数我们用不到,常用的也就是那么几个,如:Field(类的域/属性)、Method(类的方法)、Constructor(类的构造器)等,下面我们来看看这些类中定义的哪些方法。

准备工作:

创建两个实体类

/*** @author: jiangjs* @description:* @date: 2023/6/30 9:41**/
@Data
public class Animal {private String name;private Integer age;private String color;@Datapublic static class OtherAnimal{private String other;}
}/*** @author: jiangjs* @description:* @date: 2023/6/30 9:51**/
@EqualsAndHashCode(callSuper = true)
@Data
public class Dog extends Animal{/*** 品种*/private String breed;@Datapublic static class OtherDog{private String other;}
}

其中Dog继承了Animal,是Animal的子类。

2.1 Class类方法

方法名描述
forName(String className);获取当前类的对象
getClassLoader();获取当前类的加载器
getClasses();获取当前类及其父类中的所有公共类和接口的对象
getDeclaredClasses();获取当前类中所有类和接口类的对象
newInstance();创建类的实例
getName();获取当前类的完整路径名称
getSimpleName();获取类的名称
getPackage();获取当前类的包
getSuperclass();获取当前类的父类的对象
getInterfaces();获取当前类的实现类或接口对象

我们来看下代码实现:

public static void main(String[] args) throws IllegalAccessException, InstantiationException {Class<Animal> clazz = Animal.class;Class<Dog> dogClazz = Dog.class;//获取类加载器ClassLoader classLoader = clazz.getClassLoader();log.info("类加载器:" + classLoader);//获取当前类及其父类中的所有公共类和接口的对象Class<?>[] classes = dogClazz.getClasses();for (Class<?> aClass : classes) {log.info("获取的类及父类中的类对象:" + aClass);}//获取当前类中所有类和接口类的对象Class<?>[] declaredClasses = dogClazz.getDeclaredClasses();for (Class<?> aClass : declaredClasses) {log.info("获取的类对象:" + aClass);}//创建类的实例Dog dog = dogClazz.newInstance();dog.setName("橙橙");log.info("创建类的实例:" + dog.getName());//获取当前类的完整路径名称String name = dogClazz.getName();log.info("获取当前类的完整路径名称:" + name);//获取类的名称String simpleName = dogClazz.getSimpleName();log.info("获取类的名称:" + simpleName);//获取当前类的包Package aPackage = dogClazz.getPackage();log.info("获取当前类的包:" + aPackage);//获取当前类的父类的对象Class<? super Dog> superclass = dogClazz.getSuperclass();log.info("获取当前类的父类的对象:" + superclass);//获取当前类的实现类或接口Class<?>[] interfaces = dogClazz.getInterfaces();for (Class<?> anInterface : interfaces) {log.info("获取当前类的实现类或接口:" + anInterface);}}

输出:

2.2 Field属性方法

很多时候我们都是需要获取属性及属性值来做处理,特别是使用AOP时。

方法名描述
getField(String name);根据名称获取属性对象,属性值必须是公有的
getFields();获取该类所有公有的属性对象
getDeclaredField(String name);根据名称获取当前类的属性对象
getDeclaredFields();获得该类所有属性对象

代码实现:

//属性//根据名称获取属性对象Field breedField = dogClazz.getField("breed");log.info("根据名称获取属性对象:" + breedField);//获取该类所有公有的属性对象Field[] fields = dogClazz.getFields();for (Field field : fields) {log.info("获取该类公有的属性对象:" + field);}//获取当前类及父类指定的属性对象Field nameField = clazz.getDeclaredField("name");log.info("获取当前类及父类指定的属性对象:" + nameField);//获得该类所有属性对象Field[] clzFields = clazz.getDeclaredFields();for (Field field : clzFields) {log.info("获得该类所有属性对象:" + field);}

输出:

在属性对象中,也提供了一些方法:

  1. equals(Object obj) :属性与obj是否相等,相等则返回true,否则返回false。
  2. get(Object obj) :获取obj中对应的属性值。
  3. set(Object obj,Object value) :给obj中的属性赋值。

上述提供的属性方法中只能获取到当前类的属性,很多时候我们还需要知道当前类的父类有哪些属性。因此我们可以结合类中的getSuperclass()来获取。代码如下:

private static List<Field> getAllFields(Class<?> clazz) {List<Field> allFields = new ArrayList<>();while (Objects.nonNull(clazz)){Field[] declaredFields = clazz.getDeclaredFields();allFields.addAll(Arrays.asList(declaredFields));clazz = clazz.getSuperclass();}return allFields;
}

测试: 获取Dog实体及父类的属性。

List<Field> allFields = getAllFields(dogClazz);
for (Field field : allFields) {log.info("获取dog当前类及父类属性:" + field);
}

2.3 Method方法

方法名描述
getMethod(String name, Class…<?> parameterTypes)根据名称获取当前类及父类中的公有方法。name:方法名称,parameterTypes:参数类型,如String.class等,没有参数可以不填
getMethods();获取当前类及其父类的所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes)根据名称获取当前类的方法
getDeclaredMethods();获取当前类中所有的方法
getConstructor(Class…<?> parameterTypes)获取当前类的公有构造方法
getConstructors()获取当前类所有公有的构造方法
getDeclaredConstructor(Class…<?> parameterTypes)获取当前类及父类的所有构造方法
getDeclaredConstructors()获得当前类所有构造方法

代码实现:

 //method方法
Method setName = dogClazz.getMethod("setName",String.class);
log.info("获取setName方法:" + setName);Method method = dogClazz.getDeclaredMethod("getBreed");
log.info("获取getBreed方法:" + method);
Method[] declaredMethods = dogClazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {log.info("获取Dog所有方法:" + declaredMethod);
}Constructor<Dog> constructor = dogClazz.getConstructor(String.class);
log.info("获取带参数构造方法:" + constructor);
Constructor<?>[] constructors = dogClazz.getConstructors();
for (Constructor<?> con : constructors) {log.info("获取Dog下所有构造方法:" + con);
}
Method[] methods = dogClazz.getMethods();
for (Method dogMethod : methods) {log.info("获取Dog及父类所有方法:" + dogMethod);
}

输出:

在Method方法中,可以使用invoke(Object obj, Object... args) 来指定obj对象中参数相同的方法。

2.4 Annotation注解方法

方法名描述
getAnnotation(Class annotationClass)获取当前类及其父类与参数类型匹配的公有注解对象
getAnnotations();获取当前类所有公有注解对象
getDeclaredAnnotation(Class annotationClass)获取当前类及其父类与参数类型匹配的所有注解对象
getDeclaredAnnotations()获取当前类中所有注解对象
isAnnotation()验证当前类是否为注解类型,是则返回true,否则返回false
isAnnotationPresent(Class<? extends Annotation> annotationClass)属性中指定类型是否为注解类型,是则返回true,否则返回false

代码实现:

 //Annotation注解
NotBlank annotation = dogClazz.getDeclaredField("breed").getAnnotation(NotBlank.class);
log.info("获取Dog中Data注解:" + annotation);
String message = annotation.message();
log.info("获取注解信息:" + message);
boolean isAnnotation = dogClazz.isAnnotation();
boolean notBlank = NotBlank.class.isAnnotation();
log.info("验证是否为注解类型的类:dog," + isAnnotation+ ";notBlank:" + notBlank);
boolean present = dogClazz.getDeclaredField("breed").isAnnotationPresent(NotBlank.class);
log.info("指定NotBlank是否为注解类型:" + present);

输出:

2.5 其他方法

除了上述我们常用的一些方法外,还有些不常用的,我们也整理下,以备不时之需吧。

方法名描述
isAnonymousClass()当前类是否为匿名类。是则返回true,否则返回false
isArray()是否为数组类型。是则返回true,否则返回false
isEnum()是否为枚举类型。是则返回true,否则返回false
isInstance(Object obj)obj是否该类的实例。是则返回true,否则返回false
isInterface()是否为接口。是则返回true,否则返回false
isMemberClass()是否为内部类
isLocalClass()是否为局部类

代码实现:

//其他
boolean anonymousClass = dogClazz.isAnonymousClass();
log.info("当前类是否为匿名类:" + anonymousClass);
boolean array = dogClazz.isArray();
log.info("是否为数据类型:" + array);
boolean isEnum = dogClazz.isEnum();
log.info("是否为枚举类型:" + isEnum);
boolean instance = dogClazz.isInstance(dog);
log.info("obj是否该类的实例:" + instance);
boolean anInterface = dogClazz.isInterface();
log.info("是否为接口:" + anInterface);
Class<?>[] clazzs = dogClazz.getDeclaredClasses();
for (Class<?> aClass : clazzs) {log.info("类名:"+aClass.getSimpleName() + ";是否为内部类:" + aClass.isMemberClass());log.info("类名:"+aClass.getSimpleName() + ";是否为局部类:" + aClass.isLocalClass());
}

输出:

上述就是我理解的反射及常用的方法。其实只需要多敲敲代码,很多东西都会变得熟练。

一言以蔽之:反射就是通过jdk提供的方法从JVM中获取保存的类的各种属性的操作。

谢谢大家听我唠叨。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

美国政府发布新的国际网络空间和数字政策战略(上)

文章目录 前言一、战略内容介绍二、数字团结的含义三、如何建立数字团结前言 美国务院5月6日正式发布《美国国际网络空间和数字政策战略:迈向创新、安全和尊重权利的数字未来》,旨在指导国际社会参与技术外交并推动《美国国家安全战略》和《美国国家网络安全战略》。 美国务…

创新指南|将会话式AI聊天机器人纳入PLG增长战略

想象一个繁荣的数字城市广场&#xff0c;志同道合的人们在这里分享他们的激情、经验和知识。想象一个将房东与旅行者、顾客与司机、人们与他们喜爱的品牌无缝连接起来的平台。在这个世界里&#xff0c;用户交流促进增长&#xff0c;社区成为推动力。 如果您的应用程序天生不符…

视频编辑软件pitivi基本功之创建标题片段

视频编辑软件pitivi基本功之创建标题片段 台式机的系统是openSUSE-Leap-15.5-DVD-x86_64 一、素材来源 《视频编辑软件pitivi基本功之使用SSR录制电脑屏幕》 https://blog.csdn.net/weixin_42145772/article/details/138597608?spm1001.2014.3001.5502 根据上面文章的方法得…

考了PMP后,NPDP到底还有没有必要考?NPDP通关宝典来啦!

NPDP和PMP相比&#xff0c;两者的相同点都是由美国发起的&#xff0c;都是管理行业的证书。区别也很大&#xff0c;PMP是项目经理国际认证证书&#xff0c;NPDP是产品经理认证证书&#xff0c;不过PMP已经由外专局引入国内二十多年了&#xff0c;在市面上知名度更高&#xff0c…

【数据结构】第五讲:栈和队列

个人主页&#xff1a;深情秋刀鱼-CSDN博客 数据结构专栏&#xff1a;数据结构与算法 源码获取&#xff1a;数据结构: 上传我写的关于数据结构的代码 (gitee.com) 目录 一、栈 1.栈的定义 2.栈的实现 a.栈结构的定义 b.初始化 c.扩容 d.入栈 e.出栈 f.打印 g.取栈顶元素…

Java医院绩效管理应用系统源码java+ maven+ avue 公立医院绩效考核管理系统源码 支持二开

Java医院绩效管理应用系统源码java maven avue 公立医院绩效考核管理系统源码 支持二开 医院绩效管理系统解决方案紧扣新医改形势下医院绩效管理的要求&#xff0c;以“工作量为基础的考核方案”为核心思想&#xff0c;结合患者满意度、服务质量、技术难度、工作效率、医德医风…

Java入门基础学习笔记16——运算符

package cn.ensource.operator;public class OperatorDemo1 {public static void main(String[] args) {// 目标&#xff1a;掌握基本的算术运算符的使用int a 10;int b 2;System.out.println(a b);System.out.println(a - b);System.out.println(a * b); // 20System.out.…

Pandas DataFrame行迭代:初学者指南

在数据分析中&#xff0c;Pandas是一个强大的Python库&#xff0c;它提供了快速、灵活以及表达力强的数据结构&#xff0c;旨在使“关系”或“标签”数据的操作既简单又直观。对于初学者来说&#xff0c;理解如何迭代DataFrame的行是一项基础但重要的技能。本文将通过通俗易懂的…

一文讲透亚马逊云三层架构

关于三层架构&#xff0c;我们有很多想说的话&#xff1a; &#xff08;以下内容以下都在VPC中&#xff09; cloudfront做CDN加速网关规划S3做静态网站托管APIGateway作为统一网关入口认证/限流Lambda 作为传统后端&#xff0c;并发&#xff0c;底层架构Redis缓存DDB作为持久化…

CH340 RTS DTR引脚编程驱动OLED

运行结果 硬件连接&#xff08;在连接线上串接300R电阻&#xff09; 下面是c#实现代码 using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks;using uint8 System.Byt…

5月10日学习记录

[NCTF2019]True XML cookbook(xxe漏洞利用) 这题是关于xxe漏洞的实际应用&#xff0c;利用xxe漏洞的外部实体来进行ssrf探针内网的主机 和[NCTF2019]Fake XML cookbook的区别就在于xxe漏洞的利用方向&#xff0c;一个是命令执行&#xff0c;一个是SSRF 看题&#xff0c;打开…

26、Flink 的状态数据结构升级

状态数据结构升级 a&#xff09;概述 Flink 流应用通常被设计为永远或者长时间运行&#xff0c;与所有长期运行的服务一样&#xff0c;应用程序需要随着业务的迭代而进行调整&#xff0c;应用所处理的数据 schema 也会随着进行变化。 升级状态类型的数据 schema &#xff0c…

【redis】Redis五种常用数据类型和内部编码,以及对String字符串类型的总结

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

ORACLE ODAX9-2的一个误告警Affects: /SYS/MB的分析处理

在运维的多套ORACLE ODAX9-2版本&#xff0c;都遇到了一个计算节点的告警&#xff1a;Description: The service Processor poweron selftest has deteced a problem. Probabity;:100, UulD:cd1ebbdf-f099-61de-ca44-ef646defe034, Resource:/SYS/MB,&#xff1b;此告警从描述上…

React 第三十一章 虚拟DOM

面试题&#xff1a;什么是虚拟DOM&#xff1f;其优点有哪些&#xff1f; 标准且浅显的答案 虚拟dom本质上就是一个普通的 JS 对象&#xff0c;用于描述视图的界面结构 虚拟 DOM 最早是由 React 团队提出来的&#xff0c;因此 React 团队在对虚拟 DOM 的定义上面有绝对的话语权。…

【Linux】基础命令,文件处理,用户,vim编辑器,文件压缩

常用命令及参数&#xff1a;dir表示文件夹&#xff0c;file表示文件&#xff08;file可表示其他目录下的文件&#xff09; pwd命令&#xff1b;查看当前所属文件夹&#xff08;print working directory&#xff09; ls [选项] dir&#xff1b;查看当前、指定文件夹目录内容&am…

以太网技术介绍

随着通信和计算机技术的不断发展&#xff0c;无论是骨干网还是接入网&#xff0c;以太网都已成为应用场景最多&#xff0c;应用范围最广泛的技术之一。对于初次应用以太网的读者&#xff0c;本文主要给出以太网技术的基础知识&#xff0c;并对以太网涉及的部分协议进行简要说明…

硕博电子洗扫车电控系统:让洗扫更智能,更高效!

硕博电子洗扫车电控系统以7寸显示屏、移动控制器、操作面板为核心&#xff0c;具有8~ 32V DC宽压输入、耐震动、抗冲击、耐腐蚀、高防护等特性。三个主要核心元件与副发动机、底盘和、GPS 模块等均通过CAN 总线进行通信&#xff0c;交互数据&#xff0c;通信稳定可靠&#xff0…

镭速实现利用Libarchive实现高效、智能的文件传输和管理

在前一篇报道中&#xff0c;我们阐述了Libarchive这一开源库的强大功能&#xff0c;它专门用于处理归档文件。通过整合Libarchive&#xff0c;镭速在包括Windows和Linux在内的多个操作系统上提供了在线解压缩服务&#xff0c;为企业构建了一个既强大又安全的文件传输系统&#…

常见排序算法——希尔排序

基本原理 希尔排序在插入排序的基础之上&#xff0c;将待排序序列分成组&#xff0c;分成 gap 个组&#xff0c;组的数量通过 length / 2 获得&#xff0c;比如6个元素的序列&#xff0c;那么就是 3 个组&#xff0c;每个组两个元素&#xff0c;然后将每个组的元素进行插入排…