关于java中的反射,我只能努力到这一步了

news/2024/5/5 9:41:26/文章来源:https://blog.csdn.net/qq_39654841/article/details/126823449

文章目录

  • 反射是什么
  • 反射的用途
  • 反射的缺点
  • 反射的基本运用
    • 获取Class 类对象
    • 类相关的反射
      • 获取包名
      • 获取supperClass
      • 获取Public成员类
      • 获取声明的类
      • 获取所有Public构造方法
      • 获取泛型参数
      • 获取实现的接口
      • 获取所有Public方法
      • 获取所有Public字段
      • 获取所有注释
      • 获取权限修饰符
    • 字段相关反射
      • 获取字段
      • 字段赋值
      • 获取字段类型
      • 获取字段声明类
    • 方法相关的反射
      • 获取方法
      • 调用方法
    • 构造方法的反射
      • 获取构造方法
      • 使用构造函数实例化对象
  • 总结

反射是java高级特性之一,常用的框架,例如:spring、mybatis等在实现的过程中都使用到了反射,所以还是非常有必要了解反射的。

反射是什么

Java反射提供了检查和修改应用程序运行时行为的能力。反射允许我们在运行时检查和操作类、接口、构造函数、方法和字段,即使类在编译时不可访问。我们还可以使用反射来实例化一个对象,调用它的方法,更改字段值。这种动态获取的信息以及动态调⽤对象的⽅法的功能称为java语⾔的反射机制。

反射的用途

可能有些人认为反射在工作中用的并不多,但其实并不是这样的,工作中处处都能见到反射的影子,比如工作中经常会通过对象 . 的时候编译器会列出该对象可以调用的方法,其实这个原理使用的也是反射。还有像Spring、Mybatis、Tomcat等通用框架或者容器底层都会大量的使用到反射。所以如果你想实现一个通用的功能,反射或许是最好的选择之一。

反射的缺点

反射的好处是允许我们在运行时对类、接口等进行一系列操作。但是它也有缺点:

  • 性能不佳: 由于 java 反射动态解析类型,它涉及扫描类路径以查找要加载的类等处理,导致性能下降。
  • 安全限制:反射需要运行时权限,这对于在安全管理器下运行的系统可能不可用。由于安全管理器,这可能会导致应用程序在运行时失败。
  • 安全问题: 使用反射我们可以访问我们不应该访问的部分代码,例如我们可以访问一个类的私有字段并更改它的值。这可能是一个严重的安全威胁,并导致应用程序行为异常。
  • 高维护: 反射代码难以理解和调试,并且在编译时无法发现代码的任何问题,因为类可能不可用,使其灵活性降低且难以维护。

反射的基本运用

以下类用于测试

BaseInterface.java

package com.example.reflection;public interface BaseInterface {public int interfaceInt=0;void method1();int method2(String str);
}

BaseClass.java

package com.example.reflection;public class BaseClass {public int baseInt;private static void method3(){System.out.println("Method3");}public int method4(){System.out.println("Method4");return 0;}public static int method5(){System.out.println("Method5");return 0;}void method6(){System.out.println("Method6");}// inner public classpublic class BaseClassInnerClass{}//member public enumpublic enum BaseClassMemberEnum{}
}

ConcreteClass.java

package com.example.reflection;public class ConcreteClass extends BaseClass implements BaseInterface{public int publicInt;private String privateString="private string";public static String staticStr = "public static string";protected boolean protectedBoolean;Object defaultObject;public ConcreteClass(int i){this.publicInt=i;}public ConcreteClass(){}private ConcreteClass(String privateString){this.privateString = privateString;}@Overridepublic void method1() {System.out.println("Method1 impl.");}@Overridepublic int method2(String str) {System.out.println("Method2 impl.");return 0;}@Overridepublic int method4(){System.out.println("Method4 overriden.");return 0;}public int method5(int i){System.out.println("Method4 overriden.");return 0;}// inner classespublic class ConcreteClassPublicClass{}private class ConcreteClassPrivateClass{}protected class ConcreteClassProtectedClass{}class ConcreteClassDefaultClass{}//member enumenum ConcreteClassDefaultEnum{}public enum ConcreteClassPublicEnum{}//member interfacepublic interface ConcreteClassPublicInterface{}
}

