什么是单例模式?
一个类只能有一个实例,并提供对该实例的全局访问点
一个类只能有一个对象,并且这个对象在程序的任何一个地方都能被访问
为什么要用单例模式?
情形:在系统操作中,不论对象1还是对象2都是对同一个本地系统进行操作,没必要实例化多个,如果实例化多个对象对同一组数据进行操作的话,很可能出现数据不一致的情况。并且频繁的创建或者销毁实例,会占用系统内存和降低性能。
单例模式的两个标准
- 该类只能创建一个实例
- 该实例可以全局访问
如何实现类只能创建一个实例
构造函数由private或protected修饰,不可为public。
当一个类的构造函数为private或protected时,这个类自身可以访问这个构造函数,所以可以让单例类创建自己的实例。必须为该类提供一个共有的静态方法,因为静态方法可以直接被类调用,即使没有实例化对象也可以调用所需要的方法。
如何防止实例化的类被改变
创建一个私有的静态成员变量来存储这个实例,使得用户不可以直接访问,想使用只能调用类的静态方法。
懒汉式实例化
定义:只有在第一次调用getInstance()方法的时候才创建实例,在此之前程序中都没有该实例的存在
用法:
1.构建一个私有的无参构造方法,防止用户直接实例化该类
例如: private A(){}
2.构建一个私有静态的空的本类实例来存储实例化的对象
例如 private static A instance;
3.构建一个共有的静态方法,返回值为本类,在类中判断这个类是否已经被实例化,如果为空 再实例化,如果不为空就直接返回之前实例化的值。
例如 : public static A getInstance(){
if(A == null){ a = new A(); }
return a;
}
4.使用时类名直接调用公有静态方法
例如: A. getInstance();
优点:节省内存,如果程序的执行期间没有用到这个实例,那在程序的整个生命周期中都不会创建这个实例。
缺点:线程不安全,如果有两个线程a b 交替执行,线程a先判断instance为null,此时切换到线程b,线程b也判断instance为null,线程b就会实例化该单例类并给instance变量赋值。这个时候线程a恢复执行,因为之前判断了instance为null,所以会继续实例化一个新的实例,这样就有可能造成数据丢失。
优化:使用synchronized关键字实现线程同步,但是会导致程序运行变慢
例如: public static synchronized A getInstance(){
if(A == null){ a = new A(); }
return a;
}
饿汉式实例化
定义:加载该单例类的时候就创建它的唯一实例
用法:
1.构建一个私有的无参构造方法,防止用户直接实例化该类
例如: private A(){}
2.实例化一个私有静态的对象
例如: private static A a = new A();
3.构建一个共有的静态方法,返回值为本类,不用进行空值判断
优点:在getInstance()方法中可以直接返回该实例,不用再判断是否为空
缺点:会占用一部分内存空间,因为即使本类在整个程序的生命周期中都没有被使用,也会创建实例