【Java学习】反射和枚举详解

news2024/9/21 10:37:53

  所属专栏:Java学习 

在这里插入图片描述

 

🍁1. 反射

在程序运行时,可以动态地创建对象、调用方法、访问和修改字段,以及获取类的各种属性信息(如成员变量、方法、构造函数等),这种机制就称为反射

反射相关的类
类名用途
Class类代表类的实体,在运行的Java应用程序中表示类和接口
Field类代表类的成员变量 / 类的属性
Method类代表类的方法
Constructor类代表类的构造方法

🍁1.1 反射获取Class对象 

获取字节码文件对象

1. Class.forName(全类名) 包名 + 类名

2. 类名.class

3. 对象名.getClass()

public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取字节码文件对象的三种方式
        // Class.forName(全类名)包名 + 类名(常用)
        Class clazz1 = Class.forName("reflect.Student");
        //类名.class
        Class clazz2 = Student.class;
        //对象名.getClass()
        Student student = new Student();
        Class clazz3 = student.getClass();

        System.out.println(clazz1 == clazz2);
        System.out.println(clazz2 == clazz3);
    }
}

🍁1.2 反射获取构造方法

🍁1.2.1 获取构造方法的方式

方法用途
getConstructor(Class...<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法
getConstructors()获得该类的所有公有构造方法对象的数组
getDeclaredConstructor(Class...<?> parameterTypes)获得该类中与参数类型匹配的构造方法
getDeclaredConstructors()获得该类所有构造方法对象的数组

使用 getConstructors()时,只会获取类中的公共的构造方法

可以看出,使用getDeclaredConstructors()时,不论构造方法的权限修饰符是什么,都可以获取到 

来看获取单个构造方法的例子,在调用方法的时候,传入方法里面的参数要和需要获取的构造方法的参数一致 

 

 getConstructor 只能获取 public 修饰的构造方法,getDeclaredConstructor可以获取任意修饰符修饰的构造方法,所以如果要获取的构造方法如果不是 public 修饰的,但是使用了getConstructor获取,就会报错

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取class字节码文件对象
        Class clazz = Class.forName("com.li.reflect.Student");

        //获取构造方法
        Constructor[]  cons1 = clazz.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }
        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor con2 : cons2) {
            System.out.println(con2);
        }
        //获取单个的构造方法
        Constructor con1 = clazz.getDeclaredConstructor();
        System.out.println(con1);
        Constructor con2 = clazz.getDeclaredConstructor(String.class);
        System.out.println(con2);
        Constructor con3 = clazz.getDeclaredConstructor(String.class,int.class);
        System.out.println(con3);
        Constructor con4 = clazz.getDeclaredConstructor(int.class);
        System.out.println(con2);
        
    }
}

 student类:

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    private Student(int age){
        this.age = age;
    }
    protected Student(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

🍁1.2.2 获取构造方法的用途

通过反射,可以获取到构造方法的所有内容

首先第一个,就是可以获取到构造方法的权限修饰符

//获取权限修饰符,这里获取的是其对应的常量值
int modifiers = con1.getModifiers();
System.out.println(modifiers); //public 对应的常量是1

idea中的提示功能就是使用了反射的机制,获取到了构造方法的权限修饰符,这里只提示了除空参构造之外,可以使用的两种构造方法,private由于在其他类中不能调用,这里就没有显示

 

之后,还可以获取到构造方法的参数 

//获取参数
Parameter[] parameters = con3.getParameters();
System.out.println(Arrays.toString(parameters));//[java.lang.String arg0, int arg1]

 应用场景还是上面的代码提示功能

既然可以获取构造方法的所有内容,那以此来创建一个对象也是可以的:

        //创建对象
        Student student1 = (Student) con3.newInstance("张三", 18);
        System.out.println(student1);
        //获取到private修饰的构造方法时
        con4.setAccessible(true); //表示临时取消权限校验
        Student student2 = (Student) con4.newInstance(18);
        System.out.println(student2);

用这种方式创建对象需要注意:

传进去的参数要和获取到的构造方法的参数一致

如果获取到 private修饰的构造方法时,需要临时取消权限校验

🍁1.3 反射获取成员变量

🍁1.3.1 获取成员变量的方式

方法用途
getField(String name)获得某个公有的属性对象
getFields()获得所有公有的属性对象的数组
getDeclaredField(String name)获得某个属性对象
getDeclaredFields()获得所有属性对象的数组

  

public class Demo3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //获取字节码文件的对象
        Class clazz = Class.forName("com.li.reflect.Student");
        //获取所有的成员变量
        Field[] fields1 = clazz.getFields();
        System.out.println(Arrays.toString(fields1));
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        //获取单个成员变量
        Field res1 = clazz.getField("gender");
        System.out.println(res1);
        Field res2 = clazz.getDeclaredField("name");
        System.out.println(res2);
    }
}