获取Class 类对象

java.lang.Class是所有反射操作的入口点。Class 类只有java虚拟机才能new出来,任何⼀个类都是Class 类的实例对象。要使用反射首先要获取到Class对象,Class 对象有三种方式可以获取到:

  1. 通过.class
Class<Integer> integerClass = Integer.class;
  1. 使用对象的getClass方法
Date date = new Date();
Class<? extends Date> dateClass = date.getClass();
  1. 通过java.lang.Class.forName(String fullyClassifiedClassName)方法
Class<Integer> forName = Class.forName("java.lang.Integer");

对于基本类型和数组,Class对象的获取可以通过.class的方式获取。

Class<?> booleanClass = boolean.class;
System.out.println(booleanClass.getCanonicalName()); // prints booleanClass<?> cDouble = Double.TYPE;
System.out.println(cDouble.getCanonicalName()); // prints doubleClass<?> cDoubleArray = Class.forName("[D");
System.out.println(cDoubleArray.getCanonicalName()); //prints double[]Class<?> twoDStringArray = String[][].class;
System.out.println(twoDStringArray.getCanonicalName()); // prints java.lang.String[][]

对于包装类,也可以通过静态变量TYPE获取Class对象

Class<?> doubleClass = Double.TYPE;

类相关的反射

获取包名

getPackage()方法返回这个类所在的包。该类的类加载器用于查找包。

final Package aPackage = ConcreteClass.class.getPackage();
System.out.println(aPackage);System.out.println(aPackage.getName());

结果:

package com.example.reflection
com.example.reflection

获取supperClass

getSuperclass() 如果是类对象调用的话会返回类的父类,如果此类为Object类、接口、基本类型或void,则返回null。如果此对象为数组类,则返回表示Object类的类对象。

final Class<? super Integer> superclass = Integer.class.getSuperclass();
System.out.println(superclass); // 结果:class java.lang.NumberSystem.out.println(Object.class.getSuperclass()); // 结果:nullSystem.out.println(String[][].class.getSuperclass()); // 结果:class java.lang.Object

获取Public成员类

getClasses()返回一个Class类型数组, 通过getClasses()可以获取到Class对象的所有Public类、接口和枚举类。这包括从父类继承的公共类和接口以及由类声明的公共类和接口。如果Class对象没有Public成员类、接口,又或者Class对象是个数组、基本类型、void, getClasses() 会返回一个空数组。

final Class<?>[] publicClasses = ConcreteClass.class.getClasses();
Arrays.stream(publicClasses).forEach(System.out::println);

结果:
在这里插入图片描述

获取声明的类

getDeclaredClasses()方法返回一个 Class 对象数组,返回声明为该 Class 对象表示的类成员的所有类和接口。返回的数组不包括在继承的类和接口中声明的类。

final Class<?>[] declaredClasses = ConcreteClass.class.getDeclaredClasses();
Arrays.stream(declaredClasses).forEach(System.out::println);

结果:
在这里插入图片描述

获取所有Public构造方法

getConstructors()方法返回Class对象的Public构造方法列表。

final Constructor<?>[] constructors = ConcreteClass.class.getConstructors();
Arrays.stream(constructors).forEach(System.out::println);

结果:

public com.example.reflection.ConcreteClass()
public com.example.reflection.ConcreteClass(int)

获取泛型参数

如果有与该类关联的任何泛型参数,getTypeParameters() 则返回 TypeVariable 数组。泛型参数的返回顺序与声明的顺序相同。

