public class Singleton
{
public static Singleton s=new Singleton();
public static int k1;
public static int k2=0;
private Singleton(){
k1++;
k2++;
}
public static void main(String[] args)
{
System.out.println(Singleton.k1);
System.out.println(Singleton.k2);
}
}
如果是下面这样呢?
public class Singleton
{
public static int k1;
public static int k2=0;
public static Singleton s=new Singleton();
private Singleton(){
k1++;
k2++;
}
public static void main(String[] args)
{
System.out.println(Singleton.k1);
System.out.println(Singleton.k2);
}
}
加载: 查找并加载类的二进制数据
连接:
-验证 确保被加载的类的正确性
-准备 为类的静态变量分配内存,并将其初始化为默认值(int就是0 boolean就是 false 引用类型就是null)
-解析 把类中的符号引用变为直接引用
初始化: 为类的静态变量赋予正确的初始值
不知道诸位看官是否有什么疑问?
如果大家没有,我倒是有个问题,在我们最开始编写java的时候总是javac命令编译成class字节码,java命令运行。如果java代码有什么问题,在javac的时候就会抛出问题,换句话说等我们连接class文件的时候它肯定是没问题的,那还验证什么呀?
答案就是:
如果class的产生只能通过javac命令的话,那就没有任何问题了,可关键就是人们也可以手动产生class文件,所以验证这一步还是有用的。
第二个问题 在连接的准备阶段有把静态变量初始为默认值,但是在初始化的阶段也有为类的静态变量赋予正确的初始值。这两个步骤有什么关系?
看如下代码片
public class test{
public static int a=5;
public static int b;
public static int c;
static{
c=10;
}
public static Person p;
}
类的加载的最终产品是位于堆区中的Class对象
这里就有另一个名词了Class对象。
就像每一本书有作者,价格等描述自身一些熟悉的信息,每个类也都有一个描述自己信息的东西,它就是class对象。
例如
public class Person{
public String name;
public String getName(){
return name;
}
}
这个类的Class对象里就包含了这个类里面有几个属性,每个属性是什么类型,有什么方法,每个方法的参数都是什么,返回值都是什么等等。
具体信息,参考api。
谈到类的加载,就得说说类的加载器了。
java中有两种类的加载器
– Java虚拟机自带的加载器
根类加载器(Bootstrap)
(用c++实现 大家都看不到)
扩展类加载器(Extension)
系统类加载器(System)
(扩展类加载器与系统类加载器是用java写的)
-用户自定义的类加载器
java.lang.ClassLoader的子类
用户可以定制类的加载方式
看如下代码片
Class c1=Class.forName("java.lang.String");
Class c2=Class.forName("Singleton"); //就是上面的那个Singleton
System.out.println(c1.getClassLoader());
System.out.println(c2.getClassLoader());
运行结果就是
至于什么是符号引用,大家在eclipse中,打开一个class文件
上面红框里面的就是符号引用
除了以上六种,别的调用方法都是被动使用。
再说说最开始的那个题目
public static Singleton s=new Singleton();
public static int k1;
public static int k2=0;
private Singleton(){
k1++;
k2++;
}
在连接的准备阶段 k1,k2都是0,s是null
到了初始化阶段, s的初始化调用了构造函数
k1,k2都从0变成了1
继续往下阅读
public static int k1;
public static int k2=0;
k1没有被赋值还是1
但是k2却被赋值为0了
所以最后的结果就是
1
0
至于把
public static Singleton s=new Singleton();
放到后面,大家自己分析吧.