认识Java中的反射与枚举

news2024/10/7 17:28:20

作者~小明学编程 

文章专栏JavaSE基础

格言目之所及皆为回忆,心之所想皆为过往

目录

反射

什么是反射?

常用的反射类

Class类

Class类中的相关方法

常用获得类中属性相关的方法

获得类中注解相关的方法

获得类中构造器相关的方法

获得类中方法相关的方法

用法演示

获取class对象

反射构造方法

反射属性

 反射方法

枚举

引入

枚举的使用

枚举中的方法

构造方法

枚举优点和缺点


反射

什么是反射?

反射是一种在代码的运行状态下依然能获取任何的类,并且能获取该类的所有的属性方法,并且我们还能去修改它,这就是Java的反射机制,非常的强,今天带大家去认识这种机制。

常用的反射类

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

Class类

在我们的Java文件被编译之后将会生成一个.class的文件,然后我们的jvm就会去解读这个文件,将会把它当作一个对象,该对象为java.lang.Class,所以我们的每一个Java文件都会被解析为这样的一个对象,我们的反射机制就是获取这个实例对象然后去获取该类的所有属性甚至去改变它。

Class类中的相关方法

方法用途
getClassLoader()获得类的加载器
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的)
forName(String className)根据类名返回类的对象
newInstance()创建类的实例
getName()获得类的完整路径名字

常用获得类中属性相关的方法

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

获得类中注解相关的方法

方法用途
getAnnotation(Class annotationClass)返回该类中与参数类型匹配的公有注解对象
getAnnotations()返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass)返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations()返回该类所有的注解对象

获得类中构造器相关的方法

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

获得类中方法相关的方法

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

用法演示

class Student{
    //私有属性name
    private String name = "bit";
    //公有属性age
    public int age = 18;
    //不带参数的构造方法
    public Student(){
        System.out.println("Student()");
    }
    private Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Student(String,name)");
    }
    private void eat(){
        System.out.println("i am eat");
    }
    public void sleep(){
        System.out.println("i am pig");
    }
    private void function(String str) {
        System.out.println(str);
    } 
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

这是我们的一个Person类,里面是我们经过包装的方法和属性,下面我们就用反射来演示一下我们怎么用反射来获取里面的私有属性。

获取class对象

我们获取class对象有三种方式:

1.在我们知道该类的路径的时候我们可以使用 Class.forName("类的全路径名")的方式获取class对象。

   Class<?> c1 = Class.forName("reflectdemo.Student");//使用 Class.forName("类的全路径名"); 

但是这种方式可能会抛出异常,所以我们要做一个异常处理。

2.使用.class的方式

        Class<?> c2 = Student.class;//使用 .class 方法。

我们类.class这同时也说明了我们的每一个类都有一个隐藏的.class的属性。

3.使用类对象的 getClass() 方法

        Student student = new Student();
        Class<?> c3 = student.getClass();//使用类对象的 getClass() 方法

注意:

    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> c1 = Class.forName("reflectdemo.Student");//使用 Class.forName("类的全路径名"); 静态方法。
        Class<?> c2 = Student.class;//使用 .class 方法。
        Student student = new Student();
        Class<?> c3 = student.getClass();//使用类对象的 getClass() 方法
        System.out.println(c1==c2&&c2==c3);//true

    }

虽然我们用了三种不同的方式去获取我们的类对象但是我们获取的c1,c2,c3都是一样的。

反射构造方法