TypeVariable<?>[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();
for(TypeVariable<?> t : typeParameters){System.out.print(t.getName()+",");
}

结果:

K,V,

获取实现的接口

getGenericInterfaces() 方法返回由具有泛型类型信息的类实现的接口数组。
getInterfaces()方法返回类实现的所有接口

final Class<?> hashMapClass = Class.forName("java.util.HashMap");
System.out.println(Arrays.toString(hashMapClass.getGenericInterfaces()));
System.out.println(Arrays.toString(hashMapClass.getInterfaces()));

结果:

[java.util.Map<K, V>, interface java.lang.Cloneable, interface java.io.Serializable]
[interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]

获取所有Public方法

getMethods()方法返回该类的公共方法数组,包括它的父类和实现的接口的公共方法。

final Method[] allMethods = ConcreteClass.class.getMethods();
Arrays.stream(allMethods).forEach(System.out::println);

结果:

获取所有Public字段

getFields() 方法返回该类的公共字段数组,包括它的父类和实现的接口的公共字段。

public int com.example.reflection.ConcreteClass.publicInt
public static final int com.example.reflection.BaseInterface.interfaceInt
public int com.example.reflection.BaseClass.baseInt

获取所有注释

getAnnotations() 方法返回元素的所有注释。

final Annotation[] annotations = ConcreteClass.class.getAnnotations();
System.out.println(Arrays.toString(annotations));

结果:

[@java.lang.Deprecated()]

获取权限修饰符

getModifiers()方法返回类修饰符的int表示,可以使用java.lang.reflect.Modifier.toString()方法以源代码中使用的字符串格式来显示出来。

final int modifiers = ConcreteClass.class.getModifiers();
final String modifier = Modifier.toString(modifiers);
System.out.println("modifiers="+modifiers +",modifier="+modifier);

结果:

modifiers=1,modifier=public

java.lang.reflect.Modifier 权限修饰符表示的常量

public static final int PUBLIC           = 0x00000001;
/*** The {@code int} value representing the {@code private}* modifier.*/
public static final int PRIVATE          = 0x00000002;/*** The {@code int} value representing the {@code protected}* modifier.*/
public static final int PROTECTED        = 0x00000004;

字段相关反射

获取字段

getField()getDeclaredField() 方法可以获取到类的字段。不同的是,getField()获取的必须是声明了public的字段,包括父类或者实现的接口中的public字段; getDeclaredField() 只能获取的本类中定义的字段。

final Class<ConcreteClass> concreteClassClass = ConcreteClass.class;
//获取public字段
final Field interfaceInt = concreteClassClass.getField("interfaceInt");
System.out.println(interfaceInt.getName());//获取private字段
final Field privateString = concreteClassClass.getDeclaredField("privateString");
// 这一步很重要
privateString.setAccessible(true);
System.out.println(privateString.getName());

对于private类型字段一定要用setAccessible(true) 关闭访问检查,表示让字段可以被访问到,如果不关闭会报错。

字段赋值

//public 字段设值
final Field publicInt = concreteClassClass.getField("publicInt");
ConcreteClass obj = new ConcreteClass(5);
System.out.println(publicInt.get(obj)); //prints 5
publicInt.setInt(obj, 10); //setting field value to 10 in object
System.out.println(publicInt.get(obj)); //prints 10//private字段设值
Field privateField = concreteClassClass.getDeclaredField("privateString");
privateField.setAccessible(true);
ConcreteClass objTest = new ConcreteClass(1);
System.out.println(privateField.get(objTest)); // prints "private string"
privateField.set(objTest, "private string updated");
System.out.println(privateField.get(objTest)); //prints "private string updated"//static字段
final Field staticStr = concreteClassClass.getField("staticStr");
staticStr.set(null , "public static string updated");
System.out.println(staticStr.get(null));

如果字段是静态的,可以在 get() 方法中将 第一个Object参数传NULL值来调用。

获取字段类型

getType() 方法返回声明的字段类型的 Class 对象,如果字段是原始类型,则返回包装类对象。

final Class<ConcreteClass> concreteClassClass = ConcreteClass.class;
final Field publicInt = concreteClassClass.getField("publicInt");
final Class<?> type = publicInt.getType();
System.out.println(type.getCanonicalName()); //prints int

获取字段声明类

可以使用getDeclaringClass()字段对象来获取声明字段的类。

final Field interfaceInt = concreteClassClass.getField("interfaceInt");
final Class<?> declaringClass = interfaceInt.getDeclaringClass();
System.out.println(declaringClass);

方法相关的反射

获取方法

  • public方法的获取:以HashMap 的 put() 方法为例。
    可以使用getMethod()来获取类的公共方法,我们需要传递该方法的方法名和参数类型。如果在类中找不到该方法,反射 API 会在超类中查找该方法。
    Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
    //get method parameter types, prints "[class java.lang.Object, class java.lang.Object]"
    System.out.println(Arrays.toString(method.getParameterTypes()));
    //get method return type, return "class java.lang.Object", class reference for void
    System.out.println(method.getReturnType());
    //get method modifiers
    System.out.println(Modifier.toString(method.getModifiers())); //prints "public
    
  • private 方法获取
    可以使用 getDeclaredMethod() 来获取私有方法,要使用setAccessible(true)关闭访问检查
    final Class<BaseClass> baseClassClass = BaseClass.class;
    Method method = baseClassClass.getDeclaredMethod("method3", null);
    method.setAccessible(true);
    

调用方法

  • public方法调用
    可以使用 Method 对象的 invoke() 方法来调用方法,以HashMap 的put()方法为例

    Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
    Map<String, String> hm = new HashMap<>();
    method.invoke(hm, "key", "value");
    System.out.println(hm); // prints {key=value}
    
  • private方法调用
    以调用静态且没有参数的 BaseClass 的 method3()为例。

    final Class<BaseClass> baseClassClass = BaseClass.class;
    Method method = baseClassClass.getDeclaredMethod("method3", null);
    method.setAccessible(true);
    method.invoke(null, null); //prints "Method3"
    

    和静态字段一样,invoke() 方法的第一个参数object传NULL值则是调用静态方法。

构造方法的反射

获取构造方法

可以在对象的类表示上使用 getConstructor() 方法来获取特定的public构造函数。
可以在对象的类表示上使用 getDeclaredConstructor() 方法来获取特定的public构造函数。

//获取有参构造方法
Constructor<?> constructor = concreteClassClass.getConstructor(int.class);
//获取构造方法参数
System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"//获取无参构造方法
final Constructor<ConcreteClass> classClassConstructor = concreteClassClass.getConstructor();
System.out.println(classClassConstructor); // 结果:public com.example.reflection.ConcreteClass()//获取私有构造方法
final Constructor<ConcreteClass> declaredConstructor =concreteClassClass.getDeclaredConstructor(String.class);
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor); //结果:private com.example.reflection.ConcreteClass(java.lang.String)

