Java类加载机制

2018-11-23  本文已影响0人  coderpjw

Java类加载过程

Java虚拟机规范
Java类加载器

一般我们把Java的类加载分为三个过程: 加载、连接、初始化

加载 Loading

Java将字节码数据从不同的数据源读取到JVM中,并映射为JVM认可的Class对象。这里的数据源可以是jar文件,class文件,网络数据等。如果数据源类型不是ClassFile的结构,则会抛出ClassFormatError。

我们可以自定义类加载器来实现类加载的过程

链接 Linking

可以分为3步。

初始化 Initializa

执行类初始化的代码逻辑,包括静态字段赋值,执行类中静态代码块的逻辑。

在编译阶段会把这部分的逻辑整理好,父类型初始化逻辑要优先于当前类型。

什么是双亲委派模型

当类加载器试图加载某个类时,如果每个类都自己加载需要的类型,会出现重复加载的情况,因此除非父类加载器找不到相应的类型,否则尽量将这个任务代理给当前加载器的父加载器去做。

这样可以避免加载重复类型,减少资源浪费。


准备阶段给静态变量赋值,那么普通静态变量,静态常量(原始类型和引用类型)在加载时有什么区别?

public class CLPerparation {
  public static int a = 10;
  public static final int INT_CONSTANT = 100;
  public static final Integer INTEGER_CONSTAN = Integer.valueOf(1000);
}

编译和反编译一下

Javac CLPreparation.java
Javap –v CLPreparation.class

0: bipush        10
2: putstatic     #2 // Field a:I
5: sipush        1000
8: invokestatic  #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;        
11: putstatic     #4 // Field INTEGER_CONSTAN:Ljava/lang/Integer;

可以看到普通原始类型静态变量引用类型常量,需要额外调用putstatic指令,而原始类型常量不需要。

内建的类加载器有哪些?

以JDK8为例:

jdk8类加载机制.png

感谢杨晓峰老师

自定义类加载器如何定义?

package classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class MyClassLoader2 extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        byte[] b = loadClassData(name);
        return defineClass(null, b, 0, b.length);
    }

    private byte[] loadClassData(String name) {
        InputStream inputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        System.out.println(name);
        try {
            inputStream = new FileInputStream(new File(name));
            byteArrayOutputStream = new ByteArrayOutputStream();
            int len = 0;
            byte[] b = new byte[1024];
            while ((len = inputStream.read(b)) != -1) {
                byteArrayOutputStream.write(b, 0, len);
            }
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

    }

}

测试

package classloader;

public class MyTest {

    public static void main(String[] args) {
        String pathname = "文件路径";
        MyClassLoader2 classLoader = new MyClassLoader2();
        try {
            Class<?> object = classLoader.loadClass(pathname);
            System.out.println(object.getClassLoader());
        } catch (ClassNotFoundException e) {
      e.printStackTrace();
        }
    }
}

Java程序启动慢,类加载器的开销如何减小?

上一篇下一篇

猜你喜欢

热点阅读