反射&枚举

1、定义

java的反射机制是在运行状态中,对于任意一个类,都能直到这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性,既然能够拿到那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

2、用途

*在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用java的反射机制通过反射来获取所需的私有成员或方法

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

3、反射的基本信息

java程序中血多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,例如Person p=new Student();这句代码中p在编译时类型为Person,运行时为Student。程序需要在运行时发现对象和类的真实信心,而通过使用反射程序就能判断出该对象和类属于哪些类。

4、反射相关的类

反射&枚举_第1张图片

 4.1、Class的反射机制

反射&枚举_第2张图片

 4.2、获取类对象的三种方式

在反射之前,我们需要做的第一步就是先拿到当前需要反射类的对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意方法和属性,既然能拿到,那么,就可以修改部分类型信息

第一种:使用Class.forName("类的全路径名");静态方法

第二种:使用.Class方法

第三种:使用类对象的getClass()方法

示例:


/**
 * 获取类对象方式
 */
public class Reflection01 {
    public static void main(String[] args) {
        //1、通过类来获取
        Class studentClass=Student.class;
        //2、通过实例对象来获取
        Student student=new Student();
        Class classByInstance=student.getClass();
        Class classByReflect=null;
        try {
            //通过反射来获取
            classByReflect=Class.forName("Day20221201.Test11.Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //判断这三个对象是否是同一个对象
        System.out.println("===========使用==判断是否相等============");
        System.out.println(studentClass==classByReflect);
        System.out.println(classByReflect==classByInstance);
        System.out.println(studentClass==classByInstance);
        System.out.println("===========使用equals()判断是否相等============");
        System.out.println(studentClass.equals(classByReflect));
        System.out.println(classByReflect.equals(classByInstance));
        System.out.println(classByInstance.equals(studentClass));
    }
}

反射&枚举_第3张图片

 

4.3、反射的使用


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Reflection02 {
    /**
     * 通过反射创建一个新的实例对象
     */
    public static void reflectNewInstance(){
        System.out.println("========通过反射创建一个新的实例对象==========");
        try {
            //1、获取类对象
            Class clazz=Class.forName("Day20221201.Test11.Student");
            System.out.println(clazz.getName());
            //2、通过类对象创建一个新的实例对象
            Student student= (Student) clazz.newInstance();
            student.setAge(18);
            //打印一下
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过反射操作构造方法
     */
    public static void reflectConstructor(){
        System.out.println("=========通过反射操作构造方法=========");
        try {
            //1、获取类对象
            Class clazz=Class.forName("Day20221201.Test11.Student");
            //2、通过类对象获取构造方法
            //Constructor[] constructors=clazz.getConstructors();//可以获得到所有public权限的构造方法
            Constructor[] constructors=clazz.getDeclaredConstructors();//获取已经定义的构造方法,包括私有的
            for (int i = 0; i < constructors.length; i++) {
                System.out.println(constructors[i]);
            }
            //3、获取一个指定的构造方法
            Constructor constructor=clazz.getConstructor();
            //4、通过构造方法创建一个新的实例对象
            Student student= (Student) constructor.newInstance();
            System.out.println(student);
            student.setName("鸡你太美");
            System.out.println(student);
            //5、调用私有的,多个参数的构造方法去创建对象
            Constructor constructor1=clazz.getDeclaredConstructor(String.class,int.class);
            //修改私有方法的访问权限
            constructor1.setAccessible(true);
            Student student1= (Student) constructor1.newInstance("咯咯",18);
            System.out.println("通过私有构造方法创建的对象:"+student1);
        } 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();
        }
    }

    /**
     * 通过反射操作属性
     */
    public static void reflectField(){
        System.out.println("========通过反射操作属性========");
        try {
            //1、获取类对象
            Class clazz=Class.forName("Day20221201.Test11.Student");
            //2、获取所有发生的数组
            //所有访问权限为public的属性
            //Field[] fields=clazz.getFields();
            //获取所有访问权限或所有定义的属性
            Field[] fields=clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                System.out.println(fields[i]);
            }
            //创建一个对象
            Student student= (Student) clazz.newInstance();
            System.out.println(student);
            //操作这个属性
            //先获取一个属性
            Field fieldAge=clazz.getField("age");
            //给这个属性设置一个值
            fieldAge.set(student,18);
            System.out.println(student);
            //获取私有属性并赋值
            Field fieldName=clazz.getDeclaredField("name");
            //修改访问权限
            fieldName.setAccessible(true);
            fieldName.set(student, "只因坤坤爱坤坤");
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    public static void reflectMethod(){
        System.out.println("=======通过反射操作方法========");
        try {
            //1、创建类对象
            Class clazz=Class.forName("Day20221201.Test11.Student");
            //2、获取所有方法信息
            //所有访问修饰符为public的方法
            //包括父类的方法都可以获取到
            //Method[] methods=clazz.getMethods();
            Method[] methods=clazz.getDeclaredMethods();
            for (Method items:methods) {
                System.out.println(items);
            }
            //创建一个实例对象
            Student student= (Student) clazz.newInstance();
            //通过指定对象获取去获取一个指定的量
            Method methodSleep=clazz.getDeclaredMethod("sleep");
            methodSleep.invoke(student);
            //调用一个私有的量
            Method methodFunction=clazz.getDeclaredMethod("function",String.class);
            //修改访问权限
            methodFunction.setAccessible(true);
            methodFunction.invoke(student,"通过·反射传入的参数");
        } 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();
        }
    }
    public static void main(String[] args) {
        // 通过反射创建一个新的实例对象
        reflectNewInstance();
        // 通过反射操作构造方法
        reflectConstructor();
        // 通过反射操作属性
        reflectField();
        // 通过反射操作方法
        reflectMethod();
    }
}

反射&枚举_第4张图片

 

5、反射的优点和缺点

优点:

*对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法

*增加程序的灵活性和扩展性,降低耦合性,提高自适应能力

*反射已经应用在了很多流行的框架如:Spring、Structs等等

缺点:

*使用反射会有效率问题。会导致程序效率降低

*反射技术绕过了源代码技术,因而会带来维护问题。反射代码比相应的代码更加复杂

7、枚举的使用

枚举是在JDK1.5之后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式

public static  final int RED = 1;
public static  final int GREEN = 2;
public static  final int BLACK = 3;

但是常量列举有不好的地方,例如:可能碰巧有个数字1,但是它误以为是RED,现在我们可以直接用枚举类型来进行组织,这样一来,就拥有了类型——枚举类型,而不是普通的整型1;

public enum TestEnum {
  RED,BLACK,GREEN;
}

优点:将常量组织起来统一进行管理

应用场景:错误状态码,消息类型,颜色划分,状态机等等

8、使用

8.1、switch语句


public class Enum01 {
    public static void main(String[] args) {
        int color=1;
        switch(color){
            case 1:
                System.out.println("这是红色");
                break;
            case 2:
                System.out.println("这是黄色");
                break;
            case 3:
                System.out.println("这是蓝色");
                break;
            case 4:
                System.out.println("这是绿色");
                break;
        }
        int a=10;
        int b=20;
        System.out.println(sum(a,b));
        System.out.println(sum(a,color));
    }

    private static int sum(int x, int y) {
        return x+y;
    }
}

反射&枚举_第5张图片

 

8.2、Enum的常用方法

反射&枚举_第6张图片

 8.3、示例

先定义枚举类型


public enum ColorEnum {
    RED,GREEN,BLACK,WHITE;
}

public enum ResultEnum {
    SUCCESS(200,"成功"),
    ERROR_CLIENT(400,"客户端出错了"),
    ERROR_SERVER(500,"服务器出错了"),
    NONE(-99999,"未定义");
    private int code;
    private String message;

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    ResultEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    @Override
    public String toString() {
        return "ResultEnum{" +
                "code=" + code +
                ", message='" + message + '\'' +
                '}';
    }
    public ResultEnum valueOf(int Code){
        switch(code){
            case 200:
                return SUCCESS;
            case 400:
                return ERROR_CLIENT;
            case 500:
                return ERROR_SERVER;
        }
        return NONE;
    }
}

public class Enum02 {
    public static void main(String[] args) {
        ColorEnum colorEnum=ColorEnum.WHITE;
        switch (colorEnum){
            case RED:
                System.out.println("鸡你太美");
                break;
            case GREEN:
                System.out.println("唱跳、rap、篮球");
                break;
            case BLACK:
                System.out.println("小黑子");
                break;
            case WHITE:
                System.out.println("中分头、背带裤,我叫坤坤你记住");
                break;
        }
    }
}

反射&枚举_第7张图片


public class Enum03 {
    public static void main(String[] args) {
        ResultEnum resultEnum=ResultEnum.SUCCESS;
        System.out.println("状态码:"+resultEnum.getCode()+",描述;"+resultEnum.getMessage());
        ResultEnum resultEnum1=ResultEnum.NONE;
        System.out.println("状态码:"+resultEnum1.getCode()+",描述;"+resultEnum1.getMessage());
    }
}

 反射&枚举_第8张图片

 


public class Enum04 {
    public static void main(String[] args) {
        //value()方法演示
        ResultEnum[] values=ResultEnum.values();
        for (ResultEnum items:values) {
            System.out.println(items);
        }
        //valueOf方法演示
        ResultEnum resultEnum=ResultEnum.valueOf("ERROR_CLIENT");
        System.out.println("状态码:"+resultEnum.getCode()+",描述:"+resultEnum.getMessage());
        //CompareTo()方法比较
        System.out.println(ResultEnum.SUCCESS.compareTo(ResultEnum.ERROR_CLIENT));
        System.out.println(ResultEnum.SUCCESS.compareTo(ResultEnum.SUCCESS));
        //ordinal()方法
        System.out.println("========================");
        for (int i = 0; i < values.length; i++) {
            System.out.println("枚举:"+values[i]+",ordinal:"+ values[i].ordinal());
        }
    }
}

反射&枚举_第9张图片

 


import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Enum05 {
    //通过反射创建一个枚举
    public static void main(String[] args) {
        try {
            //获取类对象
            Class clazz=Class.forName("Day20221201.Test11.ResultEnum");
            Constructor[] constructors=clazz.getDeclaredConstructors();
            for (int i = 0; i < constructors.length; i++) {
                System.out.println(constructors[i]);
            }
            //获取构造方法
            Constructor constructor=clazz.getDeclaredConstructor(String.class,int.class,int.class,String.class);
            //修改访问权限
            constructor.setAccessible(true);
            Object o = constructor.newInstance("ERROR_NETWORK", 4, 600, "网络错误");
        } 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();
        }
    }
}

 9、结论:

针对Enum05的结果,可以确定不能通过new或是反射去创建一个枚举对象,所以我们认为枚举是比较安全的,利用反射性可以实现一个单例模式的类(单例模式就是全局唯一,只有一个对象)

*枚举本身就是一个类,其构造方法默认是私有的,且都继承于java.long.Enum

*枚举可以避免反射和序列化问题

*便于让我们把常量组织起来,统一管理

你可能感兴趣的:(jvm,数据结构,java,开发语言)