这里的方法的区别对比着获取构造方法的区别是一样的 

在获取单个的成员变量时,传入的参数是要获取的变量名 

🍁1.3.2 获取成员变量的用途

可以获取到成员变量的权限修饰符,名称,数据类型

        //获取成员变量的权限修饰符
        int modifiers = res1.getModifiers();
        System.out.println(modifiers);
        //获取成员变量的名称
        String name = res1.getName();
        System.out.println(name);
        //获取成员变量的数据类型
        Class<?> type = res1.getType();
        System.out.println(type);

此外,还可以获取到当前成员变量记录的值

        //获取成员变量记录的值
        Student student = new Student("张三",18,"男");
        //临时取消权限校验
        res1.setAccessible(true);
        Object value = res1.get(student);
        System.out.println(value);

 这里需要注意的是,如果获取的值是private修饰的,还是需要设置临时取消权限校验

 获取到值之后,还可以进行修改

//修改
res1.set(student,"女");
System.out.println(student);

🍁1.4 反射获取成员方法

🍁1.4.1 获取成员方法的方式

方法用途
getMethod(String name, Class...<?> parameterTypes)获得该类某个公有的方法
getMethods()获得该类所有公有的方法的数组,包括继承的
getDeclaredMethod(String name, Class...<?> parameterTypes)获得该类某个方法
getDeclaredMethods()获得该类所有方法的数组,不包括继承的

getMethods()  获取的是该类所有公有的方法的数组,包括继承的,所以显示出了很多Person类本身没有定义的方法

 getDeclaredMethods()获取的是该类所有方法的数组,不包括继承的,

获取指定的方法:

在使用getDeclaredMethod获取指定方法时,第一个参数需要指定方法的名称,第二个参数需要指定方法的形参,如果是空参,那么第二个参数就空着不写

        //获取指定方法
        Method m = clazz.getDeclaredMethod("eat",String.class);
        System.out.println(m);
        

🍁1.4.2 获取成员方法的用途

可以获取方法的修饰符,名字,方法的形参,以及方法抛出的异常

        //获取方法修饰符
        int modifiers = m.getModifiers();
        System.out.println(modifiers);
        //获取方法的名字
        String name = m.getName();
        System.out.println(name);
        //获取方法的形参
        Parameter[] parameters = m.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        //获取方法抛出的异常
        Class[] exceptionTypes = m.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

获取到的方法也可以通过调用 invoke 方法运行

    /*Object invoke(Object obj,Object...args):运行方法
          参数一:用obj对象调用该方法
          参数二:调用方法的传递的参数(如果没有就不写)
          返回值:方法的返回值(如果没有就不写)
        * */
        Person person = new Person();
        m.setAccessible(true);
        //如果有返回值可以接收
        Object res = m.invoke(person, "饭");
        //打印返回值
        System.out.println(res);

🍁2. 枚举

 枚举是一种特殊的类,枚举中的每个元素都是该类的一个唯一实例,主要用途是把一组常量组织起来

在之前我们定义常量的时候是这样定义的:

public static final int RED = 1;

但是如果恰好此时有一个数字1,就可能被误认为是RED,这时就可以通过枚举来组织常量 

在创建类时选择Enum类进行创建

🍁2.1 枚举的使用 

Enum类中的常用方法 

方法名称描述
values()以数组形式返回枚举类型的所有成员
ordinal()获取枚举成员的索引位置
valueOf()将普通字符串转换为枚举实例
compareTo()比较两个枚举成员在定义时的顺序
public enum EnumDemo1 {
    RED, BLACK, YELLO, BLUE;

