[align=center][size=xx-large][b]Class加载机制[/b][/size][/align]
[size=medium] Java之所以能够实现跨平台,是因为Java Virtual Machine(Java虚拟机)的优势;简而言之,我们编写的源代码(.java),通过Java编译器编译成为了字节码(.class)文件后,由不同平台相应的JVM通过解释执行;那么字节码(.class)没有变化,变化的是运行在不同平台上的JVM;而通过不同平台上的JVM最终生成可以运行在相应平台上的软件;这样就实现了跨平台。(注意:JVM本身是不跨平台的哟!不同的平台拥有不同的JVM)
Java是面向对象的编程语言,那么Java创建一个对象是如何实现的呢?仅仅是(new)一下这么简单吗?让我们开启JVM的大门,寻找Class加载机制的奥秘![/size]
[size=medium][b]一、Class加载的过程[/b][/size]
[align=center][img]http://dl2.iteye.com/upload/attachment/0084/6719/fdab70c1-60a5-3a94-9faa-4c06bed1d47c.gif[/img][/align]
[size=medium][b]1、Class加载:[/b]JVM会做这样一件事情,就是找到Class文件,读取Class文件中的内容;[/size]
[size=medium][b]2、Class连接:[/b]JVM会做这样三件事情;
1)验证:确保Class文件的正确性 ,为什么还要验证呢?难道Java编译器生成的Class文件不是可靠的吗?这其中的原因就是,JVM为了防止人为的编写错误的Class文件,最终会造成JVM的错误;
2)准备:将Class中的静态变量分配内存,[b][color=red]赋予默认值[/color][/b];
3)解析:将Class中的符号引用替换成直接引用。
[b]3、Class初始化:[/b]为静态变量赋予[b][color=red]正确的初始值[/color][/b]。
以上就是一个Class的加载过程,如果仔细了解完后,你会发现一个疑问,为什么在Class连接的准备阶段Class会被赋予“[color=red]默认值[/color]”,而Class初始化再一次赋予“[color=red]正确的初始值[/color]”呢?原因是这样的:
例如:[/size]
[size=medium] number1,number2 在Class连接准备阶段,它们被赋予默认值0,如果是Class类型则为Null;而到Class初始化时,number1的值还是默认值,number2则被重新赋予了1。接下来我们看一个被称为“所以程序员都会犯错的一个实例”:[/size]
[size=medium] 你知道结果是多少吗?如果你觉得number1和number2的值都是1那么你就错啦!正确答案是1和0;原因是在SingleModel 类初始化后确定两个属性都自增为1,但是经过静态属性顺序初始化后,number2又被重新赋予了0;所以结果成了1和0;[/size]
[size=medium] 如果把“private static SingleModel singleClass = new SingleModel();
”这一句放下来,那结果又会怎样呢? [/size]
[b][size=medium]二、Class加载的触发条件[/size] [/b]
[size=medium] 具体来分析一下Class的加载机制中的加载形式,首先我们需要知道JVM什么时候需要加载Class?
JVM加载Class有两种方式:主动加载、被动加载;
主动加载有六种形式:
1)、new Object();(最常见)
2)、SingleModel.number=0;(使用类中的静态属性时)
3)、SingleModel.getInstance();(使用类中的静态方法时)
4)、Class.forName("com.sean.jvm.Test");(动态加载时)
5)、初始化一个子类时;(一个子类被实例化,那么它的父类也就被加载)
6)、启动类;(含main方法的类)
除以上六种形式之外的Class加载都被称为:被动加载(特点:不会初始化)。[/size]
[size=medium][b]三、Class加载途径[/b][/size]
[size=medium] 我们在Java开发过程中,Class文件常见的来源是我们自己编写的Java源代码编译后而得到的,还有一种是来自我们引用了他人写好的架包(.jar等压缩包);然而Java不仅仅提供了这两种方式,也可以通过java.net.URLClassLoader这个类从网络上获得Class,来加载到我们的软件中;还可以通过Class专用数据库中提取Class以及采用动态编译Class方式加载Class;是不是对Class加载途径有了新认识呢?[/size]
[size=large]挖掘了Class的加载中的这么多奥秘,发现越挖越多,Class加载器中所蕴含的宝藏还远远不止这些,下一篇会更精彩,欢迎指正![/size]
[size=medium] Java之所以能够实现跨平台,是因为Java Virtual Machine(Java虚拟机)的优势;简而言之,我们编写的源代码(.java),通过Java编译器编译成为了字节码(.class)文件后,由不同平台相应的JVM通过解释执行;那么字节码(.class)没有变化,变化的是运行在不同平台上的JVM;而通过不同平台上的JVM最终生成可以运行在相应平台上的软件;这样就实现了跨平台。(注意:JVM本身是不跨平台的哟!不同的平台拥有不同的JVM)
Java是面向对象的编程语言,那么Java创建一个对象是如何实现的呢?仅仅是(new)一下这么简单吗?让我们开启JVM的大门,寻找Class加载机制的奥秘![/size]
[size=medium][b]一、Class加载的过程[/b][/size]
[align=center][img]http://dl2.iteye.com/upload/attachment/0084/6719/fdab70c1-60a5-3a94-9faa-4c06bed1d47c.gif[/img][/align]
[size=medium][b]1、Class加载:[/b]JVM会做这样一件事情,就是找到Class文件,读取Class文件中的内容;[/size]
[size=medium][b]2、Class连接:[/b]JVM会做这样三件事情;
1)验证:确保Class文件的正确性 ,为什么还要验证呢?难道Java编译器生成的Class文件不是可靠的吗?这其中的原因就是,JVM为了防止人为的编写错误的Class文件,最终会造成JVM的错误;
2)准备:将Class中的静态变量分配内存,[b][color=red]赋予默认值[/color][/b];
3)解析:将Class中的符号引用替换成直接引用。
[b]3、Class初始化:[/b]为静态变量赋予[b][color=red]正确的初始值[/color][/b]。
以上就是一个Class的加载过程,如果仔细了解完后,你会发现一个疑问,为什么在Class连接的准备阶段Class会被赋予“[color=red]默认值[/color]”,而Class初始化再一次赋予“[color=red]正确的初始值[/color]”呢?原因是这样的:
例如:[/size]
class Test {
public static int number1;
public static int number2 = 1;
}
[size=medium] number1,number2 在Class连接准备阶段,它们被赋予默认值0,如果是Class类型则为Null;而到Class初始化时,number1的值还是默认值,number2则被重新赋予了1。接下来我们看一个被称为“所以程序员都会犯错的一个实例”:[/size]
package com.sean.jvm;
public class Test {
public static void main(String[] args) {
SingleModel singleOBJ = SingleModel.getInstance();
System.out.println("number1==" + singleOBJ.number1);
System.out.println("number2==" + singleOBJ.number2);
}
}
class SingleModel {
private static SingleModel singleClass = new SingleModel();
public static int number1;
public static int number2 = 0;
public SingleModel() {
number1++;
number2++;
}
public static SingleModel getInstance() {
return singleClass;
}
}
[size=medium] 你知道结果是多少吗?如果你觉得number1和number2的值都是1那么你就错啦!正确答案是1和0;原因是在SingleModel 类初始化后确定两个属性都自增为1,但是经过静态属性顺序初始化后,number2又被重新赋予了0;所以结果成了1和0;[/size]
package com.sean.jvm;
public class Test {
public static void main(String[] args) {
SingleModel singleOBJ = SingleModel.getInstance();
System.out.println("number1==" + singleOBJ.number1);
System.out.println("number2==" + singleOBJ.number2);
}
}
class SingleModel {
public static int number1;
public static int number2 = 0;
private static SingleModel singleClass = new SingleModel();
public SingleModel() {
number1++;
number2++;
}
public static SingleModel getInstance() {
return singleClass;
}
}
[size=medium] 如果把“private static SingleModel singleClass = new SingleModel();
”这一句放下来,那结果又会怎样呢? [/size]
[b][size=medium]二、Class加载的触发条件[/size] [/b]
[size=medium] 具体来分析一下Class的加载机制中的加载形式,首先我们需要知道JVM什么时候需要加载Class?
JVM加载Class有两种方式:主动加载、被动加载;
主动加载有六种形式:
1)、new Object();(最常见)
2)、SingleModel.number=0;(使用类中的静态属性时)
3)、SingleModel.getInstance();(使用类中的静态方法时)
4)、Class.forName("com.sean.jvm.Test");(动态加载时)
5)、初始化一个子类时;(一个子类被实例化,那么它的父类也就被加载)
6)、启动类;(含main方法的类)
除以上六种形式之外的Class加载都被称为:被动加载(特点:不会初始化)。[/size]
[size=medium][b]三、Class加载途径[/b][/size]
[size=medium] 我们在Java开发过程中,Class文件常见的来源是我们自己编写的Java源代码编译后而得到的,还有一种是来自我们引用了他人写好的架包(.jar等压缩包);然而Java不仅仅提供了这两种方式,也可以通过java.net.URLClassLoader这个类从网络上获得Class,来加载到我们的软件中;还可以通过Class专用数据库中提取Class以及采用动态编译Class方式加载Class;是不是对Class加载途径有了新认识呢?[/size]
[size=large]挖掘了Class的加载中的这么多奥秘,发现越挖越多,Class加载器中所蕴含的宝藏还远远不止这些,下一篇会更精彩,欢迎指正![/size]