【注解和反射】获取类运行时结构

server/2024/9/22 20:53:51/
class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

继上一篇博客【注解和反射】类加载器-CSDN博客

class="img-center">

目录

七、获取类运行时结构

测试

getFields()和getDeclaredFields()

getMethods()和getDeclaredMethods()


七、获取类运行时结构

获取类运行时结构通常指的是在Java等面向对象编程语言中,使用反射(Reflection)机制来检查类、接口、字段(Field)和方法(Method)等程序元素的能力。这种能力允许你在运行时动态地获取类的信息,并且可以调用类的方法、改变字段的值等。

在Java中,获取类运行时结构主要包括以下几个方面:

  1. 获取Class对象: 要获取类的运行时结构,首先需要获取代表该类的Class对象。这可以通过多种方式实现,例如使用.class语法、Class.forName()方法或通过对象的getClass()方法。

  2. 获取类的名称: 通过Class对象的getName()方法可以获取类的全限定名(包括包名)。

  3. 获取类的修饰符: 使用getModifiers()方法可以获取类的修饰符(如publicabstractfinal等),通常与Modifier.toString()方法结合使用以获取可读的修饰符字符串。

  4. 获取类的父类和实现的接口: 通过getSuperclass()方法可以获取类的直接父类,而getInterfaces()方法则返回当前类实现的接口数组。

  5. 获取类的字段: 使用getDeclaredFields()方法可以获取类中声明的所有字段,无论访问权限如何。而getFields()方法仅返回public字段。

  6. 获取类的方法: 类似地,getDeclaredMethods()方法返回类中声明的所有方法,而getMethods()方法仅返回public方法,包括继承自父类的方法。

  7. 获取类的构造器: 通过getDeclaredConstructors()方法可以获取类的所有构造器,而getConstructors()方法仅返回public构造器。

  8. 获取类的注解: 如果类、方法、字段等上面有注解(Annotation),可以使用getAnnotations()getDeclaredAnnotation()等方法来获取这些注解信息。

  9. 获取类的内部类和接口: 通过getDeclaredClasses()方法可以获取当前类中声明的所有内部类和接口。

  10. 判断类的特性Class类提供了一系列的方法来判断类的特性,如isInterface()isEnum()isAnnotation()isAnonymousClass()isArray()isPrimitive()等。

获取类运行时结构的能力在Java中非常强大,它允许开发者在程序运行时动态地分析和操作类,这在很多场景下都很有用,比如框架设计、单元测试、序列化和反序列化、依赖注入等。然而,使用反射也需要谨慎,因为它可能会破坏封装性,降低性能,并且使代码更加复杂和难以维护。

测试

首先,我们需要定义一个 User 类,

class="language-class="tags" href="/JAVA.html" title=java>java">class User{private String name;private int id;private int age;public User(String name, int id, int age) {this.name = name;this.id = id;this.age = age;}public User() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", id=" + id +", age=" + age +'}';}
}

在代码示例中,Test05 类有一个 main 方法,该方法执行了以下操作:

  1. 创建了一个 User 类的对象 user
  2. 通过调用 user.getClass() 获取了 User 类的 Class 对象,并将其存储在变量 c1 中。
  3. 打印了 c1 所代表的类的全名(包名 + 类名)和简单类名(仅类名)。
  4. 打印了一行分隔符 -------
  5. 获取了 c1 所代表的类声明的所有字段(不包括继承的字段),并遍历打印了每个字段的信息。
class="language-class="tags" href="/JAVA.html" title=java>java">
public class Test05 {public static void main(String[] args) throws ClassNotFoundException {User user = new User();Class c1 = user.getClass();System.out.println(c1.getName());System.out.println(c1.getSimpleName());System.out.println("-------");// Field[] fields = c1.getFields();Field[] fields = c1.getDeclaredFields();for(Field f: fields){System.out.println(f);}}
}

这里是输出结果的详细分析:

  1. System.out.println(c1.getName()); 打印了User类的完全限定名,即包括包名(如果有的话)和类名。因为User类没有指定包名,所以输出就是User

  2. System.out.println(c1.getSimpleName()); 打印了User类的简单名字,也就是不包括包名的类名,所以输出还是User

  3. 在打印了一行分隔符之后,代码通过c1.getDeclaredFields()获取了User类中声明的所有字段,包括privateprotected、默认(包私有)和public字段。在这个例子中,User类有三个private字段:nameidage。这些字段被打印出来,包括它们的访问修饰符、类型、类名和字段名。

getFields()和getDeclaredFields()

在Java的反射API中,getFields()getDeclaredFields()方法都用于获取类的字段,但它们在获取字段的范围和访问权限上有明显的区别:

  1. getFields():

    • 这个方法返回的是当前类及其所有父类(包括Object类)中声明的public字段
    • 它不包括当前类中声明的privateprotected和默认(包私有)访问级别的字段。
    • 如果当前类或其父类中没有public字段,那么这个方法将返回一个长度为0的数组。
  2. getDeclaredFields():

