天天看点

Java中类的加载机制和反射机制——个人总结

类的加载机制和反射机制

  1. 类加载机制的原理?
  2. 有哪些类加载器?
  3. 获得Class对象的几种方式?
  4. 如何通过Class对象获得构造方法对象?
  5. 如何通过构造方法对象实例化?

1.类加载机制的原理?

1)启动JVM

2)将需要运行的class文件加载到虚拟机内存中

3)找到主类,开始执行主函数

2.有哪些类加载器?

class文件是如何被加载到JVM内存中的?

通过类加载器将class文件加载到JVM内存中

类加载器:ClassLoader

AppClassLoader 应用类加载器,负责加载核心类,加载自己写的类

ExtClassLoader 扩展类加载器,负责加载扩展类库

bootstrap JVM内置的加载器

Bootstrap类加载器是JVM的一部分,是由C++编写的,

随着启动虚拟机就会创建一个bootstrap类加载器对象

加载步骤:

1)先委托父类加载类,如果父类已经加载,就不需要再次加载,如果父类没有加载,再由本加载器加载

为什么要先委托父类加载类?

MyClassLoader 自定义类加载器

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

/**
 * 自定义类加载器移除先委托父类加载类的功能
 */
public class MyClassLoader extends  ClassLoader{
    //class文件的根路径
    String parent="D:\idea11\untitled\类的加载机制和反射机制";

    //加载Class对象的方法
    public Class<?> findClass(String name){
        Class c=null;
        try {
            //先委托给父类加载器加载
           c = super.loadClass(name);
            //如果父类加载器未加载
            if(c==null) {
                byte[] bs = loadClassData(name);
                c = this.defineClass(name, bs, 0, bs.length);
            }
            }catch (Exception ef){
            ef.printStackTrace();
        }
        return c;

    }


    //根据类名来从class文件中读取字节数据
    //com.newer.test.Student
    private byte[] loadClassData(String name){
        //将类类路径解析为文件路径
        name = name.replace(".","\\");
        name = name+".class";
        String path = parent+"\\"+name;

        try {
            //建立文件字节输入流
            FileInputStream fis = new FileInputStream(path);
            //创建一个字节数组输出流来缓存读入的数据
            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            int t = fis.read();
            while(t!=-1){
                bos.write(t);
                t = fis.read();
            }
            //将字节数组输出流转换成字节数组
            byte[] bs = bos.toByteArray();

            fis.close();
            bos.close();
            return bs;
        }catch (Exception ef){
            ef.printStackTrace();
        }

        return null;
    }
}
           

测试类

Java中类的加载机制和反射机制——个人总结

输出结果

Java中类的加载机制和反射机制——个人总结

出现了学生不是学生的情况

Java中类的加载机制和反射机制——个人总结

因为加载了2次中Student是系统的Student

自动加载器解决方法:

Java中类的加载机制和反射机制——个人总结

2)解析类路径,将类路径转换成文件路径

3)通过文件输入流来读取class文件,得到字节数组

4)将字节数组转换成类对象,对象的类型是Class类型

任何一个类都只能被加载一次

每一个class文件读取到JVM内中之后,都转换成了一个Class对象

3.获得Class对象的几种方式?

获得Class对象的几种方式

//1.通过类名.class

Class c1 = Student.class;

//2.通过对象的getClass()方法

Class c2 = stu.getClass();

//3.通过类加载器获得class对象

ClassLoader classLoader = ClassLoader.getSystemClassLoader();

Class c3 = classLoader.loadClass(“com.newer.test.Student”);

//4.通过 Class.forName()获得Class对象;

Class c4 = Class.forName(“com.newer.test.Student”);

MainClass 对象获得class
public class MainClass {
    public static void main(String[] args) throws Exception {
        Student student = new Student();

        //获得Student的Class对象
        //1.通过类名.class
        Class c1 = Student.class;

        //2.通过对象的getClass()方法
        Class c2 = student.getClass();

        //3.通过类加载器获得class对象
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        Class c3 = loader.loadClass("text.Student");

        //4.通过 Class.forName()获得Class对象;
        Class c4 = Class.forName("text.Student");

        System.out.println(c1 == c2);
        System.out.println(c2 == c3);
        System.out.println(c3 == c4);
    }
}
           

