类的加载过程

一、类加载机制

类加载全过程

1、加载

2、链接

3、初始化

二、Java程序初始化顺序

/**
 * @ClassName Demo01
 * @Description 测试程序初始化顺序
 * @Author xwd
 * @Date 2018/10/23 21:50
 */
public class Demo01 {
    public static void main(String[] args) {
        B b = new B();
    }
}

class A{

    static String str1 = "父类A的静态变量";
    String str2 = "父类A的非静态变量";

    static {
        System.out.println("执行了父类A的静态代码块");
    }

    {
        System.out.println("执行了父类A的非静态代码块");
    }

    public A(){
        System.out.println("执行了父类A的构造方法");
    }
}

class B extends A{

    static String str1 = "子类B的静态变量";
    String str2 = "子类B的非静态变量";

    static {
        System.out.println("执行了子类B的静态代码块");
    }

    {
        System.out.println("执行了子类B的非静态代码块");
    }

    public B(){
        System.out.println("执行了子类B的构造方法");
    }
}

控制台输出(程序初始化顺序):

三、类的引用

1、主动引用(一定会初始化)

2、被动引用

/**
 * @ClassName Demo02
 * @Description 测试类的引用
 * @Author xwd
 * @Date 2018/10/23 21:58
 */
public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //主动引用:new一个类的对象
//        People people = new People();
        //主动引用:调用类的静态成员(除了final常量)和静态方法
//        People.getAge();
//        System.out.println(People.age);
        //主动调用:使用java.lang.reflect包的方法对类进行反射调用
//        Class.forName("pri.xiaowd.classloader.People");


        //被动引用:当访问一个静态域时,只有真正声明这个域的类才会被初始化。
//        System.out.println(WhitePeople.age);
        //被动引用:通过数组定义引用,不会初始化
//        People[] people = new People[10];
        //被动引用:引用常量不会触发此类的初始化
        System.out.println(People.num);
    }
    //主动调用:先启动main方法所在的类
//    static {
//        System.out.println("main方法所在的类在虚拟机启动时就加载");
//    }
}

class People{

    static int age = 3;
    static final int num = 20;

    static {
        System.out.println("People被初始化了!");
    }

    public People() {
    }

    public static int getAge() {
        return age;
    }

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

class WhitePeople extends People{

    static {
        System.out.println("WhitePeople被初始化了!");
    }
}

四、类加载器的原理

1、类缓存

2、类加载器的分类

3、java.class.ClassLoader类

(1)作用:

(2)常用方法:

五、类加载器的代理模式

1、双亲委托机制

六、自定义类加载器

import java.io.*;

/**
 * @ClassName FileSystemClassLoader
 * @Description 自定义文件类加载器
 * @Author xwd
 * @Date 2018/10/24 9:23
 */
public class FileSystemClassLoader extends ClassLoader {
    private String rootDir;//根目录

    public FileSystemClassLoader(String rootDir) {
        this.rootDir = rootDir;
    }

    /**
     * @MethodName findClass
     * @Descrition 加载类
     * @Param [name]
     * @return java.lang.Class<?>
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> loadedClass = findLoadedClass(name);//查询该类是否已经被加载过
        if(loadedClass != null){  //该类已经被加载过了,直接返回
            return loadedClass;
        }else{  //该类还没有被加载过
            ClassLoader classLoader = this.getParent();//委派给父类加载
            try {
                loadedClass = classLoader.loadClass(name);
            } catch (ClassNotFoundException e) {
//                e.printStackTrace();
            }
            if(loadedClass != null){  //父类加载成功,返回
                return loadedClass;
            }else{
                byte[] classData = getClassData(name);
                if(classData == null){
                    throw new ClassNotFoundException();
                }else{
                    loadedClass = defineClass(getName(),classData,0,classData.length);
                }
            }
        }
        return loadedClass;
    }

    /**
     * @MethodName getClassData
     * @Descrition 根据类名获得对应的字节数组
     * @Param [name]
     * @return byte[]
     */
    private byte[] getClassData(String name) {
        //pri.xiaowd.test.A  -->  D:/myjava/pei/xiaowd/test/A.class
        String path = rootDir + "/" + name.replace('.','/') + ".class";
//        System.out.println(path);
        InputStream is = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            is = new FileInputStream(path);

            byte[] bytes = new byte[1024];
            int temp = 0;
            while((temp = is.read(bytes)) != -1){
                baos.write(bytes,0,temp);
            }
            return baos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if(baos != null){
                    baos.close();
                }
                if(is != null){
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

七、线程上下文类加载器

八、Tomcat服务器的类加载器

posted @ 2022-01-04 16:05  赤兔胭脂小吕布  阅读(33)  评论(0编辑  收藏  举报