我们知道我们的构造方法其实是可以用private来修饰的,这样的话我们就不能自动调用了,但是我们可以通过反射来破坏其封装然后调用构造方法。

    //获取私有的构造方法
    public static void reflectPrivateConstructor() {
        try {
            Class<?> c1 = Class.forName("reflectdemo.Student");//获取类
            Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class);//获取构造方法
            constructor.setAccessible(true);
            Student student = (Student) constructor.newInstance("haha",15);//new一个实例
            System.out.println(student);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

其思路就是,首先获取我们的class类,然后我们想要修改构造方法,那么就传入参数找到我们的构造方法,然后修改属性,最后通过newInstance方法获取实例类。

 可以看到已经在调用私有构造方法了。

反射属性

    public static void reflectPrivateField() {
        try {
            Class<?> c1 = Class.forName("reflectdemo.Student");//拿到当前需要反射的类的Class对象
            Student student = (Student) c1.newInstance();//创建类的实例
            Field field = c1.getDeclaredField("name");//通过getDeclaredField方法获取我们类成员的私有属性(共有的也能获取)
            field.setAccessible(true);
            field.set(student,"haha");
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

我们先获取类,然后实例对象,通过getDeclaredField找到我们的属性,然后修改权限,接着修改当前属性。

 反射方法

    public static void reflectPrivateMethod() {
        try {
            Class<?> c1 = Class.forName("reflectdemo.Student");//拿到当前需要反射的类的Class对象
            Student student = (Student)c1.newInstance();//创建类的实例
            Method method = c1.getDeclaredMethod("function", String.class);
            method.setAccessible(true);
            method.invoke(student,"hehe");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

1.获取类class

2.实例一个对象

3.获取我们想要的方法

4.修改权限

5.可以调用该方法了

枚举

引入

枚举是什么呢?我们为什么要用枚举?

说到枚举我们就不得不说到我们的常量了,我们枚举的作用就是将常量组织起来。

枚举的使用

public enum TestEnum {
    RED,BLUE,GREEN,BLACK,WHITE;
    public static void main(String[] args) {
        System.out.println(TestEnum.BLACK);//BLACK
        TestEnum testEnum = TestEnum.BLUE;
        switch (testEnum) {
            case BLACK:
                System.out.println("black");
                break;
            case RED:
                System.out.println("red");
                break;
            case GREEN:
                System.out.println("green");
                break;
            case BLUE:
                System.out.println("blue");
                break;
            case WHITE:
                System.out.println("white");
                break;
            default:
                System.out.println("no");
        }
    }
}

我们创建一个枚举类,然后我们的枚举常量就直接定义在我们的类中。

枚举中的方法

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

以上几种就是我们枚举中常用的方法,下面给大家演示一下使用方式。

    public static void main(String[] args) {
        TestEnum[] testEnums = TestEnum.values();
        for (int i = 0; i < testEnums.length; i++) {
            System.out.println(testEnums[i]+" "+testEnums[i].ordinal());
        }
    }

    public static void main(String[] args) {
        TestEnum testEnum1 = TestEnum.RED;
        TestEnum testEnum2 = TestEnum.BLUE;
        System.out.println(testEnum1.compareTo(testEnum2));//-1
        System.out.println(GREEN.compareTo(RED));//2
    }

在我们介绍完这些方法之后,不知道大家想过这么个事情没有,我们的这些方法从哪里来的,我们通过我们的枚举类的当前引用或者枚举常量就能调用我们的方法了这是为啥呢?

我们来看看源码

 可以看到我们的枚举类是一个抽象类,我们的一般的方法都在里面,这是因为我们自己所创建的枚举类都是默认继承我们的抽象的Enum类的。

构造方法

public enum TestEnum {
    RED("aa",3),BLUE("bb",3),GREEN("cc",3),
    BLACK("dd",3),WHITE("ee",3);
    private String str;
    private int i;
    TestEnum(String aa, int i) {
        this.str = aa;
        this.i = i;
    }
}

我们可以给枚举定义一个构造方法根据我们想要的参数定义,枚举的构造方法默认是私有的,这点需要记住。

注意:

1.我们自己所创建的枚举类都是默认继承我们的抽象的Enum类的。

2.枚举的构造方法默认是私有的。

3.枚举非常安全,我们枚举是不能通过反射来获取其中的其中的实例对象

枚举优点和缺点

优点:
1. 枚举常量更简单安全 。
2. 枚举具有内置方法 ,代码简洁。

缺点:
不能继承和扩展。
 

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

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

相关文章

Java中的运算符--短路运算

文章目录0 写在前面1 介绍2 举例2.1 逻辑与 &&2.2 逻辑或 ||3 小技巧4 写在最后0 写在前面 JAVA中有两个短路运算&#xff0c;一个是短路与&#xff0c;一个是短路或。 所谓短路&#xff0c;就是当一个参与运算的操作数足以推断该表达式的值时&#xff0c;另一个操作数…

VirtualBox安装CentOS7

一&#xff1a;、下载CentOS7的镜像 下载地址&#xff1a;Downloadhttps://www.centos.org/download/ 进入后有三个版本可以选择&#xff1a; 1、DVD ISO 标准安装版&#xff0c;一般下载这个就可以了&#xff08;推荐&#xff09;本文以此为例&#xff01; 2、Everything…

2023跨年代码(烟花+雪花)

一眨眼&#xff0c;马上就2023年了&#xff0c;祝大家在新的一年里&#xff1a;身体健康平安&#xff0c;生活充实饱满&#xff0c;事业步步高升&#xff0c;心情阳光灿烂&#xff0c;财运滚滚而来&#xff0c;家庭美满幸福&#xff0c;新年开心快乐! 本文将给大家分享一些跨年…

GitHub Copilot

介绍 GitHub Copilot 是人工智能编程助手&#xff0c;它可以帮助你编写程序。在你用visual studio或visual studio code等软件设计工具进行编程时&#xff0c;它可以直接给你整行或整个方法的代码提示&#xff0c;并且提供多种提示方案供你选择。他是由openai公司&#xff08;马…

docker 及docker-compose network概念及操作详解

1. docker network概述 Docker通过使用网络驱动程序【network drivers】支持网络容器。默认情况下&#xff0c;Docker提供了多个网络驱动程序&#xff0c;如bridge 和overlay驱动程序。用户也可以自己写一个网络驱动插件&#xff0c;这样就可以创建自己的驱动程序。 Docker引…

SpringBoot整合Mybatis-Plus分页失效

场景&#xff1a;项目整合mybatis-Plus分页失效&#xff0c;current一直是1&#xff0c;size一直是10&#xff0c;total属性一直是0&#xff0c;数据分页不准 先看官网给的示例&#xff1a; 解决方案是新建mybatis-Plus的配置文件&#xff1a; package com.amc.config;import …

[附源码]计算机毕业设计海南琼旅旅游网Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

混检阳性概率的计算(贝叶斯定理的一个应用例)

目录 1. 混检阳性概率的计算 2. 混管阳性时你阳性的概率有多大&#xff1f; 2.1 贝叶斯分析结果的解释 1. 混检阳性概率的计算 目前核酸混检的基本做法是十混一&#xff0c;如果阳性人群分布完全随机&#xff0c;那么做十混一混检为阳性的概率有多大呢&#xff1f; …

对immutable的理解?如何应用在react项目中?

一、是什么 Immutable&#xff0c;不可改变的&#xff0c;在计算机中&#xff0c;即指一旦创建&#xff0c;就不能再被更改的数据 对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象 Immutable 实现的原理是 Persistent Data Structure&#xff08…

笔试强训(四十二)

目录一、选择题二、编程题2.1 解读密码2.1.1 题目2.1.2 题解2.2 走迷宫2.2.1 题目2.2.2 题解一、选择题 &#xff08;1&#xff09;tcp套接字中&#xff0c;不会阻塞的是哪一种操作&#xff08;D&#xff09; A.read B.write C.accept D.bind bind函数不会阻塞执行流的 &#…

Stm32旧版库函数3——nrf24l01 16位数据 51单片机发送与stm32接收

51代码&#xff1a; #include <reg52.h> #include <intrins.h> typedef unsigned char uchar; typedef unsigned char uint; //****************************************NRF24L01端口定义*************************************** sbit MISO P1^7; sbit …

runnable、callable、consumer、supplier

Java 没有委托的概念&#xff1b; 相反&#xff0c;如果需要一个指向函数的指针&#xff0c;可以创建内联匿名类&#xff08;或 Java 8 的 lambda 表达式&#xff09;&#xff0c;它们是为此建议设计的某些接口的实现&#xff08;也称为 Java 8 的功能接口&#xff09;。 然而&…

Java项目:SSM汽车维修中心管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本系统包括普通用户和管理员两种角色&#xff1b; 用户角色包含以下功能&#xff1a; 用户信息管理,查看车辆信息,维修记录查看等功能。 管理…

ORB-SLAM2 --- Tracking::GrabImageMonocular函数解析

目录 1.函数作用 2.到这步之前我们做了什么 3.code 4.函数解析 1.函数作用 哈哈哈&#xff0c;这其实应该是这个专栏的第一篇文章&#xff0c;也没什么必要写&#xff0c;但是我怕大家看的时候对单目还没有初始化没有进入跟踪线程前面比较懵逼&#xff0c;所以我补了此内…

Kali Linux安装go语言环境详解

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是Kali Linux安装go语言环境。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未…

【实操篇】Linux权限管理

目录 ●权限的基本介绍 ●rwx权限 ①rwx作用到文件 ②rwx作用到目录 ●修改权限——chmod ①、-、变更权限 ②数字变更权限 ●修改文件所有者——chown ●修改文件所在组——chgrp ●权限的基本介绍 从中随便找一行进行分析如下图所示&#xff1a; 1.文件类型 - &#x…

Hudi 0.12.0 搭建——集成 Hive3.1 与 Spark3.2

Hudi 搭建环境准备一、安装 Maven1.解压2.配置环境变量3.修改 Maven 下载源二、安装 Hudi1.解压2.配置环境变量3.修改 Hudi 下载源与对应版本号4.修改源码以兼容 Hadoop3.x5. 解决 Spark 依赖冲突6. 解决 Spark 向 Hudi 插入报错7. 编译 Hudi8. 启动测试集群其它生态安装与配置…

JSP ssh驾校管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 JSP ssh驾校管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式 开发。开发环境为TOMCAT7.0,Mye…

6秒钟读懂网络攻击和防御的有关产品理论

文章目录一 常见网络攻击1.病毒攻击2.DDos网络攻击3.木马攻击WebsSheLL4.渗透攻击数据拖取5.APP漏洞6.营销撸羊毛7&#xff0c;DDoS攻击挑战二&#xff0c;大禹基本功能1.基础防护2.BGP高防包3.BGP高仿IP4.棋牌盾三&#xff0c;大禹技术原理1.高仿IP牵引攻击流量&#xff0c;保…

Java安全--CC3

CC3和CC1和CC6的执行命令方式不一样。CC3使用的是动态类加载。我们把恶意代码写在加载类的静态构造方法中。需要注意的是&#xff1a; 当初始化的时候就会执行静态构造方法&#xff0c;defineClass的时候是不会执行静态构造代码块的&#xff0c;我们在找利用点的时候需要有new…