单例模式--作用:节省不必要的内存开销,若程序从头到尾仅需一个保存相关状态的对象实例
就不必每次都创建新的对象!(于是在内里面封装一个方法专门来管理此对象
使其成为单例的类)
单例模式--弊病:1,在多个虚拟机和分布技术的系统中,应该避免使用存在状态的单例模式,
因为一个有状态的单例类,在不同虚拟机上,各个单例对象保存的状态很可能是不一样的
2, 不同的类加载器会使用不同的命名空间(namespace)来区分同一个类,
因此,单例类在多加载器的环境下会产生多个单例对象
3, 为了使一个单例类变成可串行化的,仅仅在声明中添加“implements
Serializable”是不够的。因为一个串行化的对象在每次返串行化的时候,都会创建一个新的对象,
而不仅仅是一个对原有对象的引用。为了防止这种情况,可以在单例类中加入 readResolve 方法
(具体情况请参考《Effective Java》一书第 57 条建议,另外,对象的串行化并不仅局限于上述方式,
还存在基于 XML 格式的对象串行化方式)
在eclipse 中开发,结构如下:6种单例模式, 一个测试类
单例模式---第一大类【使用现成对象】:1, 枚举实现的单例(简练,实用,美观)
//枚举实现--单例模式 public enum Singleton1_enum { OBJ; public static void printInstance(){ System.out.println(OBJ.hashCode());//查看内存地址 } }单例模式---第一大类【使用现成对象】:2, 饿汉模式( 比较适合java的)
//饿汉模式 public class Singleton1_hungry { //私有静态变量,只在类加载时初始化赋值【只在单个类加载器环境下,是单例的】 private static Singleton1_hungry single=new Singleton1_hungry(); private Singleton1_hungry(){ }//私有构造器 public static Singleton1_hungry getInstance(){ return single; } }
单例模式---第一大类【使用现成对象】:3, 静态内部类实现的单例
//使用静态内部类 public class Singleton1_staticInnerClass { //私有构造器 private Singleton1_staticInnerClass(){} //外部获取实例的接口: public static Singleton1_staticInnerClass getInstance(){ return Inner.singleton; } //静态内部类: 负责创建外部类实例 private static class Inner{ private static Singleton1_staticInnerClass singleton=new Singleton1_staticInnerClass(); } }
单例模式---第二大类【临时创建对象】: 1, 懒汉模式
//懒汉模式 public class Singleton2_lazy { private static Singleton2_lazy single; private Singleton2_lazy(){ } //同步整个方法:防止多线程并发访问异常 public synchronized static Singleton2_lazy getInstance(){ if(single==null){ single= new Singleton2_lazy(); } return single; } }
单例模式---第二大类【临时创建对象】: 2, 双重校验加锁 实现单例
//使用valatile 关键字, 同步并双重验证 public class Singleton2_doubleCheck { private volatile static Singleton2_doubleCheck single; private Singleton2_doubleCheck(){System.out.println("构造器。。。");} public static Singleton2_doubleCheck getInstance(){ if (single==null){ synchronized (Singleton2_doubleCheck.class){ //初次为null时,锁定该类,进入下一步验证 if(single==null){ single=new Singleton2_doubleCheck(); }/** 当初次为null时,若进入2个线程, 则锁定一个后直到该线程退出锁(创建了对象), 第二个线程接到锁,再次判断null为false, 退出锁return null; */ }//sychronized }//single==null return single; } }
单例模式---第三大类【HashMap注册表管理对象】: 可继承的单例实现(构造器protected)
//父类--单例类 //构造器protected, 自己管理HashMap对象注册表,可以被子类继承实现多态 public class Singleton3_protectedConstructor { //存放键值对:(“name”,对象实例) private static Map<String,Singleton3_protectedConstructor> map=new HashMap<>(); //泛型:用于管理对象实例,限定存储类型,避免强制类型转换 private static Singleton3_protectedConstructor single; protected Singleton3_protectedConstructor(){ } public static Singleton3_protectedConstructor getInstance(String name){ //判断:要获取的是什么 父类?子类? if(name==null){ name="Singleton3_protectedConstructor ";//默认获取父类的--单例对象 } //判断:map容器中,是否已存在这样的对象--无则创建并添加 if( map.get(name)==null){ try{ single=(Singleton3_protectedConstructor ) Class.forName(name).newInstance(); map.put(name, single); }catch(Exception e){ e.printStackTrace(); } } return map.get(name); //从容器里:取出该对象 } //一般方法:用于测试多态 public void say(){System.out.println("this is father class--singleton class");} }
//子类 class Son extends Singleton3_protectedConstructor { public Son(){ }//构造器 public static Son getInstance(){//获取对象实例 return (Son) Singleton3_protectedConstructor.getInstance("Son"); } //一般方法:用于测试多态 public void say(){System.out.println("this is son class");} }
测试结果:
public class SingletonTest { public static void main(String[] args) { //创建对象---验证静态内部类单例 /** Singleton1_staticInnerClass s= Singleton1_staticInnerClass.getInstance(); Singleton1_staticInnerClass s2= Singleton1_staticInnerClass.getInstance(); System.out.println(s);//单例模式.Singleton@106d69c System.out.println(s2);//单例模式.Singleton@106d69c System.out.println(s.hashCode()+"--"+s2.hashCode());//17225372--17225372 */ //验证--双重验证加锁单例 /**Single_doubleCheck single=Single_doubleCheck.getInstance(); Single_doubleCheck single2=Single_doubleCheck.getInstance(); System.out.println(single.hashCode()+"--"+single2.hashCode());//17225372--17225372 System.out.println(single+"--"+single2); //单例模式.Single_doubleCheck@106d69c--单例模式.Single_doubleCheck@106d69c */ //创建对象---验证枚举实现的单例 /**Singleton_enum single=Singleton_enum.OBJ; Singleton_enum single2=Singleton_enum.OBJ; single.printInstance(); //原地址 17225372 System.out.println(single.hashCode());//实例1地址17225372 System.out.println(single2.hashCode());//实例2地址17225372 */ //创建对象---验证饿汉模式 /**Singleton_hungry single=Singleton_hungry.getInstance(); Singleton_hungry single2=Singleton_hungry.getInstance(); System.out.println(single.hashCode());//实例1地址17225372 System.out.println(single2.hashCode());//实例1地址17225372 System.out.println(single+"--"+single2); //单例模式.Singleton_hungry@106d69c--单例模式.Singleton_hungry@106d69c */ //创建对象---验证可以继承的单例模式 String name="单例模式.Singleton3_protectedConstructor";//单例类名:包名.类名 Singleton3_protectedConstructor single=new Son().getInstance(name) ; Singleton3_protectedConstructor single2=new Son().getInstance(name) ; Singleton3_protectedConstructor son=new Son().getInstance("单例模式.Son") ; System.out.println(single.hashCode());//17225372 System.out.println(single2.hashCode());//17225372 //测试多态 single.say();//this is father class--singleton class single2.say();//this is father class--singleton class son.say(); //this is son class } }