通过Singleton单例模式,理解Java的类加载

通过Singleton单例模式,理解Java的类加载
---------------------------------------------------------------------
public class Singleton {
 private static Singleton obj = new Singleton(); //1

 public static int counter1; //2

 public static int counter2 = 0; //3

 public static Singleton getInstance() { //4
  return obj; //5
 }

 private Singleton() { //6
  counter1++; //7
  counter2++; //8
 }

 public static void main(String[] args) { //9
  Singleton obj = Singleton.getInstance(); //10
  System.out.println("obj.counter1==" + obj.counter1); //11
  System.out.println("obj.counter2==" + obj.counter2); //12
 }
}
运行结果的确让人大跌眼镜,竟然是:
obj.counter1==1
obj.counter2==0
---------------------------------------------------------------------
之后使用eclipse代码跟踪了一下,发现竟然是程序竟然是这么执行的!
步骤以及说明如下:
1.根据Java的类加载机制,加载类时首先分配static变量默认值以及执行static块,具体顺序根据代码中的顺序来执行.即:程序执行到1步骤,先分配obj=null,然后调用Singleton()方法;
2.调用Singleton()方法,进入Singleton()方法体,执行7和8步骤,将counter1和counter2分别+1;
3.从Singleton()方法中返回,由于没有执行完所有的static的变量或者代码块的初始化,则继续从2步骤开始执行;
4.由于2步骤不进行初始化赋值,则counter1的值没有发生改变,还是==1;
5.执行3步骤,由于counter2需要进行初始化,则执行counter2=0的代码,这个是问题的根源;
5.整个static执行完毕后,在进入10步骤,将结果打印出来为"counter1==1,counter2==0"
---------------------------------------------------------------------
总结:
1.由于单例模式比较特别,static的执行步骤跟代码的顺序有关.如果把private static Singleton obj = new Singleton();放到public static int counter1; public static int counter2 = 0;之后,则最终结果是"counter1==1,counter2==1".即:static的初始化跟代码顺序有关.
2.类的实例构造函数其实是经过new操作后,JVM在分配实例的空间后,进行自动调用的方法.一般我们用来初始化实例的成员数据(这也是最常见的用法).
---------------------------------------------------------------------
说明自己对类的加载的认识:
1.第一次加载类时,JVM会给类的static变量分配空间,并且使用默认值初始化分配的空间(基本数据为0,对象为null).笼统的说,就是把一些为0的空间分配给类的static变量.
2.根据类中的代码顺序,以此执行static变量的自定义初始化或者static代码块.其中,我们可以在代码中给static变量赋值,也可以在static代码块中执行更加复杂的操作.
3.通过调用new操作符,向JVM申请类的实例变量的空间,即为类的实例分配非static变量的空间,同static变量分配空间一样,JVM也是使用默认值来初始化分配的非static变量的空间.这时,实例拥有一些为0的空间.
4.然后JVM调用类的构造函数,进行一系列的操作.一般我们都是做一些对非static变量的初始化工作.从另外一个角度说,类的构造函数的作用跟类的static代码块差不多:构造函数会在非static变量获得空间后调用,而static代码块会在static变量获得空间后调用.
5.需要注意的是,static代码块或者构造函数都是在类或者类实例拥有自己的内存空间后的前提下才被调用的,一般都用来自定义的初始化操作.
---------------------------------------------------------------------
对于上面的Singleton单例模式,比较特殊.主要是这几点:
1.在执行static变量的自定义初始化或者static代码块的时候,突然new一个本身类的实例.
2.在构造函数中,对static变量进行赋值操作.
3.在返回时,继续执行未完成的static变量的自定义初始化或者static代码块工作,导致又重复对static变量重复赋值的操作.
---------------------------------------------------------------------
理解了上面几点,我想应该对JVM的类加载应该有一个比较明确的认识了:-)
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值