StaticInnerClass
静态内部类的外部调用
- 静态内部类可以直接创建对象
new B.C();
- 如果内部类不是静态的,那就得这样
B b = new B();
B.C c = b.new C();
静态内部类来实现"延时加载"的线程安全的单例模式
- 单例模式分为饿汉式、懒汉式,其中懒汉式涉及到多线程安全问题,解决方法有加同步锁synchronized,双重检查(避免对除第一次调用外的所有调用都实行同步),静态内部类实现的单例模式等。
1. 直接添加synchronized
public class Singleton {
private static Singleton instance;
private Singleton() {
System.out.println("private Singleton()");
}
public synchronized static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
2. 双重检查实现(最常用)
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) {
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
3. 静态内部类实现
- 使用静态内部类能保证线程安全的原因
- 由于内部静态类只会被加载一次,故该实现方式是线程安全的
- 类加载的初始化阶段是单线程的
- 类加载时机
- 使用new,invokestatic,putstatic,getstatic指令时若该类未加载则触发
- 反射使用某个类时若该类未加载则触发
- 子类加载时若父类未加载则触发
- 程序开始时主方法所在的类会被加载
- …
- 静态内部类的懒加载应该是第一种情况。为什么外部类加载时静态内部类未加载,《effective java》里面说静态内部类只是刚好写在了另一个类里面,实际上和外部类没什么附属关系。(但直接放在外部,1. 如果设置为public访问没有限制 2. private的话访问受限)
- 线程安全是因为,类加载的初始化阶段是单线程的,类变量的赋值语句在编译生成字节码的时候写在函数中,初始化时单线程调用这个完成类变量的赋值。
静态内部类实现的单例模式
public class Singleton {
private Singleton() {}
private static class Holder {
// 这里的私有没有什么意义
/* private */static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
// 外围类能直接访问内部类(不管是否是静态的)的私有变量
return Holder.instance;
}
}
附 类加载顺序示例
package ktuil;
public class TestStaticInnerClass {
public static void main(String[] args) {
new B();
new A.C();
}
}
class A {
private P p1 = new P("A--p1");
static P p3 = new P("A--p3");
public A() {
System.out.println("A()");
}
private P p2 = new P("A--p2");
static {
new P("A--static");
}
{
new P("A{...}");
}
public static class C {
private P p1 = new P("C--p1");
static P p3 = new P("C--p3");
public C() {
System.out.println("C()");
}
private P p2 = new P("C--p2");
static {
new P("C--static");
}
{
new P("C{...}");
}
}
}
class B extends A {
private P p1 = new P("B --p1");
static P p3 = new P("B -- p3");
public B() {
System.out.println("B()");
}
public P p2 = new P("B -- p2");
static {
new P("B -- static");
}
{
new P("B{...}");
}
}
class P {
public P(String s) {
System.out.println(s);
}
}