输出结果

Java中类的加载机制和反射机制——个人总结
数组类型的Class对象
Java中类的加载机制和反射机制——个人总结

数组与二维数组不是同一个class

第一种方式,类型.class

Class c1 = int[].class;
        Class c2 = long[].class;

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c1==c2);
           

输出结果

Java中类的加载机制和反射机制——个人总结

第二种方式 数组对象

int[] a = {1,2,3,4,5,6};
Class c3 = a.getClass();
           
基本数据类型类型的Class对象

类型.class

  	Class c5 = int.class;
        Class c6 = long.class;
        System.out.println(c5==c6);
           
包装类的Class对象

第一种方式 类型.class

第二种方式 类型.TYPE

Class c5 = int.class;
Class c8 = Integer.TYPE;
System.out.println(c5==c8);
           

输出结果:

Java中类的加载机制和反射机制——个人总结

为什么Interger.TYPE和int.class相等?

Java中类的加载机制和反射机制——个人总结

Interger.TYPE获得的是int的class

拿到包装类对应的基本类型的Class对象

4.如何通过Class对象获得构造方法对象?

反射机制

1.为什么需要获得Class对象

程序在运行时能够动态的获得类的相关信息的机制,叫做反射机制

正着走:先拿到类的信息,再使用这个类

反着走:先使用这个类,再拿到类的信息

类的所有信息都在Class对象中

Class类的反射机制中的核心类

如何拿到JVM内存中的class文件的数据?

Student类
package text;

public class Student {
    private int age;
    private String name;
    private int num;

    public Student() {
    }

    private Student(int age) {
        this.age = age;
    }

    public Student(int age, String name, int num) {
        this.age = age;
        this.name = name;
        this.num = num;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", num=" + num +
                '}';
    }
}
           

//1.获得所有可见的构造方法

Constructor[] cons= c.getConstructors();

//加载类,获得类的Class对象
            Class c = Class.forName("text.Student");
    
            //通过Class对象获得类的信息
            //1.获得所有可见的构造方法
            Constructor [] cons = c.getConstructors();
            for (Constructor con : cons){
                System.out.println(con);
            }
           

输出结果

Java中类的加载机制和反射机制——个人总结

//2.获得所有已经声明的构造方法

Constructor[] cons2= c.getDeclaredConstructors();

//2.获得所有已经声明的构造方法
        Constructor [] cons2 =c.getDeclaredConstructors();
        for (Constructor con : cons2){
            System.out.println(con);
        }
           

输出结果:

Java中类的加载机制和反射机制——个人总结

//3.获得指定的可见的某一个构造方法

Constructor cc = c.getConstructor(int.class,String.class,int.class);

Java中类的加载机制和反射机制——个人总结

不定项参数的方法

//一个方法中只能有一个不定项参数

//不定项参数必须是最后一个参数

public static void test(int a,int…t){

}

//3.获得指定的可见的某一个构造方法
        Constructor con1=c.getConstructor(int.class,String.class,int.class);
        System.out.println(con1)
           

输出结果:

Java中类的加载机制和反射机制——个人总结

如果用此方法调用私有的构造方法?

Java中类的加载机制和反射机制——个人总结

输出结果:

Java中类的加载机制和反射机制——个人总结

//4.从声明的方法中获得指定的构造方法

Constructor cc2 = c.getDeclaredConstructor(int.class);

Constructor con2=c.getDeclaredConstructor(int.class);
        System.out.println(con2);
           

输出结果:

Java中类的加载机制和反射机制——个人总结

5.如何通过构造方法对象实例化?

//通过构造方法对象得到类的实例对象
Object obj =  con1.newInstance(22,"张三",18);
        System.out.println(obj);
           

输出结果:

Java中类的加载机制和反射机制——个人总结
//通过私有构造方法实例化对象
        //设置允许访问私有构造方法
        con2.setAccessible(true);
        Object obj2 = con2.newInstance(11);
        System.out.println(obj2);
           

输出结果:

Java中类的加载机制和反射机制——个人总结