面试总结系列——单例模式静态内部类

前言:

仔细思考了一下这个模式,往里面深挖了一下,发现关于静态内部类未知的太多。尤其是java虚拟机classloader加载机制一脸迷茫,所以决定记录一下。下面相关问题的解答我都会给出推荐的博客,因为我自己再写不敢保证比他们写的更好。再次膜拜大神。

今天看单例模式,仔细思考了下静态内部类的单例。
关於单例模式的讲解,推荐一篇博文,可以说单例模式是多线程入门的教程。
博文地址
博文上面讲解的很清楚,就不多说了。原文中作者有这样一句话

第3种,利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗,所以一般我倾向于使用这一种。

那么,什么是classloader机制?为什么保证了线程安全?这个问题先留着,我们先看下文中的静态单例模式。

public class Singleton {    
    private static class LazyHolder {    
       private static final Singleton INSTANCE = new Singleton();    
    }    
    private Singleton (){}    
    public static final Singleton getInstance() {    
       return LazyHolder.INSTANCE;    
    }    
}    

这里是如何实现饿汉式的?在印象中,静态内部类难道不是一开始就加载吗?一开始就实现了INSTANCE = new Singleton()?那么哪里来的饿汉模式?
查阅资料发现(博文参考资料)如下的几句话:

  • 类级内部类指的是,有static修饰的成员内部类。如果没有static修饰的成员式内部类被称为对象级内部类。
  • 类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可以直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。

那么静态内部类是什么时候加载的呢?
参考博文1
文中讲述类加载机制:
类初始化的时机,有且仅有四个:

  1. 遇到new、getstatic、putstatic、invokestatic这四条字节码指令的时候。
  2. 使用java.lang.reflect进行反射调用的时候。
  3. 当初始化一个类的时候,发现其父类还没有初始化,那么先去初始化它的父类。
  4. 当虚拟机启动的时候,需要初始化main函数所在的类。

内部类(不论是静态内部类还是非静态内部类)都是在第一次使用时才会被加载。
对于非静态内部类是不能出现静态模块(包含静态块,静态属性,静态方法等)
非静态类的使用需要依赖于外部类的对象

参考博文2(关于这个问题,这一篇博文解释足够详细了)
原文讲述如下:
虚拟机规范则严格规定了有且只有四种情况必须立即对类进行初始化,遇到new、getStatic、putStatic或invokeStatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
生成这4条指令最常见的java代码场景是:
1) 使用new关键字实例化对象
2) 读取一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)
3) 设置一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)
4) 调用一个类的静态方法

静态内部类其实和外部类的静态变量,静态方法一样,只要被调用了都会让外部类的被加载。不过当只调用外部类的静态变量,静态方法时,是不会让静态内部类的被加载

关于类加载时机

参考博文1

参考博文2:强荐这篇博文,知识点深浅刚好合适,里面的问题,确实我之前没遇到过,长见识了。

说道类加载时机,不得不提的一个重要的面试题就是,new 一个子类代码时的执行顺序。
参考博文(虽然这篇博文作者也标明转载)

这里直接给出结论吧,方便记忆.

  1. 父类–静态变量
  2. 父类–静态初始化块
  3. 子类–静态变量
  4. 子类–静态初始化块
  5. 父类–变量
  6. 父类–初始化块
  7. 父类–构造器
  8. 子类–变量
  9. 子类–初始化块
  10. 子类–构造器

类加载时机我个人觉得是个难点,这一块必须多花功夫看看博客。本弱也在学习中,学好之后再来更新下这篇博文.

疑问

其实,涉及到volatile还有一个问题,大家都知道,一般双从锁定的单例都会涉及到重排序的问题,但是,synch指令其实也有内存回刷的功能,这一点其实蛮重要,大家可以仔细是靠下,为啥有了synch还是需要volatile,晚点再来解答。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章