使用构造函数实例化对象

可以在构造函数对象上使用 newInstance() 方法来实例化该类的新实例。

//获取有参构造方法
Constructor<?> constructor = concreteClassClass.getConstructor(int.class);
final Object newInstance = constructor.newInstance(111);
//获取method1 方法
final Method method1 = newInstance.getClass().getMethod("method1", null);
//调用method1方法
method1.invoke(newInstance , null);

总结

从上面所有的测试中我们可以发现,在Class对象中的方法中只要是带有Declared字段的都是获取本类中声明的方法、字段或者构造方法等,反之则是调用public的方法;在调用私有方法时要注意一点要将访问检查关闭。

参考资料:

https://www.digitalocean.com/community/tutorials/java-reflection-example-tutorial

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

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

相关文章

基于注解实现缓存的框架 -- SpringCache

目录 1、介绍 2、注解 3、 入门案例 3.1 环境准备 3.2 CachePut注解 3.3 CacheEvict注解 3.4 Cacheable注解 3.4.1 测试 3.4.2 缓存非null值 4 、集成Redis 1、介绍 Spring Cache是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解…

Java开发学习---Maven私服(二)本地仓库访问私服配置与私服资源上传下载

一、本地仓库访问私服配置 我们通过IDEA将开发的模块上传到私服&#xff0c;中间是要经过本地Maven的 本地Maven需要知道私服的访问地址以及私服访问的用户名和密码 私服中的仓库很多&#xff0c;Maven最终要把资源上传到哪个仓库? Maven下载的时候&#xff0c;又需要携带用…

