16 -java反射

news2024/11/19 3:16:49

目录

第16章 反射

16.1 反射的概念

16.2反射的作用

16.3 java.lang.Class类

16.3.1 哪些类型可以获取Class对象

16.3.2 获取Class对象的四种方式

16.4 反射的基本应用

16.4.1 获取类型的详细信息

16.4.2 创建任意引用类型的对象

16.4.3 操作任意类型的属性

16.4.4 调用任意类型的方法


第16章 反射

Java程序中,所有的对象都有两种类型:编译时类型和运行时类型,而很多时候对象的编译时类型和运行时类型不一致。

例如:某些变量或形参的类型是Object类型,但是程序却需要调用该对象运行时类型的方法,该方法不是Object中的方法,那么如何解决呢?

因为加载完类之后,就产生了一个Class类型的对象,并将引用存储到方法区,那么每一个类在方法区内存都可以找到唯一Class对象与之对应,这个对象包含了完整的类的结构信息,我们可以通过这个对象获取类的结构。这种机制就像一面镜子,Class对象像是类在镜子中的镜像,通过观察这个镜像就可以知道类的结构,所以,把这种机制形象地称为反射机制。

16.1 反射的概念

反射是Java的一种强大而灵活的特性,它允许程序在运行时获取类的信息、构造对象、调用方法和访问字段。在Java中,每个类都有一个对应的Class对象,通过这个Class对象,我们可以在运行时获取并操作类的结构。

Java反射机制主要提供了以下功能:

  • 在运行时判断任意一个对象所属的类。

  • 在运行时构造任意一个类的对象。

  • 在运行时判断任意一个类所具有的成员变量和方法。

  • 在运行时调用任意一个对象的方法。

16.2反射的作用

可以在运行时得到一个类的全部成分然后操作。

更重要的用途是适合:做Java高级框架。

16.3 java.lang.Class类

要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API

(1)java.lang.Class

(2)java.lang.reflect.*。

所以,Class对象是反射的根源。

16.3.1 哪些类型可以获取Class对象

哪些类型可以获取Class对象?所有Java类型

//(1)基本数据类型和void
例如:int.class
     void.class
//(2)类和接口
例如:String.class
    Comparable.class
//(3)枚举
例如:ElementType.class
//(4)注解
例如:Override.class
//(5)数组
例如:int[].class
import java.lang.annotation.ElementType;
​
public class JavaType {
    public static void main(String[] args) {
        //(1)基本数据类型和void
        Class c1 = int.class;
        Class c2 = void.class;
​
        System.out.println("c1 = " + c1);
        System.out.println("c2 = " + c2);
        //(2)类和接口
        Class c3 = String.class;
        Class c4 = Comparable.class;
        System.out.println("c3 = " + c3);
        System.out.println("c4 = " + c4);
​
        //(3)枚举
        Class c5 = ElementType.class;
        System.out.println("c5 = " + c5);
​
        //(4)注解
        Class c6 = Override.class;
        System.out.println("c6 = " + c6);
​
        //(5)数组
        Class c7 = int[].class;
        Class c9 = String[].class;
        Class c8 = int[][].class;
        System.out.println("c7 = " + c7);
        System.out.println("c8 = " + c8);
        System.out.println("c9 = " + c9);
    }
}

16.3.2 获取Class对象的四种方式

(1)类型名.class

要求编译期间已知类型

(2)对象.getClass()

获取对象的运行时类型

(3)Class.forName(类型全名称)

可以获取编译期间未知的类型

(4)ClassLoader的类加载器对象.loadClass(类型全名称)

可以用系统类加载对象或自定义加载器对象加载指定路径下的类型

public class GetClassObject {
    @Test
    public void test01() throws ClassNotFoundException{
        Class c1 = GetClassObject.class;
        GetClassObject obj = new GetClassObject();
        Class c2 = obj.getClass();
        Class c3 = Class.forName("com.haogu.classtype.GetClassObject");
        Class c4 = ClassLoader.getSystemClassLoader().loadClass("com.haogu.classtype.GetClassObject");
​
        System.out.println("c1 = " + c1);
        System.out.println("c2 = " + c2);
        System.out.println("c3 = " + c3);
        System.out.println("c4 = " + c4);
​
        System.out.println(c1 == c2);
        System.out.println(c1 == c3);
        System.out.println(c1 == c4);
    }
​
    @Test
    public void test02(){
        int[] arr1 = {1,2,3,4,5};
        int[] arr2 = {10,34,5,66,34,22};
        int[][] arr3 = {{1,2,3,4},{4,5,6,7}};
        String[] arr4 = {"hello","world"};
​
        Class c1 = arr1.getClass();
        Class c2 = arr2.getClass();
        Class c3 = arr3.getClass();
        Class c4 = arr4.getClass();
​
        System.out.println("c1 = " + c1);
        System.out.println("c2 = " + c2);
        System.out.println("c3 = " + c3);
        System.out.println("c4 = " + c4);
        System.out.println(c1 == c2);
        System.out.println(c1 == c3);
        System.out.println(c1 == c4);
        System.out.println(c3 == c4);
    }
}

