Java单例模式
设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。
- 是基于场景的解决方案
- 具体场景具体分析
1、概念
目的:使得类的一个对象成为该类系统中的唯一实例。
定义:保证一个类有且只有一个实例,并且自行实例化向整个系统提供。
要点:
- 某个类只能有一个实例
- 必须自行创建实例
- 必须自行向整个系统提供这个实例
实现:
- 只提供私有的构造方法。
- 含有一个该类的静态私有对象。
- 提供一个静态的公有方法用于创建、获取静态私有对象。
2、代码实现方案
饿汉式实现:
SingletonOne类
package javase.javaDP;
/**
* @author JumperSun
* @date 2022-08-11-0:07
* 单例模式-饿汉式:创建对象实例时直接进行实例化,典型的空间换时间(速度快,空间大)
*/
public class SingletonOne {
// 1.创建类中的私有构造
private SingletonOne() {}
// 2.创建该类的私有静态实例
private static SingletonOne instance = new SingletonOne();
// 3.创建公有静态方法返回静态实例对象
public static SingletonOne getInstance() {
return instance;
}
}
Test类
package javase.javaDP;
/**
* @author JumperSun
* @date 2022-08-11-0:14
*/
public class Test {
public static void main(String[] args) {
SingletonOne one = SingletonOne.getInstance();
SingletonOne two = SingletonOne.getInstance();
System.out.println(one);
System.out.println(two);
// 输出值相同,说明有效
}
}
懒汉式实现:
SingletonTwo类
package javase.javaDP;
/**
* @author JumperSun
* @date 2022-08-11-0:18
* 单例模式-懒汉式:类内实例对象创建时并不直接实例化,直到第一次调用get方法时,才能完成初始化操作。典型的时间换空间(时间长,空间小)
*/
public class SingletonTwo {
// 1.创建类中的私有构造
private SingletonTwo() {}
// 2.创建静态的该类实例对象
private static SingletonTwo instance = null;
// 3.创建开发静态方法提供实例对象
public static SingletonTwo getInstance() {
if (instance == null) {
instance = new SingletonTwo();
}
return instance;
}
}
Test类
public class Test {
public static void main(String[] args) {
SingletonTwo one = SingletonTwo.getInstance();
SingletonTwo two = SingletonTwo.getInstance();
System.out.println(one);
System.out.println(two);
// 输出值相同,说明有效
}
}
饿汉式PK懒汉式:
1.饿汉式线程安全
2.懒汉式存在线程风险
- 同步锁
- 双重校验锁
- 静态变量类
- 枚举
3、单例模式的特点及适用场景
优点:
1.在内存中只有一个对象,节省内存空间
2.避免频繁的创建销毁对象, 提高性能
3.避免对共享资源的多重占用
缺点:
1、扩展比较困难
2、如果实例化后的对象长期不利用,系统将默认为垃圾进行回收,会造成对象状态丢失
适用场景:
1.创建对象时占用资源过多,但同时又需要用到该类的对象
2.对系统资源要求统一读写,如读写配置信息
3.当多个实例存在可能引起程序逻辑错误,如号码生成器
4、关于单例模式的常见问题
4.1 public static SingletonOne getlnstance(){}
A.该方法为什么用静态的?为什么要用这个类的类型作为返回值?
a. getInstance()方法的作用是实现该类对象的返回,因此需要设置该类类型作为方法返回值;至于static,则是因为对于单例模式而言,需要在类外能在无需产生对象实例的情况下,完成这个方法的调用,因此该方法需要设置为static。
B.只能叫这个名字吗?
b. 方法名并不限定,只是一种推荐命名,见名知义。
4.2 关于对象实例化、对象引用、对象声明的关系
完整的对象实例化的过程,可以分为声明和实例化两部分,这两步可以拆分也可以整合。
譬如:
// 对象声明
Cat one;
// 实例化
one=new Cat();
和
// 对象声明并完成实例化
Cat one=new Cat();
结合这段代码,one表示对象名,也可称为对象引用。
4.3 不是说,单例模式只能有一个对象吗,为什么在测试类里出现了两个singletonone的对象也不报错呢?
SingletonOne one = SingletonOne.getlnstance();
SingletonOne two = SingletonOne.getInstance();
所谓单例模式只能有一个对象,是指无论应用该类型产生多少对象,都是指向唯一的堆空间,所以测试类中,只是声明了两个对象的引用指向了同一内存空间,不会报错。
4.4 单例模式中的类成员是否需要加final修饰?从语法层面来说:
饿汉式:加入final修饰对于模式实现本身无影响
// 2、创建该类型的私有静态实例
private static final SingletonOne instance=new SingletonOne();
// 3、创建公有静态方法返回静态实例对象
public static SingletonOne getInstance(){return instance,
}
懒汉式:加入final修饰产生编译报错,提示信息为:无法对final修饰的成员进行操作。
原因是,final修饰的静态成员,如果在定义时未进行实例化,则需要在静态代码块中去实现,而不能到类方法中才进行实例化。
// 2、创建静态的该类实例对象
private static final SingletonTwo instance=null;
// 3、创建开放的静态方法提供实例对象
public static SingletonTwo getInstance(){
if( instance==null)
instance=new SingletonTwo();
return instance;
}
从应用层面来说:
如果饿汉式的程序代码中不仅涉及创建对象及返回的功能,还包括其他的功能,譬如资源回收等,就不能假如final修饰,会影响程序功能实现。
总结:
- 懒汉式中不能加入final。
- 如果在饿汉式代码中,对类实例只涉及创建和返回方法,可以加入final修饰。