花了 3000 美元,我在 SaaStr 大会学到了什么?——码农驱动的 SaaS 增长之路

Michael Yuan&#xff0c;WasmEdge Runtime 创始人SaaStr 是 SaaS 领域最具影响力的大会之一。 历经疫情阴霾&#xff0c;SaaStr 盛会2022年再次归来。尽管 SaaS 估值如过山车一般疯涨又跌落&#xff0c;但即使在当下所谓的萧条中&#xff0c;SaaS 公司和产品的收入也在以前所未…

点成分享 | 带你了解移液器的原理及其分类

移液器&#xff0c;全称叫微量移液器&#xff0c;也叫移液枪、取样枪&#xff0c;是实验室定量移取微量液体体积的精密仪器&#xff0c;一次可量取0.1μL-10mL的液体&#xff0c;可实现精准的液体配比转移&#xff0c;多用于环境检测、医学实验室、生物技术实验室、食品检测实验…

一次明白 JDBC,ORM,JPA,SpringDataJPA 之间的关系

java持久层框架访问数据库一般有两种方式&#xff1a; 以SQL为核心&#xff0c;封装JDBC操作&#xff0c;如&#xff1a;MyBatis以java实体类为核心&#xff0c;将实体类和数据库表之间映射的ORM框架&#xff0c;比如&#xff1a;Spring Data JPA和Hibernate 接下来就是详细的…

青岛大学数据结构与算法——第4章

一 概述 串数组广义表 二 串 串定义&#xff1a;定义、串名、串值、串长、子串/真子串、字符位置、空格串 案例&#xff1a;病毒感染检测 串类型定义、存储结构及其运算 定义&#xff1a;ADT String 操作&#xff1a;strAssign、strCompare、strLength、concat、其他 存储…

39. 组合总和

39. 组合总和题目dfs思路一&#xff1a;dfs思路二&#xff1a;题目 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这…

相关性分析热力图(PythonMatlab代码实现)

目录 1 热力图 1.1 简介 1.2 语法 2 算例1&#xff08;Python代码实现&#xff09; 2.1 算例 2.2 Python代码 2.3 运行结果 3 算例2&#xff08;Python代码实现&#xff09; 4 算例3&#xff08;Python代码实现&#xff09; 4.1 算例 4.2 Python代码 4.3 运行结果 5…

Sovit3D智慧园区:数字孪生园区大屏一体化管理平台

建设背景 随着全球物联网、移动互联网、云计算、大数据等新一轮信息技术的迅速发展和深入应用&#xff0c;推动产业升级和发展数字经济成为重要发力点。而产业园区作为产业升级转型的重要载体&#xff0c;建设智慧园区的需求高速增长。智慧园区在加强信息基础设施建设的同时&a…

网络编程-TCP

软件结构分类 C/S结构 &#xff1a;全称为Client/Server结构&#xff0c;是指客户端和服务器结构。常见程序有&#xff31;&#xff31;、迅雷等软件 B/S结构 &#xff1a;全称为Browser/Server结构&#xff0c;是指浏览器和服务器结构。常见浏览器有谷歌、火狐等 网络编程三要…

Unity Editor 扩展入门1

