[Java]通过反射获取运行时类的对象及其内部结构

news/2024/4/30 2:20:41/文章来源:https://blog.csdn.net/m0_53022813/article/details/127158561

在这里插入图片描述


文章目录

  • 1. 创建运行时类的对象
  • 2. 体会反射的动态性
  • 3. 通过反射获取运行时类的结构
    • 3.1 用于测试的类的准备
    • 3.2 获取运行时类的属性
      • 3.2.1 getFields()
      • 3.2.2 getDeclaredField()
      • 3.2.3 获取属性的结构
    • 3.3 获取运行时类的方法
      • 3.3.1 getMethods()
      • 3.3.2 getDeclaredMethods()
      • 3.3.3 获取方法的结构
    • 3.4 获取运行时类的构造器
      • 3.4.1 getConstructors()
      • 3.4.2 getDeclaredConstructors()
    • 3.5 获取运行时类的父类及其泛型
      • 3.5.1 获取运行时类的父类
      • 3.5.2 获取运行时类的带泛型的父类
      • 3.5.3 获取运行时类的带泛型的父类的泛型
    • 3.6 获取运行时类实现的接口
      • 3.6.1 获取运行时类实现的接口
      • 3.6.2 获取运行时类的父类实现的接口
    • 3.7 获取运行时类所在的包
    • 3.8 获取运行时类的注解


1. 创建运行时类的对象

通过反射的方式创建运行时类的对象。

以Person类为例,先通过反射获取Person类的运行时类,再通过获取到的Person类的运行时类来实例化对象。

通过反射的方式创建运行时类的对象,使用获取到的运行时类中newInstance()方法创建运行时类的对象。

调用运行时类的newInstance()方法创建对应类的对象,其实还是使用对应的类的构造方法进行对象的创建,只是调用构造器创建对象封装在newInstance()方法了。

    @Testpublic void test7() throws Exception{
//        通过反射的方式创建运行时类对应的对象
//        获取Person的运行时类
//        获取运行时类的时候使用泛型,在创建实例对象的时候,可以得到对应类型的对象
//        返回的对象不用进行强制转换
//        也可以不使用泛型,newInstance()得到的对象为Object类型Class<Person> personClass = Person.class;
//        使用获取到的Person运行时类中的newInstance()方法创建对应类的对象Person person = personClass.newInstance();System.out.println(person);}

在这里插入图片描述

使用newInstance()方法创建运行时类的对象,如果对应的构造器(无参或使用其他类型构造器)不存在,会抛出InstantiationException异常;如果构造器的权限不够大,会抛出IllegalAccessException异常。
newInstance()方法正常创建运行时类的对象,需要满足:

  1. 运行时类必须存在对应的构造器
  2. 对应的构造器的访问权限要够,通常设置为public

通过反射创建运行时类的对象,更喜欢使用无参的构造器创建对象,即使用newInstance()来创建运行时类的对象,因为这样子可以写出通用的代码,提高代码的复用性。如果使用newInstance(String.class, int.class, ...)创建运行时类的对象,不同的类有不同的有参构造器,该写法代码复用性不强。

2. 体会反射的动态性

    //体会反射的动态性@Testpublic void test8(){
//        循环运行10次for(int i = 0;i < 10;i++){
//            每次随机产生一个整数,0-2,int num = new Random().nextInt(3);//0,1,2
//            类的全类名String classPath = "";
//            根据生成的随机数指定对应的全类名switch(num){case 0:classPath = "java.util.Date";break;case 1:classPath = "java.lang.Object";break;case 2:classPath = "Person";break;}try {
//                通过指定的全类名创建对应的类的对象Object obj = getInstance(classPath);System.out.println(obj);} catch (Exception e) {e.printStackTrace();}}}/*创建一个指定类的对象。classPath:指定类的全类名*/public Object getInstance(String classPath) throws Exception {
//        根据传递的全类名,获取对应类的运行时类Class clazz =  Class.forName(classPath);
//        使用指定类的运行时类创建实例对象return clazz.newInstance();}

在这里插入图片描述

3. 通过反射获取运行时类的结构

通过反射我们可以获取实现的全部接口、获取所继承的父类、获取全部的构造器、获取全部的方法、获取全部的Field。

3.1 用于测试的类的准备

在这里插入图片描述

Creature.java:

import java.io.Serializable;public class Creature<T> implements Serializable {private char gender;public double weight;private void breath(){System.out.println("生物呼吸");}public void eat(){System.out.println("生物吃东西");}
}

MyInterface.java:

public interface MyInterface {void info();
}

MyAnnotation.java:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {String value() default "hello";
}

Person.java:

@MyAnnotation(value="hi")
public class Person extends Creature<String> implements Comparable<String>,MyInterface{private String name;int age;public int id;public Person(){}@MyAnnotation(value="abc")private Person(String name){this.name = name;}Person(String name,int age){this.name = name;this.age = age;}@MyAnnotationprivate String show(String nation){System.out.println("我的国籍是:" + nation);return nation;}public String display(String interests,int age) throws NullPointerException,ClassCastException{return interests + age;}@Overridepublic void info() {System.out.println("我是一个人");}@Overridepublic int compareTo(String o) {return 0;}private static void showDesc(){System.out.println("我是一个可爱的人");}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", id=" + id +'}';}
}

