Java设计模式(一)——单例模式
作者:互联网
一.定义:singleton
一个类只有一个实例,而且这个实例自己创建。
二.单例模式的五种写法
核心代码,构造方法私有化,private,注意对外访问的是静态的,不然你们怎么访问的到
1.懒汉式:
用到的时候才创建,使用的时候检查有没有实例,如果没有就创建,有就发挥。有线程安全和不安全两种写法,区别在于synchronized
1 public class Lazybones { 2 private static Lazybones lazybones; 3 4 private Lazybones(){} 5 6 public static Lazybones getInstance(){ 7 if (null == lazybones){ 8 lazybones = new Lazybones(); 9 } 10 return lazybones; 11 } 12 }
2.饿汉式:
从名字上讲就是比较勤快的,实例在初始化的时候已经建好,不管你有没有使用到。好处是没有现成安全,坏处是浪费内存空间
1 public class HungryMan { 2 private static HungryMan hungryMan = new HungryMan(); 3 private HungryMan(){} 4 public static HungryMan getInstance(){ 5 return hungryMan; 6 } 7 }
3.双检锁:
又叫双重检验锁,综合懒汉模式和饿汉模式的优缺点整合而成。看下面代码,特点是增加了sychronized的关键字,而且sychronized(方法执行完会自动释放)关键字内外层都加了一层 if 条件判断,这样既保证了安全,又比直接上锁提高了执行效率,还节省了内存空间
synchronized本身monitorEnter,monitorExit已经具备volatile读写的内存语义,所以不用加volatile修饰
1 public class DoubleCheck { 2 private static DoubleCheck doubleCheck; 3 private DoubleCheck(){} 4 public static DoubleCheck getInstance(){ 5 if (null == doubleCheck){ 6 synchronized (DoubleCheck.class){ 7 if (null == doubleCheck){ 8 doubleCheck = new DoubleCheck(); 9 } 10 } 11 } 12 return doubleCheck; 13 } 14 }
4.静态内部类:
内部类的加载时机如下,大家可以自己编写测试类,简单的打印就可以发现的,看下外部类和类不类加载是顺序
4.1外部类初次加载,会初始化静态变量、静态代码块、静态方法,但不会加载内部类和静态内部类。
4.2实例化外部类,调用外部类的静态方法、静态变量,则外部类必须先进行加载,但只加载一次。
4.2直接调用静态内部类时,外部类不会加载。
类加载时机:JAVA虚拟机在有且仅有的5种场景下会对类进行初始化。
1.遇到new、getstatic、setstatic或者invokestatic这4个字节码指令时,对应的java代码场景为:new一个关键字或者一个实例化对象时、读取或设置一个静态字段时(final修饰、已在编译期把结果放入常量池的除外)、调用一个类的静态方法时。
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没进行初始化,需要先调用其初始化方法进行初始化。
3.当初始化一个类时,如果其父类还未进行初始化,会先触发其父类的初始化。
4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
5.当使用JDK 1.7等动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
这5种情况被称为是类的主动引用,注意,这里《虚拟机规范》中使用的限定词是"有且仅有",那么,除此之外的所有引用类都不会对类进行初始化,称为被动引用。静态内部类就属于被动引用的行列。
静态内部类
1 public class Singleton { 2 3 private static class SingletonHolder { 4 private static final Singleton singleton = new Singleton(); 5 } 6 7 private Singleton() {} 8 9 public static Singleton getInstance() { 10 return SingletonHolder.singleton; 11 } 12 }
测试静态内部类的加载时机:
1 public class StaticTest { 2 static { 3 System.out.println("StaticTest 静态代码块加载-----1"); 4 } 5 6 public StaticTest(){ 7 System.out.println("StaticTest 构造初始化----2"); 8 } 9 10 public static class InnerClass{ 11 static { 12 System.out.println("InnerClass 静态代码块加载----3"); 13 } 14 public InnerClass(){ 15 System.out.println("InnerClass 构造初始化----4"); 16 } 17 } 18 } 19 20 public static void main(String[] args) { 21 StaticTest staticTest = new StaticTest(); 22 System.out.println("==========="); 23 }
结果:不调用内部类时不加载
第二次:调用内部类
StaticTest staticTest = new StaticTest();
System.out.println("====外部类初始化后睡眠2秒======");
Thread.sleep(2000);
StaticTest.InnerClass innerClass = new StaticTest.InnerClass();
结果:
5.枚举:自动支持序列化机制,绝对防止多次实例化直接通过:EnumSingleton.ENUM_SINGLETON.anyMthod();调用,方便简洁
1 public enum EnumSingleton { 2 // 就是类的实例 3 ENUM_SINGLETON; 4 5 public void anyMthod() { 6 System.out.println("单例模式的枚举写法"); 7 } 8 } 9 10 public static void main(String[] args) throws InterruptedException { 11 EnumSingleton.ENUM_SINGLETON.anyMthod(); 12 }
结果:
标签:初始化,Java,private,StaticTest,static,单例,设计模式,public,加载 来源: https://www.cnblogs.com/kukufan/p/12462813.html