单例模式--饿汉式
单例模式是设计模式中的一种,百科资料显示有23种设计模式,每种设计模式都是为了解决特定的某个问题而设计的一套相对固定的编码流程!设计模式也区分为多种不同的类型,例如生产对象型、桥接型、代理型等,单例模式属于生产对象型的设计模式。
单例(单一实例,实例=对象)模式的目标:在同一时间,某个类的对象最多只可能存在1个,不会存在2个或更多个对象!
假设存在UserService
类:
public class UserService {}
则可以随意创建若干个对象:
UserService service1 = new UserService();
UserService service2 = new UserService();
UserService service3 = new UserService();
很显然,如果可以随意创建对象,是不符合单例模式的设计初衷的!之所以可以随意创建对象,是因为该类没有显式的声明构造方法,会导致编译器为这个类自动添加默认构造方法(公有的、无参数的),所以,以上类的代码等效于:
public class UserService {
public UserService() {
super();
}
}
为了限制对象的创建过程,可以将类的构造方法私有化,一旦显式的定义了构造方法,则编译器不会再自动添加构造方法:
public class UserService {
// 将构造方法的权限改为private
private UserService() {
super(); // 这句代码可以省略,编译器也会自动添加
}
}
则在类的外部将不可以通过UserService service = new UserService();
这样代码来创建对象了!
为了保证还是可以创建对象,甚至被类的外部获取对象,可以在类中自行创建,并对外提供获取对象的方法:
public class UserService {
// 在类的内部依然可以通过构造方法来创建对象
private UserService userService = new UserService();
private UserService() {
}
// 对外提供获取对象的方法
public UserService getInstance() {
return userService;
}
}
但是,以上代码是矛盾的,因为:如果要调用getInstance()
方法,就必须先得到类的对象,但是,得到类的对象的方式就是调用getInstance()
方法!也就是说:没有对象就不能调用getInstance()
方法,但是,不调用getInstance()
方法就无法得到对象!
为了解决这个矛盾,需要在getInstance()
方法上添加static
修饰符:
public class UserService {
private UserService userService = new UserService();
private UserService() {
}
// 添加static修饰符
public static UserService getInstance() {
return userService;
}
}
则可以通过类名.方法名()
来调用方法,也就是UserService.getInstance();
即可获取对象!
注意:以上代码是错误的,因为“被static
修饰的成员不可以直接访问非static
成员”!也就是说:在getInstance()
方法中是不可以访问(返回)userService
对象的!
为了解决问题,还需要为userService
属性也添加static
修饰符:
public class UserService {
// 添加static修饰符
private static UserService userService = new UserService();
private UserService() {
}
public static UserService getInstance() {
return userService;
}
}
至此,饿汉式单例模式就完成了(另外还有懒汉式的单例模式)!
注意:默认情况下,Spring框架管理的对象都具有“单例”的特点,但是,这些对象的类型并不是通过单例模式来设计的,只是这些对象具有“单例”的特点而已!所以,不要把Spring框架和单例模式混为一谈,它们之间没有任何关系!
注意:由于单例模式中,对象是添加了static
关键字进行修饰的,所以,单例的对象都具有“常驻内存”的特点!