• JavaSE基础day24 枚举常用方法、反射



    一. 枚举的定义特点以及常用方法

    (一)  枚举类型中的常用方法

    1. ordinal(): 获取枚举类型中的枚举序数,序数根据定义的枚举项,从0开始,返回值int

    2. compareTo(E o) : 比较枚举项之间的顺序大小,方法调用枚举项的序数减去参数枚举项的序数

    3. name() : 将枚举项转换成String类型

    4. toString() : 将枚举项转换成String类型

    5. static <T> T valueOf(Class<T> type,String name) 是Enum类的静态方法,获取指定枚举类中的指定名称的枚举值

    6. static values() : 将一个枚举类型中的所有枚举项获取到,返回值类型枚举类型的数组

    public enum MyEnum {
        ONE,TWO,THREE,FOUR;
    }
    public class EnumMethod {
        public static void main(String[] args) {
         // 1.ordinal(): 获取枚举类型中的枚举序数,序数根据定义的枚举项,从0开始,返回值int
            System.out.println(MyEnum.ONE.ordinal());// 0
            System.out.println(MyEnum.THREE.ordinal());// 2
    
            // 2.compareTo(E o) : 比较枚举项之间的顺序大小,方法调用枚举项的序数减去参数枚举项的序数
            // 0 - 3
            System.out.println(MyEnum.ONE.compareTo(MyEnum.FOUR));// -3
    
           /* 3.name() : 将枚举项转换成String类型
            4.toString() : 将枚举项转换成String类型*/
    
            System.out.println(MyEnum.TWO.name());// TWO
            System.out.println(MyEnum.TWO.toString());// TWO
    
            //5.static <T> T valueOf(Class<T> type,String name) 是Enum类的静态方法,获取指定枚举类中的指定名称的枚举值
            MyEnum my1 = MyEnum.valueOf("THREE");
            System.out.println(my1);// THREE
    
            System.out.println("---------------------");
            MyEnum my2 = MyEnum.valueOf(MyEnum.class,"ONE");
            System.out.println(my2);// ONE
    
            // 6.static values() : 将一个枚举类型中的所有枚举项获取到,返回值类型枚举类型的数组
            MyEnum[] arr = MyEnum.values();
            for(MyEnum my : arr){
                System.out.println(my);
            }
        }
    }

    二. 反射

    (一)  虚拟机类加载机制

    2.1 虚拟机类加载机制概述

    虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制.

    2.2 类加载过程

    当程序要使用某个类时,如果该类还未被加载到内存中,系统会通过加载,连接,初始化三步来实现对这个类的加载.

    1. 加载

    (1) 就是指将class文件读入内存,并为之创建一个Class对象.

    任何类被使用时系统都会建立一个Class对象

    2. 连接

    (1) 验证是否有正确的内部结构,并和其他类协调一致

    (2) 准备负责为类的静态成员分配内存,并设置默认初始化值

    (3) 解析将类的二进制数据中的符号引用替换为直接引用

    3. 初始化

            主要对类变量进行初始化

                 a: 类还未被加载, 程序先加载并连接该类

                 b: 如该类还有直接父类, 则先初始化其直接父类

                 c: 有初始化语句,按顺序执行

     

    2.3 类的初始化时机

    什么时候这个类的字节码文件被加载?【什么时候创建出该类的字节码对象 Class对象】

    1.创建类的实例

    2.类的静态成员使用

    3.类的静态方法调用

    4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

    5.初始化某个类的子类

    6.直接使用java.exe命令来运行某个主类

    (二)  类加载器

    概述: 类加载器是负责加载类的对象,将class文件加载到内存中,并为之生成对应的java.lang.Class对象.

    2.1 类加载器的分类

    1. Bootstrap ClassLoader 引导类加载器,通常表示为null

            也被称为根类加载器,负责jre\lib目录下核心类的加载,比如System,String等.

    2. Extension ClassLoader 扩展类加载器

            负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录.

    3. Application ClassLoader 系统类加载器

            负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径.

    4. 自定义类加载器

            开发人员可以通过继承java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求.

    类加载器之间的关系是子父类, 但是不是继承关系

    -Bootstrap ClassLoader

      -Extension ClassLoader

          -Application ClassLoader

    import sun.net.spi.nameservice.dns.DNSNameService;
    
    public class ClassLoaderTest {
        public static void main(String[] args) {
            System.out.println(System.class.getClassLoader());// null
            System.out.println(String.class.getClassLoader());// null
            System.out.println(DNSNameService.class.getClassLoader());// sun.misc.Launcher$ExtClassLoader@677327b6
            System.out.println(ClassLoaderTest.class.getClassLoader());// sun.misc.Launcher$AppClassLoader@18b4aac2
    
            System.out.println("------------------------------");
            ClassLoader cl = ClassLoaderTest.class.getClassLoader();
            while(cl != null){
                System.out.println(cl);
                cl = cl.getParent();
            }
        }
    }

    2.2 双亲委派机制

    1. 双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器.每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载.

    2. 双亲委派模型工作过程:

            1)当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成.   

            2)当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成. 

            3)如果Bootstrap ClassLoader加载失败,就会让Extension ClassLoader尝试加载.

            4)如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载.

            5)如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载.

            6)如果均加载失败,就会抛出ClassNotFoundException异常.

    3.例子:

      当一个Hello.class这样的文件要被加载时.不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了.如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法.父类中同理会先检查自己是否已经加载过,如果没有再往上.注意这个过程,直到到达Bootstrap classLoader之前,都是没有哪个加载器自己选择加载的.如果父加载器无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException.

    2.3 ClassLoader类

    1. ClassLoader 叫做类加载器.虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流” 也就是.class字节码文件,这个动作放到java虚拟机外部去实现,以便让应用程序自己决定去如何获取所需要的类,实现这个动作的代模块称之为“类加载器”.把【.class】文件加载到jvm虚拟机当中,转换为一个Class的对象【类的字节码对象 类的类对象】

     

     

    2.ClassLoader的方法:        

            ClassLoader getParent()

                    返回父类加载器进行委派

    import sun.net.spi.nameservice.dns.DNSNameService;
    public class ClassLoaderTest {
        public static void main(String[] args) {
            System.out.println(System.class.getClassLoader());// null
            System.out.println(String.class.getClassLoader());// null
            System.out.println(DNSNameService.class.getClassLoader());// sun.misc.Launcher$ExtClassLoader@677327b6
            System.out.println(ClassLoaderTest.class.getClassLoader());// sun.misc.Launcher$AppClassLoader@18b4aac2
    
            System.out.println("------------------------------");
            ClassLoader cl = ClassLoaderTest.class.getClassLoader();
            while(cl != null){
                System.out.println(cl);
                cl = cl.getParent();
            }
        }
    }

    (三) 反射应用

    3.1 反射机制的概述

       反射是指在运行时去获取一个类的变量和方法信息.然后通过获取到的信息来创建对象,调用方法的一种机制.由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展.

     

      举例说明 :

      1. 例如项目工程中, 有两个类,Student, Teacher, 需要使用这两个类

      2. 因为要使用上述两类, 这个两个类对应的.class字节码文件就会被类加载器从磁盘路径上加载进入到内存中

      3. 一个类型一旦进入到内存,证明需要使用,证明代码需要运行, 这种状态就是动态的效果

      4. 类加载器为这个正在运行的.class字节码文件, 创建出一个对应的Class对象, 对象中包含了class文件中所有代码内容(可以包含类中所有成员变量, 构造方法,方法...)

      5. 使用Class对象, 获取出类型中所有的需要的成员, 这种使用方式称为反射

    3.2 获取Class类对象三种方式

    1.Class类: Class类型的实例表示正在运行的java应用程序的类或者接口.

    2.Class类的对象: 想获取和操作类中的内容,首先要获取类的字节码对象(Class类对象),每一个正在运行的类,都有对应的字节码对象,获取了类的字节码对象,就可以使用这个对象的所有方法,这些方法都定义在Class类型中.

     

    3.三种获取Class类对象的方式:

            1)类名.class属性

            2)对象名.getClass()方法

            3)Class.forName(全类名)方法

           全类名 : com.ujiuye.demos.Demo01 包名 + 类名

    public class Demo01_CLass对象获取三种方式 {
        public static void main(String[] args) throws ClassNotFoundException {
            String s = "abc";
            // 1. 直接使用类型名称.class, 获取这个类型的字节码文件对象
            Class<Person> c = Person.class;
            System.out.println(c);
    
            // 2. object父类中getClass(): 获取这个类型的字节码文件对象
            Person p = new Person();
            Class c1 = p.getClass();
            System.out.println(c1);
    
            // 3. Class类中静态方法功能内容: Class.forName(提供带有完整包名的类名),
            // 获取这个类的字节码文件对象
            Class c2 = Class.forName("com.ujiuye.reflect.Person");
            System.out.println(c2);
    
            // 注意: 一个类型的.class字节码文件加载进入到内存中之后, 类加载器会为这个字节码文件自动生成
            // 一个字节码文件对象, 对象中包含有文件的一切内容和功能, 这个对象只有一个, 存在于堆内存中
            // 上述的三个方法都是获取这个对象的手段
            System.out.println(c == c1);// true
            System.out.println(c1 == c2);// true
        }
    }

    3.3反射获取构造方法并使用

    1. Class类获取构造方法对象:

    方法分类:

    Constructor<?>[] getConstructors()

        返回所有public公共构造方法对象的数组

       

    Constructor<?>[] getDeclaredConstructors()

        返回所有构造方法对象的数组

       

    Constructor getConstructor(Class<?>... parameterTypes)

        返回单个公共构造方法对象

       

    Constructor getDeclaredConstructor(Class<?>...parameterTypes)

        返回单个构造方法对象

     

    2. 注意:

            getConstructor(Class<?>... parameterTypes)

            getDeclaredConstructor(Class<?>...parameterTypes)

    两方法的参数列表为可变参数,可变参数即参数的个数可以是任意个,0个,1个或者多个均可,任意的数据类型都有对应Class对象, 连基本数据数据类型也不例外 : int.class

     

    3. Constructor类型:

            1)Constructor类表达的含义就是一个类当中的构造方法,一个对象就表达了一个构造方法

            2)构造方法对象应该具有的功能: 获取构造方法各种信息(构造方法修饰符、构造方法名称、构造方法的参数列表、构造方法的注解),最基本的一个功能就是,创建对象.

     

    4. Constructor类用于创建对象的方法:

            T newInstance(Object...initargs) 根据指定的构造方法创建对象,参数为所运行构造方法需要的实际参数.

    public class Person {
        int i = 10;
        public Person(){}
    
        public Person(String name){
            System.out.println(name);
        }
    
        Person(String name, int age){
            System.out.println(name + "--" + age);
        }
    
        private Person(int age){
            System.out.println(age);
        }
    }
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class Demo02_ReflectConstructor {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            // 1. 获取到Person类型的字节码文件对象
            Class c = Class.forName("com.ujiuye.reflect.Person");
            // 2. 获取到Person中的所有的公共修饰的构造方法
            Constructor[] conArr  = c.getConstructors();
            for(Constructor con : conArr){
                System.out.println(con);
            }
    
            // 3.Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
            Constructor[] conArrAll = c.getDeclaredConstructors();
            for(Constructor con : conArrAll){
                System.out.println(con + "-----");
            }
    
            // 4.Constructor getConstructor(Class<?>... parameterTypes)回单个公共构造方法对象
            // 想要获取到公共修饰的, 空参数构造方法
            Constructor con1 = c.getConstructor();
            System.out.println(con1);
    
            // 5.Constructor getDeclaredConstructor(Class<?>...parameterTypes)返回单个构造方法对象
            Constructor con2 = c.getDeclaredConstructor(int.class);
            System.out.println(con2);
    
            // 6. Constructor构造器类: 表示一个构造方法,构造方法可以运行,运行效果就是创建出一个指定类型对象
            // Constructor类中有一个方法功能: newInstance(Object...initargs)
            Person p = (Person)con1.newInstance();
            System.out.println(p.i);
    
            // 7. 获取到默认修饰的构造方法
            Constructor con3 = c.getDeclaredConstructor(String.class, int.class);
            Person p3 = (Person)con3.newInstance("张三",19);
            System.out.println(p3.i);
        }
    }
  • 相关阅读:
    mysql表的查询(连接查询)练习
    mysql基础语法
    Linux 常用命令整理
    1.django 环境搭建
    2.django 操作笔记
    mysql基础笔记(1)
    VMware复制Linux虚拟机后网络配置
    uC/OS-III 软件定时器(三)
    uC/OS-III 时间管理(二)
    uC/OS-III 时钟节拍(一)
  • 原文地址:https://www.cnblogs.com/lw1095950124/p/16093770.html
Copyright © 2020-2023  润新知