Java 中的反射和枚举

简介: Java 中的反射和枚举

引言



在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量或成员方法是私有的或只对系统应用开放,这时候就可以利用 Java 的反射机制通过反射来获取所需的私有成员或方法,当然,公开的成员变量和方法显然也能通过反射获取得到。


反射最重要的用途就是开发各种通用框架,比如在 spring 中,我们将所有的类Bean 交给 spring 容器管理,无论是 XML 配置 Bean 还是注解配置,当我们从容器中获取 Bean 来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring 根据这些信息,需要创建 Bean,spring 动态的这些类。


一、什么是反射



Java 的反射机制表示在运行状态中,对于任意一个类或者说对于任意一个对象,都能够调用它的任意方法和属性(主要解决调用私有方法和私有属性的问题)。这样一来,我们就可以修改部分类型信息,而这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。


二、通过反射获取对象的三种方式



通过反射机制获取对象的三种方式中,方式一用的最多。


创建一个包 demo1,在包中创建一个 java 文件,里面放着两个类,即类 Student 和 类 Test1,如下所示:


那么下面的方式一需要指明类的全路径,如果有包需要加包的路径。


Class<?> c1 = Class.forName("demo1.Student"); //用的情况最多


/**
 * 演示 获取对象的三种方式
 */
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 eating");
    }
    public void sleep(){
        System.out.println("I am sleeping");
    }
    private void function(String str) {
        System.out.println(str);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws ClassNotFoundException{
        //获得 Class 对象的三种方式
        //不管使用哪种方式来获取 Class 对象,此时对象只有一个
        //方式一
        Class<?> c1 = Class.forName("demo1.Student"); //用的情况最多
        //方式二
        Class<?> c2 = Student.class;
        //方式三
        Student student = new Student();
        Class<?> c3 = student.getClass();
        System.out.println(c1==c2);
        System.out.println(c1==c3);
        System.out.println(c2==c3);
    }
}


输出结果:


c3a9b62834d74bd0a2632dfd4f09650c.png


三、演示反射机制的一些方法



在刚刚的包 demo1 中,我们创建第二个 java 文件,里面创建四个类,用来测试反射机制来拿到 Student 类中的相关信息。


接下来我们测试反射机制常用的四个方法:


① 通过 Class 类的 newInstance( )方法获取学生实例

② 通过 Constructor 类 的 getDeclaredConstructor( )方法,获得私有的构造方法(公开的构造方法也可通过反射获得)

③ 通过 Field 类的 getDeclaredField( )方法获得对象中私有的成员变量(公有的成员变量也可通过反射获得)

