单例模式解决的问题就是可以确保一个类在内存中的对象唯一性。
它可以实现数据共享,比如A程序需要用到一个配置文件,B程序也要用到一个配置文件,现在有个需求:A程序如果修改了这个配置文件,B程序需要知道更新过后的这个配置文件。这时候就要使用单例模式来确保配置文件的唯一性。
那么如何确保对象的唯一性?
1 不允许其他程序用new来创建该类的对象。
2 在该类中创建一个本来实例。
3 对外提供一个方法让其他程序可以获取对象。
那么如何实现?
1 私有化该类的构造函数。这样类外部无法访问构造函数进行创建对象。
2 通过new在本类中创建一个本类对象。
3 定义一个公有的方法,将创建的对象返回,提供给外部使用。
代码实现:
class Single
{
static Single sg = new Single();
private Single()
{
}
//外部不能创建Single对象,还要获取这个对象,那么获取的函数必须是static,
//这样可以通过类名调用了。
public static Single getInstance()
{
return sg;
}
//--------------------------------------------------
private int num; //单例里面的数据
public void SetNum(int num)
{
this.num = num;
}
public int GetNum()
{
return this.num;
}
//--------------------------------------------------
}
class SingleDemo
{
public static void main(String[] args)
{
Single s = Single.getInstance(); //①
Single s = Single.sg; //②
}
}
代码分析:
1 既然②也可以访问单例对象,那么为什么还要用①这种形式来访问呢?
因为通过②这种方式访问单例,不如形式①通过函数访问可控,①的可控体现在可以在函数内部对sg进行相关处理,(比如取不到单例就返回null)
说白了①方式是函数调用,函数内部可以写更多的代码来控制着单例。所以一般推荐①方式来访问。
2 为了避免不安全的调用,我们习惯将单例改成private权限,即
static Single sg = new Single() ==> private static Single sg = new Single()
接下来我们进一步修改:
class Single
{
private static Single sg = new Single(); //加了一个private限制 ③
private Single()
{
}
public static Single getInstance()
{
return sg;
}
}
class SingleDemo
{
public static void main(String[] args)
{
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
System.out.println(s1 == s2); //结果为true
}
}
我们看到上面代码的③:
如果我们延迟加载,在调用getInstance方法的时候再创建对象,我们需要修改一下代码如下:
//但是这种方式存在隐患,在多线程里面使用有时候会无法保证单例的唯一性。
class Single
{
//类加载进来,没有对象,只有调用了getInstace方法时,才会创建对象。
private static Single sg = null;
private Single()
{
}
public static Single getInstance()
{
if(sg == null)
a = new Single();
return sg;
}
}
注意:但是这种方式存在安全隐患,在多线程里面使用时候会无法保证单例的唯一性。