class Dog implements Serializable{
public static final Dog INSTANCE = new Dog();
private Dog(){}
}
上面能控制只生成一个单实例吗?
如果对实现了Serializable的对象进行序列化后,再反序列化,内中会不只一个实例了,因为反序列化时会重新
生成一个对象。
既然INSTANCE为静态域,那序列化时返回的对象如果也是INSTANCE就可以解决问题了,而打开API我们发现
Serializable接口确实有这样两个特殊的方法描述:
? 将对象写入流时需要指定要使用的替代对象的可序列化类,应使用准确的签名来实现此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此 writeReplace 方法将由序列化调用,前提是如果此方法存在,而且它可以通过被序列化对象的类中定义的一
个方法访问。因此,该方法可以拥有私有 (private)、受保护的 (protected) 和包私有 (package-private) 访
问。子类对此方法的访问遵循 java 访问规则。
? 在从流中读取类的一个实例时需要指定替代的类应使用的准确签名来实现此特殊方法:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此 readResolve 方法遵循与 writeReplace 相同的调用规则和访问规则。
上述两个方法的只要出现,就会履盖以下两个方法(这两个方法本质的意义就是用来替换序列与反序列的对
象),虽然会执行它们,但最后得到的结果却是writeReplace、readResolve两个方法写入或读出的对象:
? private void writeObject(java.io.ObjectOutputStream out) throws IOException
? private void readObject(java.io.ObjectInputStream in)throws IOException, ClassNotFoundException;
另外,writeObject与readObject需成对实现,而writeReplace与readResolve则不需要成对出现,一般单独使
用。如果同时出现这四个方法,最后写入与读出的结果以writeReplace和readResolve方法的结果为准。
所以下要解决真真单实例问题,我们如下修正:
class Dog implements Serializable {
public static final Dog INSTANCE = new Dog();
private Dog() {}
private Object readResolve() {
return INSTANCE;
}
}
public class SerialDog {
public static void main(String[] args) throws IOException,
ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new ObjectOutputStream(bos).writeObject(Dog.INSTANCE);
ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray());
Dog dog = (Dog) new ObjectInputStream(bin).readObject();
System.out.println(dog == Dog.INSTANCE);//true
}
}
一个实现了Serializable的单例类,必须有一个readResolve方法,用以返回它的唯一实例。
分享到:
相关推荐
下面将详细介绍七种常见的单例模式实现方式,并结合多线程环境和反序列化测试进行讨论。 1. **饿汉式单例**: 这是最简单的单例实现,它在类加载时就创建了实例,因此是线程安全的。 ```java public class ...
### 单例模式详解 #### 概述与应用场景 单例模式是一种常用的设计模式,它的主要目的是确保某个类仅有一个实例...通过上述讨论,我们可以看到单例模式在不同场景下的适用性及其潜在问题,并学习到了相应的解决方案。
本文将详细讨论四种常见的单例实现方式:饿汉模式、懒汉模式、双重检查锁定(DCL)单例模式以及枚举单例。 1. **饿汉模式**: 饿汉模式是在类加载时就完成了实例化,避免了线程同步问题。这种方式简单且安全,但...
在实际开发中,还经常需要考虑单例的可序列化问题和多线程环境下的线程安全问题。 在提供的内容中,讨论了配置文件和其对应的Java类(ThirdConfig),这个类用于读取配置文件中的信息,并在内存中保持一个配置对象...
除了上述的单例模式实现,Java中还提供了`Enum`方式来创建单例,这种方式不仅简单且线程安全,同时也避免了反射和序列化攻击。例如: ```java public enum Singleton { INSTANCE; } ``` 通过枚举方式实现单例,...
枚举方式不仅避免了同步问题,还能防止反序列化导致的多实例问题。 单例模式的优点包括: - 节省内存:只创建一个实例,节省系统资源。 - 全局访问点:提供一个全局访问点,方便对单例对象的操作。 - 控制实例化...
除了上述四种方式,还可以使用枚举类型来实现单例,这是最安全且简洁的方式,因为它自动支持序列化并且防止反射攻击。 ```java public enum Singleton { INSTANCE; public void whateverMethod() { //... } } ...
在Java中实现单例模式有多种方法,这里主要讨论了两种常见的实现方式: 1. **饿汉式(Eager Initialization)** 饿汉式是在类加载时就完成了实例化,通过一个静态私有成员变量持有单例对象。由于实例在类加载时就...
数据库单例模式是一种在软件设计中常见的模式,它主要用于确保在一个应用程序中,数据库连接只被创建一次,并且全局范围内只有一个实例存在。这样可以避免频繁创建和销毁数据库连接带来的性能开销,同时也能保证多个...
同时,它提到了"protobuf",这是一个Google开发的序列化框架,用于高效地处理结构化数据,常用于网络通信和数据存储。"C++库"表明这个项目是用C++语言编写的,而"zip"则表示这是一个压缩文件。 首先,让我们深入...
在Java编程语言中,序列化是一种将对象的状态转换为字节流的过程,以便...如果你在实际应用中遇到关于Java序列化或`readResolve()`方法的问题,可以查阅更多相关文档或在线社区进行讨论,以获取更深入的理解和支持。
在Java中,通常通过私有构造器和静态工厂方法来实现单例,同时要防止反射和序列化破坏单例的唯一性。 其次,是**工厂方法模式**。它是一种创建型设计模式,提供了一种封装对象创建过程的方法,使得创建过程可以延迟...
原型设计模式有深拷贝和浅拷贝两种方式,深拷贝可以使用 clone 方法实现,也可以使用序列化来实现。 三、解释器设计模式 解释器设计模式是指使用解释器来解释某种语言的设计模式。该模式的核心角色包括 ...
在这种方法中,枚举类型的实例默认是单例的,线程安全且无法被反射或反序列化破坏。通过定义一个名为 `INSTANCE` 的枚举常量,我们可以得到单例的实例。枚举的这种特性使得它成为实现单例的一个优雅且推荐的方法。...
这包括工厂模式、单例模式、原型模式和创建者模式。 - 工厂模式:它提供了一种创建对象的最佳方式。通过一个工厂类,它可以根据不同的条件创建不同的对象,而不必直接使用new关键字创建。在简单工厂模式中,一个...
3. **序列化与反序列化**:将XML数据转换为内部数据结构,并能将内部数据结构重新写回XML文件。 4. **动画处理**:可能提供播放、停止、跳转帧等控制动画的方法。 5. **优化与压缩**:为了减少内存占用和提高加载...
- **单例模式**:确保一个类只有一个实例,并提供一个全局访问点。 - **工厂方法模式**:定义一个创建对象的接口,让子类决定实例化哪一个类。 - **抽象工厂模式**:提供一个创建一系列相关或相互依赖对象的接口,而...
设计模式是经过实践验证的解决方案模板,可以解决常见的设计问题,如单例模式、工厂模式、观察者模式等。通过模式的应用,开发者可以更高效地重用代码,提高系统的可维护性和可扩展性。 此外,书中还介绍了如何将...
- **单例模式**:限制类的实例只有一个,与原型模式的多实例创建相对。 6. **与Java中的序列化与反序列化对比**: - 序列化和反序列化也可以达到类似克隆的效果,但它们通常用于持久化数据或跨网络传输,不是为了...
常见的设计模式包括单例模式、工厂模式、策略模式、观察者模式等。 对于那些对面向对象技术有一定了解,但希望进一步提高自己开发水平的应用开发人员,本书提供了一个宝贵的学习资源。它不仅帮助读者在概念上理解...