JVM 类的生命周期、类加载器
类的加载、连接与初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class Test { public static void main(String[] args) { Count count = Count.getInstance(); System.out.println( "count1 = " + count.count1); System.out.println( "count2 = " + count.count2); } } class Count { // 这个运行结果是 count1 = 1 count2 = 0 ; 因为按顺序执行1. Count(); 2. count1; 3. count2; private static Count count = new Count(); public static int count1; public static int count2 = 0 ; // 所以这个运行结果是 count1 = 1 count2 = 1 ; // private static Count count = new Count(); private Count() { count1++; count2++; } public static Count getInstance() { return count; } } |
1. 类的加载
2. 连接
2.1 类的验证
2.2 类的准备
1
2
3
4
5
6
7
8
9
|
public class Sample { private static int a = 1 ; private static long b; static { b = 2 ; } // ... } |
2.3 类的解析
1
2
3
|
public void gotoWord(){ car.run(); //这段代码在Worker类的二进制数据中表示为符号引用 } |
3. 类的初始化
1
2
3
4
5
6
7
8
9
10
|
public class Sample { private static int a = 1 ; private static long b; private static long c; static { b = 2 ; } // ... } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Sample { private static int a = 1 ; static { a = 2 ; } static { a = 4 ; } public static void main(String[] args) { System.out.println(a); // 输出4 } } |
3. 1 类的初始化时机
以下代码可以加深理解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class Test { public static void main(String[] args) { // x是一个编译时的常量,编译的时候就知道值是多少,不需要对类进行初始化 System.out.println(FinalTest.x); // x非编译时的常量,x在编译时不知道是多少, // 运行才知道的就需要对类进行初始化,对类进行初始化static代码快就会执行 System.out.println(FinalTest2.x); } } class FinalTest { public static final int x = 6 / 3 ; static { System.out.println( "FinalTest staic block!" ); } } class FinalTest2 { public static final int x = new Random().nextInt( 100 ); static { System.out.println( "FinalTest2 staic block!" ); } } |
运行结果:
当 JVM 初始化一个类时,要求它的所有父类都己经被初始化,但是这条规则并不适用于接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class Test { static { System.out.println( "Test static block!" ); } public static void main(String[] args) { System.out.println(Child.b); } } class Parent { static int a = 3 ; static { System.out.println( "Parent static block!" ); } } class Child extends Parent { static int b = 4 ; static { System.out.println( "Child static block!" ); } } |
运行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class Test { public static void main(String[] args) { System.out.println(Child.a); Child.doSomething(); } } class Parent { static int a = 3 ; static { System.out.println( "Parent static block!" ); } static void doSomething() { System.out.println( "do something!" ); } } class Child extends Parent { static { System.out.println( "Child static block!" ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Test { public static void main(String[] args) throws ClassNotFoundException { // 获取系统类加载器 ClassLoader loader = ClassLoader.getSystemClassLoader(); // 这行代码没有导致任何输出 不会导致类的初始化 Class<?> clazz = loader.loadClass( "CL" ); System.out.println( "------" ); clazz = Class.forName( "CL" ); } } class CL { static { System.out.println( "Class CL" ); } } |
类加载器
扩展(Extension)类加载器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Test { public static void main(String[] args) throws ClassNotFoundException { // String 是由根类加载器加载的,下面打印结果为null Class<?> clazz = Class.forName( "java.lang.String" ); System.out.println(clazz.getClassLoader()); // 应用加载器加载的 Class<?> clazz2 = Class.forName( "C" ); System.out.println(clazz2.getClassLoader()); } } class C { } |
类加载的父委托机制
1
2
3
4
|
ClassLoader loader1 = new MyClassLoader(); // 参数loader1将作为loader2的父加载器 ClassLoader loader2 = new MyClassLoader(loader1); |
命名空间
每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成。在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类;在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类。
运行时包(package)
创建用户自定义的类加载器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
public class MyClassLoader extends ClassLoader { // 类加载器名字 private String name; // 加载类的路径 private String path = "d:\\" ; // class文件的扩展名 private final String fileType = ".class" ; public MyClassLoader(String name) { super (); // 让系统类加载器成为该类加载器的父加载器 this .name = name; } public MyClassLoader(ClassLoader parent, String name) { super (parent); // 显示指定该类加载器的父加载器 this .name = name; } public String toString() { return this .name; } public String getPath() { return path; } public void setPath(String path) { this .path = path; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte [] data = this .loadClassData(name); return this .defineClass(name, data, 0 , data.length); } private byte [] loadClassData(String name) { InputStream is = null ; byte [] data = null ; ByteArrayOutputStream baos = null ; try { this .name = this .name.replace( "." , "\\" ); is = new FileInputStream( new File(path + name + fileType)); baos = new ByteArrayOutputStream(); int ch = 0 ; while (- 1 != (ch = is.read())) { baos.write(ch); } data = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { baos.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } return data; } public static void main(String[] args) throws Exception { // 父加载器为系统类加载器 MyClassLoader loader1 = new MyClassLoader( "loader1" ); loader1.setPath( "D:\\test\\serverlib\\" ); // 指定loader2的父加载器为loader1 MyClassLoader loader2 = new MyClassLoader(loader1, "loader2" ); loader2.setPath( "D:\\test\\clientlib\\" ); // 指定loader3的父加载器为根加载器 MyClassLoader loader3 = new MyClassLoader( null , "loader3" ); loader3.setPath( "D:\\test\\otherlib\\" ); test(loader2); test(loader3); } public static void test(ClassLoader loader) throws Exception { Class clazz = loader.loadClass( "Sample" ); Object object = clazz.newInstance(); } } |
1
2
3
4
5
6
|
public class Dog { public Dog() { System.out.println( "Dog is load by : " + this .getClass().getClassLoader()); } } |
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Sample { public int v1 = 1 ; public Sample() { System.out.println( "Sample is load by : " + this .getClass().getClassLoader()); // 主动使用Dog new Dog(); } } |
1
2
3
4
5
|
D:\myapp\syslib>java MyClassLoader Sample is load by : loader1 Dog is load by : loader1 Sample is load by : loader3 Dog is load by : loader3 |
1
2
3
4
5
|
D:\myapp\syslib>java MyClassLoader Sample is load by : sun.misc.Launcher$AppClassLoader@659e0bfd Dog is load by : sun.misc.Launcher$AppClassLoader@659e0bfd Sample is load by : loader3 Dog is load by : loader3 |
1
2
3
4
5
|
D:\myapp\syslib>java - cp .;d:\myapp\serverlib MyClassLoader Sample is load by : sun.misc.Launcher$AppClassLoader@659e0bfd Dog is load by : sun.misc.Launcher$AppClassLoader@659e0bfd Sample is load by : loader3 Dog is load by : loader3 |
1
2
3
4
5
|
D:\myapp\syslib>java MyClassLoader Sample is load by : loader1 Dog is load by : sun.misc.Launcher$AppClassLoader@659e0bfd Sample is load by : loader3 Dog is load by : loader3 |
1
2
3
4
5
6
7
8
9
10
11
|
public static void main(String[] args) throws Exception { // 父加载器为系统类加载器 MyClassLoader loader1 = new MyClassLoader( "loader1" ); loader1.setPath( "D:\\myapp\\serverlib\\" ); Class clazz = loader1.loadClass( "Sample" ); Object object = clazz.newInstance(); // 创建对象 Sample sample = (Sample)object; System.out.println(sample.v1); } |
1
2
3
4
5
6
7
8
9
10
11
|
D:\myapp\syslib>java MyClassLoader Sample is load by : loader1 Dog is load by : loader1 Exception in thread "main" java.lang.NoClassDefFoundError: Sample at MyClassLoader.main(MyClassLoader.java:110) Caused by: java.lang.ClassNotFoundException: Sample at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 1 more |
1
2
3
4
5
6
7
8
9
10
11
12
|
public static void main(String[] args) throws Exception { // 父加载器为系统类加载器 MyClassLoader loader1 = new MyClassLoader( "loader1" ); loader1.setPath( "D:\\myapp\\serverlib\\" ); Class clazz = loader1.loadClass( "Sample" ); Object object = clazz.newInstance(); // 创建对象 Field field = clazz.getField( "v1" ); int v1 = field.getInt(object); System.out.println( "v1:" + v1); } |
1
2
3
4
|
D:\myapp\syslib>java MyClassLoader Sample is load by : loader1 Dog is load by : loader1 v1:1 |
类的卸载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public static void main(String[] args) throws Exception { // 父加载器为系统类加载器 MyClassLoader loader1 = new MyClassLoader( "loader1" ); //1 loader1.setPath( "D:\\myapp\\serverlib\\" ); //2 Class objClass = loader1.loadClass( "Sample" ); //3 System.out.println( "objClass's hashCode is " + objClass.hashCode()); //4 Object obj = objClass.newInstance(); // 创建对象 //5 loader1 = null ; //6 objClass = null ; //7 obj = null ; //8 loader1 = new MyClassLoader( "loader1" ); //9 objClass = loader1.loadClass( "Sample" ); //10 System.out.println( "objClass's hashCode is " + objClass.hashCode()); //11 } |
1
2
3
4
5
|
D:\myapp\syslib>java MyClassLoader objClass's hashCode is 1311053135 Sample is load by : loader1 Dog is load by : loader1 objClass's hashCode is 865113938 |
JVM 类的生命周期、类加载器的更多相关文章
- Java - JVM - 类的生命周期
概述 简述 JVM 里 类的生命周期 上次写了 30%, 居然丢了 难受, 又要重新写 类的生命周期 加载 使用 卸载 1. 加载 概述 类型的加载 大体流程 装载 连接 验证 准备 解析(可选的) ...
- JVM类加载器及Java类的生命周期
预定义类加载器(三种): 启动(Bootstrap)类加载器: 是用本地代码实现的类装入器,它负责将<Java_Runtime_Home>/lib下面的类库加载到内存中(比如rt.jar) ...
- 乐字节Java反射之三:方法、数组、类加载器和类的生命周期
本文承接上一篇:乐字节Java发射之二:实例化对象.接口与父类.修饰符和属性 继续讲述Java反射之三:方法.数组.类加载器 一.方法 获取所有方法(包括父类或接口),使用Method即可. publ ...
- JVM:类的生命周期
类的生命周期 综述 1. 只有当一个类被切实使用到的时候才会被加载到虚拟机中(例如:new, 方法调用, A a = null;不算) 2. 若在加载一个类的过程中,有其他类被切实使用到, ...
- <JVM中篇:字节码与类的加载篇>03-类的加载过程(类的生命周期)详解
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- JVM与垃圾回收机制(GC)和类的生命周期
JVM运行时数据区 GC(垃圾回收机制) 什么是垃圾回收机制: 在系统运行过程中,会产生一些无用的对象,这些对象占据着一定的内存,如果不对这些对象清理回收无用的是对象,可能会导致内存的耗尽,所以垃圾回 ...
- Java类的生命周期详解
引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告 ...
- 【转】Java 类的生命周期详解
一. 引 言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大 ...
- 【转载】详解java类的生命周期
原文地址:http://blog.csdn.net/zhengzhb/article/details/7517213 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑, ...
随机推荐
- Codeforces Round #396(Div. 2) A. Mahmoud and Longest Uncommon Subsequence
[题意概述] 找两个字符串的最长不公共子串. [题目分析] 两个字符串的最长不公共子串就应该是其中一个字符串本身,那么判断两个字符串是否相等,如果相等,那么肯定没有公共子串,输出"-1&qu ...
- Node.js URL
稳定性: 3 - 稳定 这个模块包含分析和解析 URL 的工具.调用 require('url') 来访问模块. 解析 URL 对象有以下内容,依赖于他们是否在 URL 字符串里存在.任何不在 URL ...
- MongoDB 自动增长
MongoDB 没有像 SQL 一样有自动增长的功能, MongoDB 的 _id 是系统自动生成的12字节唯一标识. 但在某些情况下,我们可能需要实现 ObjectId 自动增长功能. 由于 Mon ...
- Android开发技巧——设置系统状态栏颜色
开门见山,先来三张效果图: 然后我们再来讲如何实现以及如何快速地实现. 如何实现 实现设置系统状态栏颜色需要至少在Android 4.4.2(API 19)以上.这是因为,在这个版本以下,没有任何的A ...
- webpack dev server 和 sublime text 配合时需要注意的地方
参考:https://webpack.js.org/guides/development/ Adjusting Your Text Editor Some text editors have a &q ...
- Java中常用缓存Cache机制的实现
缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例. 这样做可以减少系统开销,提高系统效率. 缓存主要可分为二大类: 一.通过文件缓存,顾名思义文件 ...
- malloc_stats---检查内存泄露的神器
在之前的博客中提到过,valgrind可以用来检测内存泄露,但在使用中,往往会遇到一些问题,给调试工作带来很多不必要的麻烦,我自己遇到的有以下两种: (1)内存泄露误检(系统初始化时,可能有一些需要长 ...
- Android 5.0 调色 Palette调色功能
Palette非常好用,也非常好玩. Palette的作用是从图像中提取突出的颜色,这样我们可以根据提取到的色值把它赋给Toolbar,标题,状态栏等,可以使我们的整个界面色调统一,效果非常好看. P ...
- Swift基础之自定义PUSH和POP跳转动画
之前用OC代码写过PUSH和POP的转场动画,闲来无事,将其转换成Swift语言,希望对大家有帮助,转载请注明.... 如何实现PUSH和POP的转场动画? 首先,创建一个NSObject的类,分别用 ...
- C++ 中const作用
一.对const与#define的特点及区别的理解 #define只是用来做文本替换的,#define常量的生命周期止于编译期,它存在于程序的代码段,在实际程序中它只是一个常数,一个命令中的参数,并没 ...