源码:test.java
package Test;
/*这个文件主要用来做java课程作业*/
public class test {
public static void main(String[] args){
System.out.println("this is a test");
}
}
编译成功后,用xxd test.class
命令可以查看一下这个字节码文件
00000000: cafe babe 0000 0038 0010 0a00 0300 0d07 .......8........
00000010: 000e 0700 0f01 0006 3c69 6e69 743e 0100 ........<init>..
00000020: 0328 2956 0100 0443 6f64 6501 000f 4c69 .()V...Code...Li
00000030: 6e65 4e75 6d62 6572 5461 626c 6501 0012 neNumberTable...
00000040: 4c6f 6361 6c56 6172 6961 626c 6554 6162 LocalVariableTab
00000050: 6c65 0100 0474 6869 7301 000b 4c54 6573 le...this...LTes
00000060: 742f 7465 7374 3b01 000a 536f 7572 6365 t/test;...Source
00000070: 4669 6c65 0100 0974 6573 742e 6a61 7661 File...test.java
00000080: 0c00 0400 0501 0009 5465 7374 2f74 6573 ........Test/tes
00000090: 7401 0010 6a61 7661 2f6c 616e 672f 4f62 t...java/lang/Ob
000000a0: 6a65 6374 0021 0002 0003 0000 0000 0001 ject.!..........
000000b0: 0001 0004 0005 0001 0006 0000 002f 0001 ............./..
000000c0: 0001 0000 0005 2ab7 0001 b100 0000 0200 ......*.........
000000d0: 0700 0000 0600 0100 0000 0400 0800 0000 ................
000000e0: 0c00 0100 0000 0500 0900 0a00 0000 0100 ................
000000f0: 0b00 0000 0200 0c .......
第一行cafe babe
被称为“魔数”,是JVM识别.class文件到标志。文件格式的定制者可以自由选择魔数值(只要没用过),比如说 .png 文件的魔数是 8950 4e47
。
类加载分为三个步骤:加载,连接,初始化。
java.lang.Class
对象,即程序中使用的任何类时,系统都会为之建立一个java.lang.Class
对象。系统中所有类都是由这个对象实现的。连接阶段负责把类的二进制数据合并到JRE中,其又可分为如下三个阶段:
staric int a = 5;
static { b = 5;}
java.lang.Object
类Class.forName("Person")
java.lang.Object
|__java.lang.ClassLoader
类加载器负责将class文件读入内存并为之生成对应的java.lang.Class对象
对于任意一个类,都需要由它的类加载器和这个类本身一同确定其在 JVM 中的唯一性。也就是说,如果两个类的加载器不同,即使两个类来源于同一个字节码文件,那这两个类就必定不相等(两个类的 Class 对象不 equals
)。
Java类加载器可分为三种:
java.lang.ClassLoader
的子类,所以下面运行为null。public class TestJdkCl {
public static void main(String[] args) {
System.out.println(String.class.getClassLoader());
}
}
jre/lib/ext
包下面的jar文件。我们可以通过把自己开发的类打包成JAR文件放入扩展目录来为Java扩展核心类以外的新功能。例子:
public class Test {
public static void main(String[] args) {
ClassLoader loader = Test.class.getClassLoader();
while (loader != null) {
System.out.println(loader.toString());
loader = loader.getParent();
}
}
}
每个 Java 类都维护着一个指向定义它的类加载器的引用,通过 类名.class.getClassLoader()
可以获取到此引用;然后通过 loader.getParent()
可以获取类加载器的上层类加载器。
这段代码的输出结果如下:
jdk.internal.loader.ClassLoaders$AppClassLoader@3d4eac69
jdk.internal.loader.ClassLoaders$PlatformClassLoader@38af3868
第一行输出为 Test 的类加载器,即应用类加载器,它是 jdk.internal.loader.ClassLoadersAppClassLoader 类的实例;第二行输出为启动类加载器,是 jdk.internal.loader.ClassLoadersPlatformClassLoader@38af3868 类的实例。
层级关系
Java类加载机制主要有以下三种:
changed
可见,在JDK 9中,应用程序类加载器可以委托给平台类加载器以及引导类加载器;平台类加载器可以委托给引导类加载器和应用程序类加载器。
此外,JDK 9不再支持扩展机制。但是,它将扩展类加载器保留在名为平台类加载器的新名称下。ClassLoader类包含一个名为getPlatformClassLoader()的静态方法,该方法返回对平台类加载器的引用。
在JDK 9之前,扩展类加载器和应用程序类加载器都是java.net.URLClassLoader类的一个实例。而在JDK 9中,平台类加载器(以前的扩展类加载器)和应用程序类加载器是内部JDK类的实例。如果你的代码依赖于URLClassLoader类的特定方法,代码可能会在JDK 9中崩溃。
JDK 9中的类加载机制有所改变。三个内置的类加载器一起协作来加载类。
JDK 9中的类加载机制有所改变。三个内置的类加载器一起协作来加载类。
JDK 9中的类加载机制有所改变。三个内置的类加载器一起协作来加载类。
source:https://chenzhuo233.github.io/2019/09/28/JVM类加载机制/
喜欢,在看