教程来源:https://www.youtube.com/watch?v=491TSNwXTIg&t=204s 一个点击物体修改材质颜色的简单editor扩展工具 using UnityEngine; using UnityEditor;public class ExampleWindow : EditorWindow {[MenuItem("Window/Colorizer")]public static void ShowWi…

入行数字IC验证后会做些什么?需要哪些必备技能?

想必大家眼中的验证工程师就是整天对着电脑敲代码&#xff0c;这是大家对这个岗位的固定印象。其实真实情况并不是这样&#xff0c;那么入行数字IC验证后会做些什么&#xff1f;需要哪些必备技能&#xff1f;下面就一起来了解一下吧。 什么是IC验证工程师&#xff1f; 回答这…

15天深度复习JavaWeb的详细笔记(四)——HTML、CSS

Demo04-HTML、CSS 1&#xff0c;HTML 1.1 介绍 HTML 是一门语言&#xff0c;所有的网页都是用HTML 这门语言编写出来的&#xff0c;也就是HTML是用来写网页的&#xff0c;像京东&#xff0c;12306等网站有很多网页。HTML(HyperText Markup Language)&#xff1a;超文本标记语…

阿里云 window下 nginx 安装https证书的配置。

首先我这里使用的是阿里云免费的https证书。 免费证书可以申请20个&#xff0c;每个的有效期为1年。 我这里使用的是nginx部署&#xff0c;所以下载nginx的 证书压缩包 下载下来之后解压&#xff0c;有两个文件一个是&#xff0c; 一个是xxx.pem ,另一个是xxxx.key. nginx 配…

企业文件加密系统价格—公司文件加密系统多少钱?

企业文件加密系统多少钱&#xff1f;怎么收费&#xff1f;一般是根据需要购买的台数进行收费的。 现在市面上有很多做文件加密系统的厂商&#xff0c;每家收费标准都不一样&#xff0c;在百度搜索文件加密系统的价格&#xff0c;就会发现价格有几百到1000/台的不等。企业文件加…

详细讲解FuzzBench如何添加新的Fuzzer

最近几天一直在弄FuzzBench添加新的fuzzer&#xff0c;在添加过程中遇到各种问题&#xff0c;在此做详细记录。 拉取fuzzbench到本地 这一部分可以直接参考此链接FuzzBench预备条件 1.拉取代码到本地 git clone https://github.com/google/fuzzbench cd fuzzbench git submo…

我上线了一个炫酷的项目实战教程网站,主流技术一网打尽~

之前经常遇到小伙伴问我&#xff0c;之前写的某篇技术文章在哪里。又或者是拿着很早以前的部署文档问我&#xff0c;按这个文章怎么部署不起来。其实他们如果上过我的实战教程网站的话&#xff0c;估计就不会有这些问题了&#xff0c;我的原创文章基本都会同步上去。今天和大家…

孙宇晨:区块链行业势必迎来光明的未来

近日&#xff0c;波场TRON创始人孙宇晨受邀在米尔肯研究院&#xff08;Milken Institute&#xff09;官方网站上发表了题为《区块链行业势必迎来光明的未来》的署名文章。孙宇晨在文章中表示&#xff0c;作为一种新兴的颠覆性技术&#xff0c;加密行业的发展之路并非一帆风顺。…

Fat Tree 分析

本文是源于USTC Advance Computer Network 的课程内容做的总结 论文来源&#xff1a;A scalable, commodity data center network architecture 本文将分析Fat Tree的 拓扑结构、编址方案和路由算法三个方面。 拓扑结构 该文章中从传统数据中心通信的问题提出了FatTree的拓扑…

机器学习——聚类(K-Means)

机器学习——聚类(K-Means)那是什么 无监督学习——聚类聚类是基于相似对象将一组对象分组为类/类别的过程。聚类是一部分 无监督学习 .这种方法通常用于确定业务决策,特别是在基于来自集群的数据预测来预测正确的业务策略时。聚类还可用于异常检测、客户细分和改善客户服务…