    public static void main(String[] args) {
        EnumDemo1[] enumDemo1s = EnumDemo1.values();
        for (int i = 0; i < enumDemo1s.length; i++) {
            System.out.println(enumDemo1s[i] + " " + enumDemo1s[i].ordinal());
        }
        //根据字符串返回类中的实例
        EnumDemo1 res = EnumDemo1.valueOf("RED");
        System.out.println(res);
        //比较定义顺序
        System.out.println(RED.compareTo(BLUE));
    }
}

可以和switch语句一起使用:

public enum EnumDemo1 {
    RED, BLACK, YELLO, BLUE;

    public static void main(String[] args) {
        EnumDemo1 e1 = RED;
        switch (e1) {
            case RED:
                System.out.println("RED");
                break;
            case BLACK:
                System.out.println("BLACK");
            default:
                System.out.println("无法匹配");
        }
    }
}

 

在这里插入图片描述

 

 


 

 

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

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

相关文章

【算法】马踏棋盘(骑士周游)问题回溯算法实现以及使用贪心算法优化

目录 1.游戏规则 2.算法分析 3.解决步骤和思路 4.马踏棋盘算法的代码实现 4.1计算马儿还能走哪些位置 4.2马踏棋盘的核心代码 4.3马踏棋盘算法完整代码 4.4使用贪心算法进行优化 4.4.1思路 4.4.2代码实现 1.游戏规则 将马儿随机放在国际象棋的 8*8 棋盘的某个方格中…

阶段练习——minishell

目录 &#xff08;一&#xff09;文件复制&#xff08;my_cp函数&#xff09; &#xff08;二&#xff09;文件内容查看&#xff08;my_cat函数&#xff09; &#xff08;三&#xff09;切换目录&#xff08;my_cd函数&#xff09; &#xff08;四&#xff09;列出目录内容…

一款专为IntelliJ IDEA用户设计的插件,极大简化Spring项目中的API调试过程,功能强大(附源码)

前言 在软件开发过程中&#xff0c;尤其是Spring MVC(Boot)项目中&#xff0c;API调试调用是一项常见但繁琐的任务。现有的开发工具虽然提供了一些支持&#xff0c;但往往存在效率不高、操作复杂等问题。为了处理这些痛点&#xff0c;提升开发效率&#xff0c;一款新的工具应运…

python 捕获异常

捕获指定异常 e 是保存的异常信息 捕获多个异常

快速体验fastllm安装部署并支持AMD ROCm推理加速

序言 fastllm是纯c实现&#xff0c;无第三方依赖的高性能大模型推理库。 本文以国产海光DCU为例&#xff0c;在AMD ROCm平台下编译部署fastllm以实现LLMs模型推理加速。 测试平台&#xff1a;曙光超算互联网平台SCNet GPU/DCU&#xff1a;异构加速卡AI 显存64GB PCIE&#…

Selenium + Python 自动化测试18(数据驱动实现测试)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了数据驱动测试中如何读取Excel文件&#xff0c;今天我们试着进一步深入学习数据驱动。 本篇文章我们讨论一下如何使用数据驱动思想实现测试。 1、数据驱动框架…

从零开始学cv-5: 图像的仿射变换

文章目录 一&#xff0c;简介&#xff1a;二&#xff0c;图像仿射变换详解2.1&#xff0c;图像平移&#xff1a;2.2 &#xff0c;图像旋转&#xff1a;2.3&#xff0c;仿射变换&#xff1a; 一&#xff0c;简介&#xff1a; 仿射变换&#xff08;Affine Transformation 或 Aff…

Lumina学术引擎免费问世,性能超谷歌学术5倍

Lumina介绍 Lumina是一款完全免费的AI学术搜索引擎&#xff0c;借助强大的数据库和高效的匹配速度。利用超过 15 种模型从超过 100 万篇期刊文章中找出最相关的来源&#xff0c;从而构建答案。搜索结果相关性平均比谷歌学术高出5倍&#xff0c;支持超1亿研究对象搜索&#xff…

8.18日学习打卡---Spring Cloud Alibaba(五)

8.18日学习打卡 目录&#xff1a; 8.18日学习打卡 RocketMQ什么是RocketMQ生产者和消费者技术架构 RocketMQ安装与配置环境搭建与测试RocketMQ管理命令 RocketMQ发送消息普通消息顺序消息之全局消息顺序消息之局部消息消费者消费消息延迟消息延迟消息代码实现单向消息批量消息过…

