Java单例模式详解

来源:互联网 发布:oracle导入数据 编辑:程序博客网 时间:2024/04/30 06:00

要解决的问题

让一个类在内存中只有一个对象。

问题的由来

1.对于系统中的某些类来说只有一个实例很重要。
windows中只能打开一个任务管理器窗口。如果不使用机制对窗口对象进行唯一化,就会有我每点击一下按钮就出现一个任务管理器窗口这样的现象。如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符。
2.对于一些需要频繁创建的对象,用单例模式可以节约系统资源。

如何保证对象的唯一性

1.为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象
2.还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三步怎么用代码实现?
1.将构造函数私有化
2.在类中创建一个本类对象
3.提供一个方法可以获取到该对象。

饿汉式单例模式

class Single(){    private Singel(){}//将构造函数私有化    private static Single s=new Singel();    public static Singel getInstance()    {        return s;    }}class SingleDemo{    public static void main(String[] args)    {        Single ss=Single.getInstance();        Single sss=Single.getInstance();    }}

先将构造函数私有化,这样在其他类中就不能使用new来创建他的对象。
创建一个Single类型的变量s来存储创建的Single对象,这个变量不必让外界知道,所以加上private修饰符。

private Singel s=new Singel();

创建一个公开的方法来返回这个对象

public Singel getInstance(){    return s;}

方法要么通过对象来调用,要么通过类名来调用。现在不能创建对象了,只能通过类名调用。所以这个方法应该静态方法。
在本类中静态方法只能访问静态成员,所以s也应该为静态的。
这里写图片描述
第一调用Single.getInstance();的时候,先加载类,创建对象,将对象的地址赋给s,再调用getInstance方法再将地址赋给ss。
第二次调用的时候,内存中已经存在s了,直接将地址赋给sss就行了。(这就省去了频繁创建对象的过程)。
光写这几句话没什么意义,对事物该怎么描述的时候还怎么描述,只是当需要保证事物的对象在内存中唯一时,将这三步加上即可。

懒汉式单例模式

class Single{    private Single(){}    private static Single s=null;    public static Single getInstance()    {        if(s==null)            s=new Single();        return s;    }}

这种写法,当一个程序来调用,不会出现问题。但当多个程序调用的时候就可能出现问题。
比如A程序在执行了if(s==null)后,判断为null,本来应该接着执行,但cpu又去执行别的程序了(cup一个时刻只能执行一个程序,只不过是cup切换程序的速度很快,用户感觉不到)。
之后B在执行了if(s==null)后,判断为null,本来应该接着执行,cup又切换到了A程序接着往下执行,创建了Single对象。之后cup又切换到了B,B接着执行,又创建了一个对象。这时候对象已经不唯一了。

class Single{    private Single(){}    private static Single s=null;    public static synchronized Single getInstance()    {        if(s==null)            s=new Single();        return s;    }}

可以添加synchronized关键字来吧这段程序锁起来,即使A程序执行到if(s==null),cpu切换了出去。因为加了锁,B也进不来。
但是这时程序的效率就低了,不管s是否为null,之前我都要判断是否锁着呢。

class Single{    private Single(){}    private static Single s=null;    public static Single getInstance()    {        if(s==null)        {            synchronized(Single.class)            {                if(s==null)                    s=new Single();            }         }           return s;    }}

这样为s为空的时候才判断锁,减少了判断次数。

总结

饿汉式是Single类一进内存就已经创建好了对象。
懒汉式(也叫对象的延迟加载),在Single进内存的时候,对象还没有存在,只有调用了getInstance方法时,才建立了对象。
开发的时候用饿汉式,简单,安全(方法里就一句话,涉及不到多线程)。懒汉式面试的时候问的多。
玩儿单例模式就是为了用那个唯一对象,获取对象是首先要做的事,有了对象才能调用其它的方法。先创建后创建早晚都要加载。

0 0
原创粉丝点击