3.2 获取运行时类的属性

3.2.1 getFields()

获取运行时类及其父类中声明为public访问权限的属性。

    @Testpublic void test1() {Class personClass = Person.class;
//        使用getFields()获取运行时类及其父类中声明为public访问权限的属性。
//        返回值为一个Field类型的数组Field[] fields = personClass.getFields();for (Field field: fields) {System.out.println(field);}}

在这里插入图片描述

3.2.2 getDeclaredField()

获取运行时类中声明的所有属性,不包含父类中声明的属性。

    @Testpublic void test2() {Class personClass = Person.class;
//        getDeclaredField()获取运行时类中声明的所有属性,不包含父类中声明的属性。
//        返回值为一个Field类型的数组Field[] fields = personClass.getDeclaredFields();for (Field field: fields) {System.out.println(field);}}

在这里插入图片描述

3.2.3 获取属性的结构

属性的权限修饰符、数据类型、变量名等也可以通过反射进行获取。

    @Testpublic void test3() {Class personClass = Person.class;Field[] fields = personClass.getDeclaredFields();for (Field field: fields) {
//            1. 获取属性的权限修饰符
//            field.getModifiers()得到的为权限修饰符对应的数字
//            默认权限为0
//            可以使用Modifier.toString(modifiers)将权限修饰符对应数字转换为对应的权限修饰符字符串int modifiers = field.getModifiers();System.out.println(Modifier.toString(modifiers));//            2. 获取属性的数据类型
//            返回值类型为ClassClass type = field.getType();
//            type.getName()会返回数据类型的全类名System.out.println(type.getName());//            3. 获取属性的变量名String fieldName = field.getName();System.out.println(fieldName);System.out.println("---------------");}}

在这里插入图片描述

3.3 获取运行时类的方法

3.3.1 getMethods()

获取运行时类及其所有父类中声明为public访问权限的方法。

    @Testpublic void test1() {Class personClass = Person.class;
//        getMethods()获取运行时类及其所有父类中声明为public访问权限的方法。
//        返回值为Method类型的数组Method[] methods = personClass.getMethods();for (Method method: methods) {System.out.println(method);}}

在这里插入图片描述

3.3.2 getDeclaredMethods()

获取运行时类中声明的所有方法,不包含父类中声明的方法

    @Testpublic void test2() {Class personClass = Person.class;
//        getDeclaredMethods()获取运行时类中声明的所有方法,不包含父类中声明的方法
//        返回值为Method类型的数组Method[] methods = personClass.getDeclaredMethods();for (Method method: methods) {System.out.println(method);}}

在这里插入图片描述

3.3.3 获取方法的结构

方法的结构:

@Xxxx
权限修饰符 返回值类型 方法名(参数类型1 参数名1, ...) throws Exception {}
    @Testpublic void test4() {Class clazz = Person.class;Method[] methods = clazz.getDeclaredMethods();for (Method m : methods) {//1.获取方法声明的注解//返回值为Annotation类型的数组,因为一个方法上可以加多个注解Annotation[] annos = m.getAnnotations();for (Annotation a : annos) {System.out.println(a);}//2.权限修饰符//m.getModifiers()得到的为权限修饰符对应的数字//Modifier.toString()将权限修饰符数字转换为对应的字符串System.out.print(Modifier.toString(m.getModifiers()) + "\t");//3.返回值类型System.out.print(m.getReturnType().getName() + "\t");//4.方法名System.out.print(m.getName());System.out.print("(");//5.形参列表Class[] parameterTypes = m.getParameterTypes();//判断方法是否有形参列表if (!(parameterTypes == null || parameterTypes.length == 0)) {// 循环输出参数类型for (int i = 0; i < parameterTypes.length; i++) {// 最后一个形参的输出进行特殊处理if (i == parameterTypes.length - 1) {System.out.print(parameterTypes[i].getName() + " args_" + i);break;}System.out.print(parameterTypes[i].getName() + " args_" + i + ",");}}System.out.print(")");//6.抛出的异常//抛出的异常可能有多个也可能没有异常的抛出Class[] exceptionTypes = m.getExceptionTypes();//判断是否有异常的抛出if (exceptionTypes.length > 0) {System.out.print("throws ");for (int i = 0; i < exceptionTypes.length; i++) {if (i == exceptionTypes.length - 1) {System.out.print(exceptionTypes[i].getName());break;}System.out.print(exceptionTypes[i].getName() + ",");}}System.out.println("{}");}}

在这里插入图片描述

3.4 获取运行时类的构造器

3.4.1 getConstructors()

获取运行时类中声明为public访问权限的构造器。

    @Testpublic void test1() {Class personClass = Person.class;
//        getConstructors()获取运行时类中声明为public访问权限的构造器。
//        返回值为Constructor类型的数组,构造器可能有多个Constructor[] constructors = personClass.getConstructors();for (Constructor constructor : constructors) {System.out.println(constructor);}}

在这里插入图片描述

3.4.2 getDeclaredConstructors()

获取运行时类中声明的所有构造器

    @Testpublic void test2() {Class personClass = Person.class;
//        getDeclaredConstructors()获取运行时类中声明的所有构造器
//        返回值为Constructor类型的数组,构造器可能有多个Constructor[] constructors = personClass.getDeclaredConstructors();for (Constructor constructor : constructors) {System.out.println(constructor);}}

在这里插入图片描述

通过反射也可以获取构造器的结构,获取方法与获取方法的结构类似。

3.5 获取运行时类的父类及其泛型

3.5.1 获取运行时类的父类

    @Testpublic void test() {Class personClass = Person.class;
//        获取运行时类的父类
//        运行时类的父类的类型也为ClassClass superClass = personClass.getSuperclass();System.out.println(superClass);}

在这里插入图片描述

3.5.2 获取运行时类的带泛型的父类

    @Testpublic void test() {Class personClass = Person.class;Type genericSuperclass = personClass.getGenericSuperclass();System.out.println(genericSuperclass);}

在这里插入图片描述

3.5.3 获取运行时类的带泛型的父类的泛型

    @Testpublic void test() {Class personClass = Person.class;Type genericSuperclass = personClass.getGenericSuperclass();System.out.println(genericSuperclass);//已经确定genericSuperclass带有泛型,将其强转为带有参数类型ParameterizedType类型ParameterizedType paramType = (ParameterizedType) genericSuperclass;//获取泛型类型//返回的为数组,是由于有时候泛型有多个,如Map<K, V>就有两个泛型Type[] actualTypeArguments = paramType.getActualTypeArguments();System.out.println(actualTypeArguments[0].getTypeName());}

在这里插入图片描述

3.6 获取运行时类实现的接口

3.6.1 获取运行时类实现的接口

    @Testpublic void test() {Class clazz = Person.class;// 获取运行时类实现的接口// 由于实现的接口可能有多个,所以返回的为数组Class[] interfaces = clazz.getInterfaces();for(Class c : interfaces){System.out.println(c);}}

在这里插入图片描述

3.6.2 获取运行时类的父类实现的接口

    @Testpublic void test() {Class clazz = Person.class;//获取运行时类的父类实现的接口//先获取运行时类的父类//然后获取运行时类的父类实现的接口Class[] interfaces1 = clazz.getSuperclass().getInterfaces();for(Class c : interfaces1){System.out.println(c);}}

在这里插入图片描述

3.7 获取运行时类所在的包

    @Testpublic void test() {Class clazz = Person.class;Package pack = clazz.getPackage();System.out.println(pack);}

在这里插入图片描述

3.8 获取运行时类的注解

    @Testpublic void test() {Class clazz = Person.class;Annotation[] annotations = clazz.getAnnotations();for(Annotation annos : annotations){System.out.println(annos);}}

在这里插入图片描述

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

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

相关文章

美食篇:大闸蟹与梭子蟹的区别

文章目录大闸蟹梭子蟹区别总结吃蟹子的季节大闸蟹 梭子蟹 区别总结 大闸蟹香&#xff0c;小&#xff0c;有黄 梭子蟹鲜&#xff0c;大&#xff0c;无黄 小的梭子蟹也有黄&#xff0c;小的便宜 总结&#xff1a;浓缩的都是精华&#xff01;个头大的不一定好吃&#xff0c;但一…

面积结构设计

面积结构设计 针对面积的拓扑是尽可能最大程度地复用逻辑资源,常常以流量(速度)为代价。 1、折叠流水线 折叠流水线可以优化在流水线赋值逻辑的流水线设计的面积。 定点的分数乘法器。A表示定点刚好在最低有效位(LSB)右边的归一化整数格式,输入B的定点刚好在最高有效…

Torch

张量 Tensor torch.is_tensor[source] torch.is_tensor(obj) 如果obj是一个pytorch张量&#xff0c;则返回True torch.is_storage(obj) torch.set_default_tensor_type(t) 设置pytorch中默认的浮点类型&#xff0c;一般使用pytorch进行运算时候使用的都是浮点数来进行计算…

Linux进程(冯诺依曼体系结构、操作系统、进程)

文章目录一、冯诺依曼体系结构&#xff1a;1.基本概念&#xff1a;2.为什么如此设计&#xff1a;2.1.运行速度优化&#xff1a;2.2.成本&#xff1a;3.总结&#xff1a;二、操作系统&#xff1a;1.基本概念&#xff1a;2.操作系统的作用&#xff1a;3.什么是管理&#xff1a;三…

【Shell编程】Bash变量-用户自定义变量

目录系列文章Bash变量-用户自定义变量变量的命名规则变量分类本地变量实例系列文章 【Shell编程】Shell基本概述与脚本执行方式 【Shell编程】Shell中Bash基本功能 Bash变量-用户自定义变量 变量的命名规则 不能以数字开头在Bash中&#xff0c;变量的默认类型都是字符串型&…

关于XShell下载安装和连接Ubuntu(linux)

目录 1.XShell下载和安装 其实很多CSDN博主已经发表很多关于这个下载安装和连接的问题&#xff0c;但是我发现都是不完整的&#xff0c;所以自己再根据大佬写的&#xff0c;重新总结一下。 XSheel下载地址 XSheel安装教程 XShell连接的话看下面的教程&#xff0c;上面中的X…

系统调用,库函数以及Linux下与进程相关的指令操作

文章目录操作系统怎么为我们提供服务什么是系统调用库函数和系统调用Linux系统下操作进程的相关指令fork系统调用操作系统怎么为我们提供服务 我们知道&#xff0c;操作系统是管理的软件。那么有的时候&#xff0c;用户需要服务&#xff0c;那么对应的操作系统就要提供对应的服…

实验5 开源控制器实践——POX

实验5 开源控制器实践——POX 基础实验hub分析: 由于在hub模式下,采取广播帧的模式,交换机每收到一帧,会向所有端口进行广播,因而h1发给h2的数据包在h3的端口也能监听到switch分析: 由于在自学习模式下,交换机会根据mac高速缓存信息进行发送数据包,因而在实验过程中,对…

设计模式解析---------------单例模式

单例模式定义 确保某一个类只有一个实例&#xff0c;而且自行实例化并向整个系统提供这个实例。 单例模式的使用场景 确保某个类只有一个对象的场景&#xff0c;避免产生多个对象消耗过多的资源&#xff0c;或者某种对象有且只能有一个。 单例模式的UML图 角色介绍&#xff1…

数字媒体概论——系统篇

一&#xff1a;需求分析 需求分析三大要素&#xff1a; 表达内容 -> 媒体种类面向人群 -> 交互方式使用方式 -> 硬件需求 例如&#xff1a;海洋馆需要一个可以展示海洋生物知识的媒体交互系统&#xff0c;可供多人同时观赏&#xff0c;主要面向儿童&#xff0c;这里…

计算机二级C语言题库(44套真题+刷题软件)第一套

刷题软件 gongzhonghao&#xff1a;露露IT 1、循环队列的存储空间为Q(1:100),初始状态为frontrear100。经过一系列正常的入队与退队操作后,frontrear99,则循环队列中的元素个数为( )。 A. 0或100 B. 1 C. 2 D. 99 本题考查知识点是循环队列。当队头和队尾指针指向同一个元素…

常见的图片格式介绍

常见的图片格式介绍 图片&#xff08;Picture&#xff09;包括图形、图像。图形&#xff08;Graph&#xff09;是矢量图&#xff08;Vector Drawn&#xff09;&#xff0c;图像&#xff08;Image&#xff09;是位图&#xff08;Bitmap&#xff09;。 图片&#xff08;Picture…

【老板要我啥都会】|前端升全栈之项目使用express重构项目(下篇)

前言 承接上一篇文章&#xff0c;《前端升全栈之项目使用express重构项目&#xff08;上篇&#xff09;》&#xff0c;我们继续讲解下一篇的项目使用express重构项目完整的下一篇&#xff08;主要是国庆&#xff0c;需要放松&#xff0c;所以该文章分为上下篇&#xff0c;请大…

2022年Webpack 5初学者完整指南

2022年Webpack 5初学者完整指南 从基础到高级学习 Webpack 5&#xff01;将 Webpack 与 JS、CSS、NPM、模块联合和微前端一起使用 课程英文名&#xff1a;Webpack 5 in 2022 The Complete Guide For Beginners 此视频教程共2.5小时&#xff0c;中英双语字幕&#xff0c;画质…

都这麽大了还不快了解防病毒网关?

目录 一、思考 二、实验 1、实验拓扑 2、配置过程&#xff08;网页端配置&#xff09; 三、总结 1. 什么是恶意软件&#xff1f; 2. 恶意软件有哪些特征&#xff1f; 3. 恶意软件的可分为那几类&#xff1f; 4. 恶意软件的免杀技术有哪些&#xff1f; 5. 反病毒技术…

OceanBase 从0到1数据库内核实战教程学习笔记 - 3.OceanBase基础架构和开发技巧

这篇文章主要介绍王泽林老师分享的 《OceanBase 的基础架构和开发技巧》。如果您看过第一篇文章的对应视频&#xff0c;会发现整个系列主要分为 MiniOB 和 OceanBase 两个系列&#xff0c;本篇文章就是 OceanBase 系列的开篇&#xff0c;所以文章中会有很多 OceanBase 的概念和…

Java类的成员方法的创建以及调用|在使用时有何意义|附运行方式及题目

&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d; &#x1f947;博主昵称&#xff1a;Jovy. &#x1f35f;博客主页…

遥感航拍影像25篇CVPR39个数据集

摘要 本文讲解了39个数据集&#xff0c;关于高空卫星图和低空无人机航拍图像。 本文汇总了25篇CVPR2020年和2021年的论文。 本文详细介绍了这25篇论文的任务是什么&#xff0c;难点是什么&#xff0c;场景是什么。 同时&#xff0c;本文在需要的地方解释了一些卫星图和航拍…

Vue学习第35天——模拟项目上线基本流程

一、打包 将.vue文件生成为.html、.css、.js文件 npm run build执行完之后&#xff0c;会在项目中生成一个dist文件&#xff08;执行的速度取决于项目的大小以及电脑的配置&#xff09; 二、创建服务器 没有后端服务器&#xff0c;这里我们使用node.js express 搭建一个服…

(附源码)计算机毕业设计ssm餐厅管理系统

毕设帮助&#xff0c;指导&#xff0c;本源码分享&#xff0c;调试部署(见文末) 4.1.2系统的主要的功能结构 餐厅管理系统的主要功能的结构如图4-1所示。 图4-1系统功能结构图 4.2系统设计 4.2.1数据表E-R图 菜谱信息属性图如图4-2所示。 图4-2菜谱信息实体属性图 账单信息…