疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

设计模式之单例模式


 

   

  单例模式通常有两种,饿汉单例和懒汉单例。

  饿汉单例模式:

  public class Singleton {

  private static Singleton singleton = new Singleton();

  private int flag;

  public int getFlag() {

  return flag;

  }

  public void setFlag(int flag) {

  this.flag = flag;

  }

  private Singleton() {

  }

  public static Singleton getInstance() {

  return singleton;

  }

  懒汉单例模式

  public class Singleton2 {

  private static Singleton2 singleton;

  private Singleton2(){

  }

  public static synchronized Singleton2 getInstance(){

  

  if(singleton == null){

  singleton = new Singleton2();

  }

  return singleton;

  }

  饿汉单例模式中有一个 flag成员,以及相应的get和set方法。这不是单例模式必须的。方便后文做测试。

  可以看到,它们都有一个共同点,那就是都有一个静态的成员,且该成员就是自己。同样,它们都有一个静态方法,去返回自己的实例。

  这样做有什么意思呢,根据我自身的体会,刚开始学的时候,会不明白,这个模式怎么就能返回一个自己的实例,而且,在初始化实例的时候,对象本身有一个自己这个对象的方法,难道不会陷入死循环么,自己实例化的成员对象,又实例化一个。

  出现这样的疑问,是自己基础不牢固的问题。

  其实是这样的

  类定义中不能包含自己本身的对象,否则会引起像无限递归的问题,而静态成员属于类,而不属于对象,静态成员的作用域属于类,但不占类的大小,不属于类的对象,内存在全局存储区。

  静态成员是不属于类的实例的,它是类的在编译的时候初始化放在全局变量里面的。

  我们总是把类比喻成 一座大楼的图纸,而实例对象就是建造出来的大楼。但是静态成员是已经存在的东西,他不属于当时实际建造出来的那个大楼,而是图纸本身带有的东西。

  继续

  因为已经类的成员是静态的了,而且是私有的,所以,想要获得这个静态对象,就必须通过类的方法返回。所以我们需要一个可以 return Singleton类型的方法。

  这就是实现单例模式的基本思路。

  那么懒汉和饿汉有什么区别呢,其实看名字也能了解。

  饿汉是不管你什么时候用,我都在程序编译的时候,就生成一个静态对象放在全局变量区里面(就好像饿了很久的人迫不及待地去做吃东西)

  懒汉是你什么时候用,我什么时候给你实例一个对象,我不会在程序编译的时候生成对象(就好像一个有拖延症的人,等到deadline来的时候才会去做)

  既然这样,我们可以思考一个问题,饿汉因为迫不及待的去做(编译时就有了实例),所以当我们想要得到实例的时候,我们可以放心大胆的拿来用。

  那么在懒汉模式,我们怎么知道有没有已经生成的实例的呢?

  可以轻而易举地想到:加个if语句判断一下,如果这个静态成员为null,那么就实例化。

  这样做其实是会出现问题的:如果很多人在同时使用了这个方法,而此时静态成员却为null,那么系统会生成多于一个的静态实例(事实上会报错)。所以,我们

  给方法加一个 synchronized,表示这个方法只能同时被一个线程使用。

  一个简单的测试方法:

  public class testSingleton {

  public static void main(String[] args) {

  Singleton s = Singleton.getInstance();

  s.setFlag(3);

  Singleton s1 = Singleton.getInstance();

  System.out.println("s1的flag值为"+s1.getFlag());

  }

  思路:既然返回同一个单例,那么我在第一个引用中存入一个数值给一个变量,然后通过getInstance()给予第二个引用单例,在第二个引用中获取这个变量,如果这个变量的数值和我存的一样,那么就证明这是同一个实例。