23中设计模式中,单例模式是我接触最多的模式,也是我目前为止唯一真正自己编程的时候用到的设计模式。。。。
单例模式的思想:在工程存续阶段,这个类只能有一个对象存在在内存里。常见的工具类,资源连接类等很多都是单例的。spring框架中的bean,默认情况下也是单例的(节省资源,提高效率)。
写法1:
package InvolvedMode.single; /** * Single : * @author xuejupo [email protected] * create in 2015-12-17 下午8:09:48 */ public class Single { public static void main(String[] args){ //访问类: try { ClassLoader.getSystemClassLoader().loadClass("InvolvedMode.single.single1"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("类加载完成----------"); int i = single1.i; System.out.println("访问类中的成员------"); single1 s = single1.getSingle(); s.myMeoth(); } } class single1{ public static int i = 1; public int getI(){ return i; } static{ System.out.println("变量被加载"); } private single1(){ System.out.println("类被初始化"); } private static single1 single = new single1(); public static single1 getSingle(){ return single; } public void myMeoth(){ } }
结果:
类加载完成---------- 变量被加载 类被初始化 访问类中的成员------
写法2:
public class Single { public static void main(String[] args){ //访问类: try { ClassLoader.getSystemClassLoader().loadClass("InvolvedMode.single.single2"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("类加载完成----------"); int i = single2.i; System.out.println("访问类中的成员------"); single2 s = single2.getSingle(); s.myMeoth(); } } class single2{ public static int i = 1; static{ System.out.println("变量被加载"); } private single2(){ System.out.println("类被初始化"); } private static class Singleton{ static{ System.out.println("内部类被加载"); } private static final single2 INSTANCE = new single2(); } public static single2 getSingle(){ return Singleton.INSTANCE; } public void myMeoth(){ } }
结果:
类加载完成---------- 变量被加载 访问类中的成员------ 内部类被加载 类被初始化
写法3:
enum single3{ SINGLE; private single3(){ System.out.println("类被初始化"); } static{ System.out.println("变量被加载"); } static int i; public void myMethod(){ } }
类似的,方法3就不贴测试用例了,结果为:
类加载完成---------- 类被初始化 变量被加载 访问类中的成员------
总结:
从以上结果可以看到,真正延迟加载的只是写法2:只有在用到单例模式的时候,整个类才会被初始化。写法一和写法3中,类被加载的时候不会初始化整个类,但是如果访问类的属性,就会初始化整个类(调用类的构造函数,实际上这时候类并不需要被构造,所以不是延迟加载)(网上很多人说的类被加载的时候就会初始化整个类肯定是不对的,但是除了类中变量被访问,不知道还有没有别的方法使整个类被初始化,比如用反射机制,还有一些容器的特殊的加载---加载类的时候也加载类的静态成员变量,这个有待考究)。
写法3是用枚举实现单例模式,这种写法很新颖,是1.5版本后出现的写法,Effective Java这本书推荐写法,这种写法可以使单例模式避免利用反射机制的攻击,真正实现了绝对只有一个实例的思想。