16.4 反射的基本应用

Java 反射的主要组成部分有4个:

正在运行的 Java 应用程序中的类:Class。

在运行时,可以直接得到这个类的成员变量对象:Field

在运行时,可以直接得到这个类的构造器对象:Constructor

在运行时,可以直接得到这个类的成员方法对象:Method

这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。

16.4.1 获取类型的详细信息

可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
​
public class TestClassInfo {
    public static void main(String[] args) throws Exception {
        //1、先得到某个类型的Class对象
        Class clazz = String.class;
        //比喻clazz好比是镜子中的影子
​
        //2、获取类信息
        //(1)获取包对象,即所有java的包,都是Package的对象
        Package pkg = clazz.getPackage();
        System.out.println("包名:" + pkg.getName());
​
        //(2)获取修饰符
 
        int mod = clazz.getModifiers();
        System.out.println("类的修饰符有:" + Modifier.toString(mod));
​
        //(3)类型名
        String name = clazz.getName();
        System.out.println("类名:" + name);
​
        //(4)父类,父类也有父类对应的Class对象
        Class superclass = clazz.getSuperclass();
        System.out.println("父类:" + superclass);
​
        //(5)父接口们
        System.out.println("父接口们:");
        Class[] interfaces = clazz.getInterfaces();
        for (Class iter : interfaces) {
            System.out.println(iter);
        }
​
        //(6)类的属性,  你声明的一个属性,它是Field的对象
/*      Field clazz.getField(name)  根据属性名获取一个属性对象,但是只能得到公共的
        Field[] clazz.getFields();  获取所有公共的属性
        Field clazz.getDeclaredField(name)  根据属性名获取一个属性对象,可以获取已声明的
        Field[] clazz.getDeclaredFields()   获取所有已声明的属性
        */
//        Field valueField = clazz.getDeclaredField("value");
//      System.out.println("valueField = " +valueField);
​
        System.out.println("------------------------------");
        System.out.println("成员如下:");
        System.out.println("属性有:");
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            //修饰符、数据类型、属性名
            int modifiers = field.getModifiers();
            System.out.println("属性的修饰符:" + Modifier.toString(modifiers));
​
            String name2 = field.getName();
            System.out.println("属性名:" + name2);
​
            Class<?> type = field.getType();
            System.out.println("属性的数据类型:" + type);
        }
        System.out.println("-------------------------");
        //(7)构造器们
        System.out.println("构造器列表:");
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (int i=0; i<constructors.length; i++) {
            Constructor constructor = constructors[i];
            System.out.println("第" + (i+1) +"个构造器:");
            //修饰符、构造器名称、构造器形参列表  、抛出异常列表
            int modifiers = constructor.getModifiers();
            System.out.println("构造器的修饰符:" + Modifier.toString(modifiers));
​
            String name2 = constructor.getName();
            System.out.println("构造器名:" + name2);
​
            //形参列表
            System.out.println("形参列表:");
            Class[] parameterTypes = constructor.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println(parameterType);
            }
​
            //异常列表
            System.out.println("异常列表:");
            Class<?>[] exceptionTypes = constructor.getExceptionTypes();
            for (Class<?> exceptionType : exceptionTypes) {
                System.out.println(exceptionType);
            }
            System.out.println();
        }
        System.out.println("---------------------------------");
        //(8)方法们
        System.out.println("方法列表:");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (int i=0; i<declaredMethods.length; i++) {
            Method method = declaredMethods[i];
            System.out.println("第" + (i+1) +"个方法:");
            //修饰符、返回值类型、方法名、形参列表 、异常列表
            int modifiers = method.getModifiers();
            System.out.println("方法的修饰符:" + Modifier.toString(modifiers));
​
            Class<?> returnType = method.getReturnType();
            System.out.println("返回值类型:" + returnType);
​
            String name2 = method.getName();
            System.out.println("方法名:" + name2);
​
            //形参列表
            System.out.println("形参列表:");
            Class[] parameterTypes = method.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println(parameterType);
            }
​
            //异常列表
            System.out.println("异常列表:");
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            for (Class<?> exceptionType : exceptionTypes) {
                System.out.println(exceptionType);
            }
            System.out.println();
        }
​
    }
}
​

16.4.2 创建任意引用类型的对象

两种方式:

1、直接通过Class对象来实例化(要求必须有公共的无参构造)

