• 类加载器,,,,,反射,,,,,泛型擦除,,,,, 反射配置文件


        类加载器

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

    l  加载

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

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

    l  连接

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

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

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

    l  初始化

    就是我们以前讲过的初始化步骤(进栈进堆调方法)

          类初始化时机(什么时候类进内存)

    1. 创建类的实例(new类对象的时候,创建class文件对象)

    2. 类的静态变量,或者为静态变量赋值(类名 . 静态成员变量或成员变量赋值时,进内存)

    3. 类的静态方法(调用类的静态方法时进内存)

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

    5. 初始化某个类的子类(初始化子类时,父类会进内存。因为构造方法先调super())

    6. 直接使用java.exe命令来运行某个主类(main方法所在的类,主类)

    //如何证明进内存:一进内存就会执行静态代码块

    public class Demo01 {
    public static void main(String[] args) {
        //System.out.println(Person.a);//先进内存再打印a
        //Person.aa();//先进内存再调方法
        new Person();//先父类进内存,再子类进内存
    }
    }
    public class Person extends God{
        public static int a=1;
    static{
        System.out.println("Person类进内存了");
    }
    public static void aa(){
        System.out.println("静态方法");
    }
    
    }
    public class God {
    static{
        System.out.println("父类进内存了");
    }
    }

          类加载器

    l  负责将.class文件加载到内存中,并为之生成对应的Class对象。

          类加载器的组成

    l  Bootstrap ClassLoader 根类加载器(已经写好的JDK中的类)

    也被称为引导类加载器,负责Java核心类的加载

    比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

    l  Extension ClassLoader 扩展类加载器

    负责JRE的扩展目录中jar包的加载。

    在JDK中JRE的lib目录下ext目录(jdk所依赖的jar包里面的类)

    l  System ClassLoader 系统类加载器(我们自定义的类,以及导入jar包里面的类)

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

         反射

          Class类(字节码类)

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    l  获取Class对象的三种方式

    方式一: 通过Object类中的getObject()方法

    方式二: 通过 类名.class 获取到字节码文件对象(任意数据类型都具备一个class静态属性,看上去要比第一种方式简单)。

    方式三: 通过Class类中的方法(将类名作为字符串传递给Class类中的静态方法forName即可)。

    public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取Class字节码文件对象的方式
        Person p=new Person();
        Class c1=p.getClass();//person类的字节码文件对象
        System.out.println(c1);//公共空参构造(new调用构造方法执行的),class是Person类的字节码文件对象
        //Class属性获取
        Class c2=Person.class;
        System.out.println(c2);
        //System.out.println(c1==c2);获取只有一个,一个类的字节码文件只有一个
        //通过class。forname()
        Class c3=Class.forName("com.oracle.demo06.Person");//要加载类的完整包名+类名
        System.out.println(c3);
    }
    }
    public class Person {
    public String name;
    private int age;
    public Person(){
        System.out.println("公共空参构造");
    }
    public Person(String name){
        System.out.println("公共有参构造");
    }
    private Person(String name,int age){
        System.out.println("私有有参构造");
    }
    public void eat(){
        System.out.println("公共无参方法");
    }
    public void sleep(String name){
        System.out.println("公共有参方法");
    }
    public void smoke(int age){
        System.out.println("私有有参方法");
    }

    反射获取构造方法并使用

    在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示。其中,构造方法使用类Constructor表示。可通过Class类中提供的方法获取构造方法:

    //构造方法封装成一个类

    l  返回一个构造方法

      public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取public修饰, 指定参数类型所对应的构造方法

    //Class<?>字节码文件对象(参数写的啥就获取啥),... 可变参

      public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型所对应的构造方法(包含私有的)

    l  返回多个构造方法

      public Constructor<?>[] getConstructors() 获取所有的public 修饰的构造方法

      public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法(包含私有的)

    public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        //获取Person的字节码文件对象
        Class c=Class.forName("com.oracle.demo06.Person");
        //获取公共指定构造方法对象
        Constructor con=c.getConstructor(String.class);//完整报名+类名String.class
        System.out.println(con);//公共有参public修饰完整包名+类名,String类完整包名+类名
        //获取私有构造方法对象
        Constructor con2=c.getDeclaredConstructor(String.class,int.class);
        System.out.println(con2);
        //用公共构造方法对象创建Person对象
        //返回值Object类型
        Person p=(Person)con.newInstance("admin");
        p.eat();//调方法
        //用私有构造方法创建Person类对象
        //暴力反射(不提倡,破坏了面向对象封装)
        //con2.setAccessible(true);
        //不用暴力反射报错:不能被创建
        Person p2=(Person)con2.newInstance("小红",18);
        p2.eat();
    }
    }

    Person类

    public class Person {
    public String name;
    private int age;
    public Person(){
        System.out.println("公共空参构造");
    }
    public Person(String name){
        System.out.println("公共有参构造");
    }
    private Person(String name,int age){
        System.out.println("私有有参构造");
    }
    public void eat(){
        System.out.println("公共wu参方法");
    }
    public void sleep(String name){
        System.out.println("公共有参方法");
    }
    public void smoke(int age){
        System.out.println("siyou有参方法");
    }
    }

        通过反射方式,获取构造方法,创建对象

    获取构造方法,步骤如下:

    1. 获取到Class对象

    2. 获取指定的构造方法

    3. 通过构造方法类Constructor中的方法,创建对象

    public T newInstance(Object... initargs)

    //1,获取到Class对象
            Class c = Class.forName("cn.oracle_01_Reflect.Person");//包名.类名
            //2,获取指定的构造方法
            //public Person()
            //Constructor con = c.getConstructor(null);
            
            //public Person(String name, int age, String address)
            Constructor con = c.getConstructor(String.class, int.class, String.class);
            
            //3,通过构造方法类中Constructor的方法,创建对象
            //Object obj = con.newInstance(null);
            Object obj = con.newInstance("小明", 22, "哈尔滨");
            
            //显示
            System.out.println(obj);

          通过反射获取成员变量并使用

    在反射机制中,把类中的成员变量使用类Field表示。可通过Class类中提供的方法获取成员变量:

    l  返回一个成员变量

      public Field getField(String name) 获取指定的 public修饰的变量

      public Field getDeclaredField(String name) 获取指定的任意变量

    l  返回多个成员变量

      public Field[] getFields() 获取所有public 修饰的变量

      public Field[] getDeclaredFields() 获取所有的 变量 (包含私有)

     

    //通过反射获取成员变量并使用
    public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
        //获取Person类的字节码文件
        Class c=Class.forName("com.oracle.demo06.Person");
        //获取成员变量对象
        Field fl=c.getField("name");
        //System.out.println(fl);
        //快速创建对象,只能调用空参构造
        Person p=(Person)c.newInstance();
        fl.set(p,"小红帽");
        System.out.println(p.name);//获得成员变量
    }
    }

          通过反射获取成员方法并使用

    在反射机制中,把类中的成员方法使用类Method表示。可通过Class类中提供的方法获取成员方法:

    l  返回获取一个方法:

      public Method getMethod(String name, Class<?>... parameterTypes)

                               获取public 修饰的方法

      public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

                               获取任意的方法,包含私有的

    参数1: name 要查找的方法名称; 参数2: parameterTypes 该方法的参数类型

    l  返回获取多个方法:

      public Method[] getMethods() 获取本类与父类中所有public 修饰的方法

    public Method[] getDeclaredMethods() 获取本类中所有的方法(包含私有的)

            

    //获取成员方法
    public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        //获取字节码
        Class c=Class.forName("com.oracle.demo06.Person");
        Method m=c.getMethod("sleep", String.class);//获取对象方法
        //快速创建对象
        Person p=(Person)c.newInstance();
        //调用方法
        m.invoke(p, "小红帽");
    }
    }

          泛型擦除

    程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除。

    //泛型擦除,泛型不进class文件
    public class Demo03 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        ArrayList<String> arr=new ArrayList<String>();
        arr.add("abc");
        //获取arr的字节码文件对象
        Class c=arr.getClass();
        //获取add的方法对象
        Method method=c.getMethod("add", Object.class);
        //调用方法:执行add()方法
        method.invoke(arr, 123);
        System.out.println(arr);
    }
    }

          反射配置文件

    l  通过反射配置文件,运行配置文件中指定类的对应方法

    读取Peoperties.txt文件中的数据,通过反射技术,来完成Person对象的创建

    package com.oracle.demo08;
    
    public class Worker {
    
        public void work(){
            System.out.println("工人工作");
        
    }
    }
    public class Student {
    public void study(){
        System.out.println("学生学习");
    }
    }
    public class Doctor {
    
        public void job(){
            System.out.println("医生工作");
        
    }
    }
    public class Demo01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        //创建Properties集合对象
        Properties pro=new Properties();
        //创建输入流读取
        FileInputStream fis=new FileInputStream("src/com/oracle/demo08/pro.properties");
        pro.load(fis);//读到集合中
        //获取类名
        String className=pro.getProperty("className");
        String methodName=pro.getProperty("methodName");
        //反射获取字节码文件
        Class c=Class.forName(className);
        //获取方法对象
        Method m=c.getMethod(methodName);
        //快速创建对象
        Object obj=c.newInstance();
        //调用方法
        m.invoke(obj);
        
    }
    }

    创建对象的三种方法:new,反序列,反射

  • 相关阅读:
    JS定时执行,循环执行
    Ecshop(二次开发)
    百度歌曲接口
    给大家讲讲在哪些地方发外链最好
    360浏览器默认以兼容模式或急速模式方式打开页面
    子iframe 怎么调用 父级的JS函数
    ASP 发送邮件
    PHP发送邮件
    php表单数据验证类
    js获取url传递参数
  • 原文地址:https://www.cnblogs.com/111wdh/p/13443377.html
Copyright © 2020-2023  润新知