在1.5版本之前可以两种实现Singleton的方法,但是都要把构造器保存为私有的。
1、公有静态成员是个final域
- // Singleton with public final field - Page 17
- public class Elvis {
- public static final Elvis INSTANCE = new Elvis();
- private Elvis() { }
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.INSTANCE;
- elvis.leaveTheBuilding();
- }
- }
问题:但是客户端可以通过AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。
AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。
在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。
2、公有的成员是个静态工厂方法
这种方法很清晰的表明了这个类是一个Singleton
- // Singleton with static factory - Page 17
- public class Elvis {
- private static final Elvis INSTANCE = new Elvis();
- private Elvis() { }
- public static Elvis getInstance() { return INSTANCE; }
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.getInstance();
- elvis.leaveTheBuilding();
- }
- }
问题:同上
3、实现Singleton类变成可序列化的,仅仅实现序列化是不够的,为了维护并保证Singleton,必须声明所有实例域都是瞬时(transient)的,并提供一个readResolve方法。否则,每次反序列化一个序列的实例时,都会创建一个新的实例。
《The readResolve Method -- 序列化实现readResolve方法的作用》http://blog.csdn.net/partner4java/article/details/7058741
- import java.io.Serializable;
- // Serializable singleton with public final field - Page 18
- public class Elvis implements Serializable{
- public static final Elvis INSTANCE = new Elvis();
- private Elvis() { }
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- private Object readResolve() {
- // Return the one true Elvis and let the garbage collector
- // take care of the Elvis impersonator.
- return INSTANCE;
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.INSTANCE;
- elvis.leaveTheBuilding();
- }
- }
4、从JDK 1.5开始,实现Singleton,可以编写一个包含单个元素的枚举类型。
而且可以解决复杂的反序列化或者反射的攻击。
单元素的枚举类型已经成为实现Singleton的最佳方法。
- // Enum singleton - the preferred approach - page 18
- public enum Elvis {
- INSTANCE;
- public void leaveTheBuilding() {
- System.out.println("Whoa baby, I'm outta here!");
- }
- // This code would normally appear outside the class!
- public static void main(String[] args) {
- Elvis elvis = Elvis.INSTANCE;
- elvis.leaveTheBuilding();
- }
- }
相关推荐
- **副作用**:使用私有构造器的一个副作用是使得该类不能被继承。 **避免创建不必要的对象**: 1. **不可变对象**:对于不可变对象,可以通过缓存已创建的对象来避免重复创建。 2. **使用静态工厂方法**:如果一...
实现单例时,通常会使用私有构造器防止外部创建实例,同时提供一个静态方法用于获取唯一的实例。Java中常使用双重检查锁定(Double-Check Locking)或枚举方式来实现线程安全的单例。 ```java // 双重检查锁定示例 ...
#### EJ 第3条:用私有构造器或枚举类型强化Singleton属性 单例模式是一种常用的软件设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点。Kotlin通过`object`关键字进一步简化了单例模式的实现,使得创建...
另外,如果我们确实需要在不同类中使用私有构造函数,可以使用工厂方法或者友元类(friend class,Java中没有直接支持这一概念,但可以通过内部类或者持有对方的引用来实现类似效果)。工厂方法是一种设计模式,它...
Java中的枚举类型是线程安全的,并且只会装载一次,设计者充分考虑到了线程安全问题,因此使用枚举实现单例模式是一种简洁而且高效的解决方案。 6. 容器式单例(Singleton Holder) 通过一个私有的静态内部类...
1. **构造器的访问控制**:将构造器设为私有或受保护的,防止外部直接通过`new`关键字创建实例。 2. **静态实例成员**:定义一个静态的类成员变量,用于存储Singleton实例。 3. **公共访问方法**:提供一个公共的...
而“singleton method.txt”很可能是讲解或展示了不同类型的单例实现方式,包括传统的单例模式和基于枚举的单例实现。 通过深入学习和实践这三个主题,你将能更好地理解和掌握Java的核心特性,以及在实际项目中如何...
- 构造器私有化,防止其他类通过new关键字创建实例。 - 创建并保存该类的唯一实例,通常使用静态变量存储。 - 提供一个公共的静态方法或属性,以便外部获取这个唯一的实例。 常见的单例实现方式有以下几种: - **...
### Java面向对象编程中的单实例(Singleton)模式解析 #### 概述 在Java面向对象编程中,单...此外,随着Java语言的发展,还可以利用枚举类型来实现单实例模式,这种方式既简单又安全,值得在实际开发中考虑使用。
1. **避免反射攻击**:在私有构造器中添加条件判断,如`if (instance != null)`,这样即便反射尝试创建新实例也会被阻止。 2. **避免反序列化攻击**:为单例类实现`readResolve()`方法,确保即使反序列化也不会创建...
单态模式(Singleton Pattern)是一种常用的软件设计模式,它的核心目标是确保一个类在整个应用程序中只有一个实例,并提供全局...在某些情况下,如依赖注入框架或使用枚举类型替代,可以避免单态模式带来的复杂性。
- **枚举方式**:利用枚举类型天然的线程安全性和唯一性实现单例模式,简洁高效。 #### 五、单例模式的适用场景 单例模式适用于以下情况: - 系统只需要一个实例对象时。 - 单例对象需要被共享,并且所有的实例...
Java的反射API提供了获取构造器(Constructor)并创建对象的能力,如果构造器允许被访问,那么即使是私有的构造器也可以通过反射得到。因此,即使实现了单例模式,反射仍可能导致破坏单例模式的实例唯一性。在单例的...
在Java中,单例模式通常通过私有构造器、静态工厂方法或者枚举类型来实现。PMD的这个规则旨在提醒开发者,如果一个类只有一个公共构造器并且没有被标记为final,那么它可能是适合作为单例的。 在描述中提到的`...
1. **私有构造器(Private Constructor)**:这是最常用的控制对象创建的方式,特别是用于实现单例模式。通过将类的构造器声明为私有,外部类无法直接实例化它。例如: ```java public class Singleton { private ...
实现代码:public class Singleton { private Singleton() { // 私有化构造函数 } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton...
1. **私有构造器**: 单例类的构造器通常被声明为`private`,这样其他类无法通过`new`关键字直接创建该类的实例。这是防止外部代码实例化单例对象的第一道防线。 2. **静态内部类**: 在上述例子中,单例对象`...
单例可以通过私有构造器和静态工厂方法实现,或者使用枚举类型。使用枚举类型实现单例可以确保线程安全且防止反射攻击,是推荐的实现方式: ```java public enum Singleton { INSTANCE; public void someService...