2、通过获取构造器对象来进行实例化

方式一的步骤:

(1)获取该类型的Class对象(2)创建对象

方式二的步骤:

(1)获取该类型的Class对象(2)获取构造器对象(3)创建对象

16.4.3 操作任意类型的属性

(1)获取该类型的Class对象

Class clazz = Class.forName("包.类名");

(2)获取属性对象

Field field = clazz.getDeclaredField("属性名");

(3)如果属性的权限修饰符不是public,那么需要设置属性可访问

field.setAccessible(true);

(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象

Object obj = clazz.newInstance(); //有公共的无参构造

Object obj = 构造器对象.newInstance(实参...);//通过特定构造器对象创建实例对象

(4)设置属性值

field.set(obj,"属性值");

如果操作静态变量,那么实例对象可以省略,用null表示

(5)获取属性值

Object value = field.get(obj);

如果操作静态变量,那么实例对象可以省略,用null表示

16.4.4 调用任意类型的方法

(1)获取该类型的Class对象

Class clazz = Class.forName("包.类名");

(2)创建实例对象

Object obj = clazz.newInstance();

(3)获取方法对象

Method method = clazz.getDeclaredMethod("方法名",方法的形参类型列表);

(4)调用方法

Object result = method.invoke(obj, 方法的实参值列表);

如果方法的权限修饰符修饰的范围不可见,可以调用setAccessible(true)

如果方法是静态方法,实例对象可以省略,用null代替

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

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

相关文章

【uni-app】Pinia 持久化

小程序端 Pinia 持久化 说明&#xff1a;Pinia 用法与 Vue3 项目完全一致&#xff0c;uni-app 项目仅需解决持久化插件兼容性问题。 持久化存储插件 安装持久化存储插件&#xff1a; pinia-plugin-persistedstate pnpm i pinia-plugin-persistedstate插件默认使用 localStor…

观成科技:Play勒索软件组织加密流量分析

1.概述 近年来&#xff0c;勒索软件组织的作业链条逐渐从“加密数据->收取赎金”转变到“数据窃取->加密数据->暗网披露窃取数据大小和内容描述->收取赎金”[1]。勒索软件组织在获取到受害者的访问权限后&#xff0c;不会立刻进行勒索&#xff0c;而是进行横向移动…

k8s部署calico遇到的问题

kubernetes安装calico calico官网 环境&#xff1a;centos7.9&#xff0c;calico 3.23&#xff0c;kuberadm 1.26 问题1&#xff1a;执行kubectl create -f calico.yml后报错如下 error: resource mapping not found for name: “tigera-operator” namespace: “” from “…

【旧文更新】武汉光迅科技22校招笔试Python题改进(增加GUI) 基于Python的125温度传感器模块数据处理

【旧文更新】武汉光迅科技22校招笔试Python题改进&#xff08;增加GUI&#xff09; 基于Python的125温度传感器模块数据处理 文章目录 关于旧文新发题目分析附录&#xff1a;列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 附录&#xff1a;关于旧文新发 关于…

HCIA--DHCP: 动态主机配置协议 (复习)

DHCP: 动态主机配置协议 -- 同一分发管理ip地址 基于UDP 67/68端口工作 网络中存在DHCP的服务器为需要自动生成ip地址的设备分配ip地址&#xff1b;--C/S模型 成为DHCP服务器的条件&#xff1a; 该设备存在接口或网卡连接到所要分发ip地址的广播域内该接口或网卡必须已经配置…

在Windows安装Flutter

一、安装 Android Studio 官网&#xff1a; 下载 Android Studio 和应用工具 - Android 开发者 | Android Developers 教程&#xff1a;Android Studio 安装配置教程 - Windows(详细版)-CSDN博客 Flutter 官网&#xff1a;Windows | Flutter 中文文档 - Flutter 中文开发…

乡村振兴的乡村产业创新发展:培育乡村新兴产业,打造乡村产业新名片,促进乡村经济多元化发展

目录 一、引言 二、乡村产业创新发展的必要性 &#xff08;一&#xff09;适应新时代发展要求 &#xff08;二&#xff09;满足消费升级需求 &#xff08;三&#xff09;促进农民增收致富 三、培育乡村新兴产业策略 &#xff08;一&#xff09;加强科技创新引领 &#…

阿里云物联网平台python ADK 发布/订阅

基础知识学习参考&#xff1a; 1、使用消息通讯Topic 2、python link SDK 一、环境变量配置 1、python3.6&#xff1a;下载安装 2、安装paho-mqtt 1.4.0版本 pip install paho-mqtt1.4.03、安装安装Link SDK最新版本 pip install aliyun-iot-linkkit 4、下载python ADK…

ES报错1

ES在kibana的JSON如图: 提交后错误信息如下 所以是什么错误呢: 原来是:json的格式有误改成 这里的错误其实是我在文件传输时,为了节约空间,没有以json格式传递,而是一串字符就传过来了,需要使用josn的格式化工具格式化才行,结果格式化的不正确,才遇到此坑

Echarts正负条形图将x轴都设置成正数

1、先修改x轴上面显示为负数的刻度标签&#xff0c;找到xAxis[i].axisLabel&#xff0c;重写他的formatter xAxis: [{type: value,axisLabel: {formatter: (value) > {// 负数取反 显示的就是正数了if (value < 0) return -valueelse return value}}} ] 2、在修改柱状图…

vue中计算属性computed和watch的区别是什么?

watch : 监测的是属性值&#xff0c;只要属性值发生变化&#xff0c;其都会触发执行回调函数来执行一系列操作&#xff1b; computed : 监测的是依赖值&#xff0c;依赖值不变的情况下其会直接读取缓存进行复用&#xff0c;变化的情况下才会重新计算&#xff1b; 它们之间最…

zynq/zynqMP启动模式总结:FLASH+emmc启动/petalinux烧写速度最快的启动方式

因客户要求zynq开发板只有FLASH和emmc&#xff0c;然而还得在petalinux进行开发系统&#xff0c;因FLASH大小有限&#xff0c;所以没办法把内核和根文件地址全部存储到FLASH中&#xff0c;于是想配合emmc进行启动&#xff0c;但是在网上搜索的大多都是只把根文件系统放到了emmc…

制造企业如何通过PLM系统实现BOM管理的飞跃

摘要 在当今快速变化的制造行业中&#xff0c;产品生命周期管理&#xff08;PLM&#xff09;系统的应用已成为企业提升效率、降低成本和增强竞争力的关键。本文将探讨PLM系统如何通过其先进的BOM&#xff08;物料清单&#xff09;管理功能&#xff0c;帮助制造企业在整个产品生…

100T微机控制电液伺服卧式拉力试验机

一、产品概述 微机控制卧式拉力试验机适用于额定试验力下的拉伸试验及恒负荷拉伸&#xff0c;可用于钢丝绳、锚链、钩环、电瓷瓶、电缆、光缆、钢铰线、棒材、绳类等制品或材料的拉伸强度测试。 二、性能特点 本机采用计算机控制&#xff0c;具有力、位移自动跟踪测量加荷速…

视频监控业务平台LntonCVS国标GB28181视频平台智慧城市应用方案

随着科技的不断进步&#xff0c;尤其是人工智能技术的飞速发展&#xff0c;视频应用已经超越了传统的视频监控、视频会议、视频通话和视频指挥调度等基本功能。它们正在向更加多元化、灵活化、融合化和智能化的方向发展。因此&#xff0c;建立一个视频AI中台变得至关重要。 通过…

RTPS协议之Messages Module

目录 Messages ModuleType定义RTPS消息结构RTPS消息头子消息结构 RTPS消息接收者SubmessageElementsRTPS HeaderRTPS Submessages Messages Module RTPS Writer和RTPS Reader之间的交换数据的消息。 Type定义 TypePurposeProtocolId_tSubmessageFlagsub msg flagSubmessageK…

【YashanDB知识库】OCI驱动类问题定位方法

【标题】OCI驱动类问题定位方法 【需求分类】故障分析 【关键字】OCI 【需求描述】由于我们的OCI接口目前尚不完善&#xff0c;经常会遇见OCI接口能力不足导致应用功能无法运行的问题&#xff0c;需要定位手段确定底层是哪个接口报错 【需求原因分析】方便一线数据库管理员…

揭秘智慧校园:可视化技术引领教育新篇章

随着科技的飞速发展&#xff0c;我们的生活方式正在经历一场前所未有的变革。而在这场变革中&#xff0c;学校作为培养未来人才的重要基地&#xff0c;也在不断地探索与创新。 一、什么是校园可视化&#xff1f; 校园可视化&#xff0c;就是通过先进的信息技术&#xff0c;将学…

Nocobase快速上手 - 常见block的使用

在上一篇文章 Nocobase快速上手 -第一个collection 中&#xff0c;我们新建了一个collection ,并且通过在页面中配置block实现了数据的展示&#xff0c;本文继续探索block的使用。 Block类型 Block(区块)的整体架构如下图: 我们可以看到&#xff0c;block分为三个大类&#…

【C++】二维前缀和

1.题目 2.算法思路 和一维前缀和的方法类似&#xff0c;我们需要预处理一个求和矩阵&#xff0c;然后再求和。 下面是模板&#xff1a; 上面两张图片总结出来了两个公式&#xff0c;这是解决此类问题的关键。 3.代码 #include <iostream> using namespace std; #incl…