    • 这个方法返回的是当前类中声明的所有字段,无论它们的访问权限是什么(publicprivateprotected或默认)。
    • 它不包括父类中声明的任何字段,只查看当前类的字段。
    • 即使当前类中没有字段,这个方法也会返回一个数组,只不过数组的长度是0。

通常,如果你只对当前类的字段感兴趣,而不关心父类的字段,那么你应该使用getDeclaredFields()。同时,如果你需要访问非public字段,你也需要使用getDeclaredFields(),因为getFields()不会返回这些字段。

另外,值得注意的是,如果你使用getDeclaredFields()获取了非public字段,并且想要访问或修改这些字段的值,你需要先调用Field.setAccessible(true)来允许访问这些字段,否则会抛出IllegalAccessException异常。

getMethods()getDeclaredMethods()

现在,让我们来讨论getMethods()getDeclaredMethods()的区别:

  1. getMethods():

    • 这个方法返回当前类及其所有父类(包括Object类)中声明的所有public方法。
    • 它不包括当前类中声明的privateprotected和默认(包私有)访问级别的方法。
    • 返回的数组包含了从当前类开始,沿着继承链向上直到Object类的所有public方法。
  2. getDeclaredMethods():

    • 这个方法返回当前类中声明的所有方法,无论它们的访问权限是什么(publicprivateprotected或默认)。
    • 它不包括父类中声明的任何方法,只查看当前类的方法。
    • 即使当前类中没有方法,这个方法也会返回一个数组,只不过数组的长度是0。

与字段的情况类似,如果你只对当前类的方法感兴趣,而不关心父类的方法,那么你应该使用getDeclaredMethods()。同时,如果你需要访问非public方法,你也需要使用getDeclaredMethods(),因为getMethods()不会返回这些方法。

同样值得注意的是,如果你使用getDeclaredMethods()获取了非public方法,并且想要调用这些方法,你需要先调用Method.setAccessible(true)来允许访问这些方法,否则会抛出IllegalAccessException异常。


http://www.ppmy.cn/server/21619.html

相关文章

HTTP接口调用时报错 java.io.IOException: Connection reset by peer解决办法

问题描述 在接口调用时,遇到如下报错:Caused by: java.io.IOException: Connection reset by peer at sun.nio.ch.FileDispatcherImpl.write0(Native Method) ~[?:1.8.0_241] at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47) ~[?:1.8.0_…

GO语言核心30讲 笔记

原站地址:Go语言核心36讲_Golang_Go语言-极客时间 一、基础知识 1. 两种声明变量方式的差异: 短变量声明 name : "abc" 只能在函数体内部使用。 var name "abc" 这方式才可以用在所有地方。 2. 类型推断有什么好处? …

ES5、ES6类的定义

ES5定义类 1、类名首字母一般都是大写 2、可以当成普通函数调用,但一般都通过new关键字调用,通过关键字调用会生成一个新的对象 3、通过new关键字创建的对象,给当前的this绑定成新创建的对象 4、给当前类定义一个方法,通常绑定在…

代码随想录35期Day24-Java

Day24 回溯算法 LeetCode77.组合&#xff1a;给出1-n之间每k个数的所有组合 核心思想&#xff1a;回溯&#xff0c;维护一个当前的元素集。注意结束条件 class Solution {// path存放当前元素List<Integer> path new ArrayList<>();// 结果集resList<List&l…

拉普拉斯分布(Laplace Distribution)

Laplace Distribution 是尖峰长尾分布&#xff0c;其密度函数为&#xff1a; p ( x ∣ μ , b ) 1 2 b e − ∣ x − μ ∣ b p(x|\mu,b) \frac{1}{2b}e^{-\frac{|x-\mu|}{b}} p(x∣μ,b)2b1​e−b∣x−μ∣​ 其期望为 μ \mu μ。方差为 2 b 2 2b^2 2b2。在英伟达论文Prod…

JAVAEE—HTTPS和ssl证书

0[toc] 什么是HTTPS HTTPS 也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层. HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中出现一些被篡改的情况而HTTPS则是新采用加密的方式进行传输 为什么需要HTTPS 为什么要使用HTTPS呢&#xff1f;这…

Android Monkey工具介绍与使用

过于爽快的承认失败&#xff0c;就可能发觉不了曾经与正确非常接近。大家好&#xff0c;依旧是在翻看旧文档的时候&#xff0c;发现一篇关于Monkey的介绍和使用&#xff0c;Monkey这款工具在软件测试中主要用于进行压力测试和稳定性测试。它可以模拟大量随机的用户操作&#xf…

【Docker】docker部署lnmp和wordpress网站

环境准备 docker&#xff1a;192.168.67.30 虚拟机&#xff1a;4核4G systemctl stop firewalld systemctl disable firewalld setenforce 0 安装docker #安装依赖包 yum -y install yum-utils device-mapper-persistent-data lvm2 #设置阿里云镜像 yum-config-manager --add…