【HarmonyOS】云开发-用户自动认证

背景 华为云服务提供了统一认证的云服务&#xff0c;支持手机、邮箱等自定义登录服务&#xff0c;并且提供了免费使用的额度&#xff0c;这样子方便中小企业或者项目快速的开发工作。下面是支持的认证方式&#xff1a; 操作步骤 1.AGC(AppGallery Connect)创建项目 在AGC界…

C++ | Leetcode C++题解之第342题4的幂

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isPowerOfFour(int n) {return n > 0 && (n & (n - 1)) 0 && n % 3 1;} };

zabbix监控进程、日志、主从状态和主从延迟

zabbix监控进程、日志、主从状态和主从延迟 监控进程1、下载服务2、编写脚本3、编写zabbix_agentd.conf4、新建监控项配置触发器5、查看邮件 监控日志1、上传log.py的2、编写zabbix_agentd.conf3、新建监控项配置触发器 监控数据库主从状态1、编写/etc/hosts&#xff08;master…

IOS 09 R.swift框架和使用方法

R.swift框架主要是实现通过类字段访问字符串&#xff0c;图片&#xff0c;等资源&#xff1b;类似Android那边通过R类访问&#xff0c;好处是有提示&#xff0c;如果缺少资源&#xff0c;直接就是编译错误&#xff1b;OC类似的功能叫R.objc。 添加依赖 添加依赖 #将资源&…

第八周:机器学习笔记

第八周机器学习笔记 摘要Abstract机器学习1. 鱼和熊掌和可兼得的机器学习1.1 Deep network v.s. Fat network 2. 为什么用来验证集结果还是不好&#xff1f; Pytorch学习1. 卷积层代码实战2. 最大池化层代码实战3. 非线性激活层代码实战 总结 摘要 本周学习对李宏毅机器学习视…

AI学习记录 - Word2Vec 超详细解析

创作不易&#xff0c;点个赞 我们有一堆文本&#xff0c;词汇拆分 sentences ["jack like dog", "jack like cat", "jack like animal","dog cat animal", "banana apple cat dog like", "dog fish milk like"…

URP平面阴影合批处理 shadow

闲谈 相信大家在日常工作中发现了一个问题 &#xff0c; urp下虽然可以做到3个Pass 去写我们想要的效果&#xff0c;但是&#xff0c;不能合批&#xff08;不能合批&#xff0c;那不是我们CPU要干冒烟~&#xff01;&#xff09; 好家伙&#xff0c;熊猫老师的偏方来了 &#x…

【数值方法-Python实现】Crout分解+追赶法实现

涉及Crout分解、追赶法的线性方程组求解方法的Python实现。 原文链接&#xff1a;https://www.cnblogs.com/aksoam/p/18366119 Codes def CroutLU(A:np.ndarray)->Tuple[np.ndarray,np.ndarray]:"""Crout LU分解算法,ALUinput:A: (n,n) np.ndarray,方阵out…

DrissionPage自动化获取城市数据内容

一、获取页面内容 二、最终结果 上海市 约收录140个指标 查看98075次 人均GDP 153299元 公交车 17899辆 户籍人口 1469.3万人 三、代码 from DrissionPage._pages.chromium_page import ChromiumPage import time page ChromiumPage() page.get(https://www.swguancha.com/…

【Delphi】中多显示器操作基本知识点

提要&#xff1a; 目前随着计算机的发展&#xff0c;4K显示器已经逐步在普及&#xff0c;笔记本的显示器分辨率也都已经超过2K&#xff0c;多显示器更是普及速度很快。本文介绍下Delphi中操作多显示器的基本知识点&#xff08;Windows系统&#xff09;&#xff0c;这些知识点在…

UniFab 是一款由人工智慧驅動的視訊增強器+ crack

UniFab 是一款功能强大的视频处理工具,包括 10 个基于 AI 的功能。使用 UniFab,您可以提高视频和音频质量、将视频转换为不同的格式、根据自己的喜好编辑视频等等。以下是适用于 Windows 的 UniFab 程序的简要说明: 视频转换器。UniFab 支持 1000 多种视频格式的转换,包括 …