④ 通过 Method类的 getDeclaredMethod( )方法获得对象中私有的成员方法(公有的成员变量也可通过反射获得)


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectClass {
    /**
     * 通过 Class 类的 newInstance()方法 获取学生实例
     */
    public static void reflectNewInstance() {
        try {
            //1. 拿到 Class 对象
            Class<?> c1 = Class.forName("demo1.Student");
            Student student = (Student) c1.newInstance();
            //2. 直接打印
            System.out.println(student);
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 反射私有的构造方法(公开私有皆可)
     */
    public static void reflectPrivateConstructor(){
        try {
            //1. 拿到 Class 对象
            Class<?> c1 = Class.forName("demo1.Student");
            //2. 获得该类中与参数类型匹配的构造方法
            //例如:Student 类的公开和私有的构造方法都可以获取到
            Constructor<?> constructor = c1.getDeclaredConstructor(String.class, int.class);
            constructor.setAccessible(true); // 设置为true后可修改访问权限
            Student student = (Student) constructor.newInstance("linxi", 13);
            System.out.println(student);
        } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException
                 | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 反射私有的成员变量(公开私有皆可)
     */
    public static void reflectPrivateField() {
        try {
            //1. 拿到 Class 对象
            Class<?> c1 = Class.forName("demo1.Student");
            Student student = (Student) c1.newInstance();
            //2. 获得对象中私有的成员变量并给其赋值(公有也可进行操作)
            Field field = c1.getDeclaredField("name");
            field.setAccessible(true);
            field.set(student,"Jack");//给指定对象私有的成员变量赋值
            System.out.println(student);
        } catch (ClassNotFoundException | InstantiationException
                 | IllegalAccessException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 反射私有的成员方法(公开私有皆可)
     */
    public static void reflectPrivateMethod() {
        try {
            //1. 拿到 Class 对象
            Class<?> c1 = Class.forName("demo1.Student");
            Student student = (Student) c1.newInstance();
            //2. 获得对象中私有的成员方法并给其赋值(公有也可进行操作)
            Method method = c1.getDeclaredMethod("function", String.class);
            method.setAccessible(true);
            method.invoke(student,"拿到私有方法");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                 | NoSuchMethodException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) {
        reflectNewInstance();
        reflectPrivateConstructor();
        reflectPrivateField();
        reflectPrivateMethod();
    }
}


输出结果:


174509e1390a41f5a2bd037f1f25cb58.png


四、枚举



枚举类的本质:枚举类是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示继承 Enum ,但在 Java 中,它都默认继承了Enum 类。


源代码中的 Enum 类是抽象类,其作用就是用来被继承。


fac92dfbdda241c68a79a556e06ce19b.png


1. 语法


public enum TestEnum {
  RED,BLACK,GREEN; //列举某个事物的颜色
}


2. 枚举的一些方法


5360d1814a6d4ac3aa33c039fc9cd30b.png


3. 演示1


public enum TestEnum {
    RED,BLACK,GREEN,WHITE;
    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() );
        }
        System.out.println("-----------------");
        System.out.println(BLACK.compareTo(RED)); //依照索引下标比较
        System.out.println(BLACK.compareTo(WHITE));
    }
}


输出结果:


8313cad24b0e40928996df6427ef2492.png


4. 演示2


public enum TestEnum2 {
    RED("red",1),BLACK("black",2),
    WHITE("white",3),GREEN;
    public String color;
    public int ordinal;
    //1. 当枚举对象有参数后,需要提供相应的构造函数
    //2. 枚举的构造函数默认是私有的
    TestEnum2 (String color,int ordinal) { //private
        this.color = color;
        this.ordinal = ordinal;
    }
    TestEnum2(){
    }
    public static void main(String[] args) {
    }
}


5. 枚举的优缺点


优点:

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


缺点:

不可被继承,无法扩展


6. 枚举与反射


枚举非常安全,不能通过反射来获取到枚举的实例对象


7. 学完线程再回过头看问题


如何实现一个线程安全的单例模式(只能获取一个实例对象)?


通过枚举实现。


目录
相关文章
|
13天前
|
Java 数据库连接 Spring
反射-----浅解析(Java)
在java中,我们可以通过反射机制,知道任何一个类的成员变量(成员属性)和成员方法,也可以堆任何一个对象,调用这个对象的任何属性和方法,更进一步我们还可以修改部分信息和。
|
2月前
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
125 60
|
2月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
58 24
|
2月前
|
监控 Java
Java基础——反射
本文介绍了Java反射机制的基本概念和使用方法,包括`Class`类的使用、动态加载类、获取方法和成员变量信息、方法反射操作、以及通过反射了解集合泛型的本质。同时,文章还探讨了动态代理的概念及其应用,通过实例展示了如何利用动态代理实现面向切面编程(AOP),例如为方法执行添加性能监控。
|
2月前
|
Java
Java的反射
Java的反射。
39 2
|
3月前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
45 0
[Java]反射
|
3月前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
34 2
|
4月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
98 5
|
4月前
|
安全 Java 开发者
Java 枚举(enum)详解
Java 中的枚举(`enum`)是一种特殊的数据类型,用于定义一组固定的常量,提升代码的类型安全性和可读性。枚举使用 `enum` 关键字定义,支持方法和构造函数,具有类型安全、单例、自动序列化等特点,并且可以遍历和用于 `switch` 语句中。实际应用包括状态机、指令集、类型标识等场景。枚举使代码更加清晰易维护。
317 1
|
3月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
29 0