我试图通过添加readResolve()方法来编写Serializable Singleton类。我的目的是在序列化时获得与对象状态相同的对象。
下面的是我的测试示例代码:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SingletonDemo {
public static void main(String[] args) {
Singleton obj = Singleton.getInstance();
System.out.println("After NEW Object creation : " + obj);
obj.i = 5;
System.out.println("Object modified");
System.out.println("After Object 1st Modification : " + obj);
serializeMe();
System.out.println("Serialized successfully with object state : " + obj);
obj.i = 10;
System.out.println("Object modified again");
System.out.println("After Object 2nd Modification : " + obj);
Singleton st = (Singleton)deSerializeMe();
System.out.println("Deserialized successfully");
System.out.println("After Deserialization : " + st);
}
public static void serializeMe() {
FileOutputStream fos;
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("d:\\SingletonData.txt"));
oos.writeObject(Singleton.getInstance());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object deSerializeMe() {
ObjectInputStream oin = null;
Object obj = null;
try {
oin = new ObjectInputStream(new FileInputStream("d:\\SingletonData.txt"));
obj = oin.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
class Singleton implements Serializable {
int i;
private static Singleton obj = null;
private Singleton() {
System.out.println("Executing constructor");
i=1;
}
public static Singleton getInstance() {
if(obj == null) {
obj = new Singleton();
}
System.out.println("An instance is returned");
return obj;
}
/*private void writeObject(ObjectOutputStream oos) {
try {
oos.writeInt(i);
} catch (Exception e) {
e.printStackTrace();
}
}
private void readObject(ObjectInputStream ois) {
try {
i = ois.readInt();
} catch (Exception e) {
e.printStackTrace();
}
}*/
public Object readResolve() {
System.out.println("Executing readResolve");
return Singleton.getInstance(); // FIXME
}
@Override
public String toString() {
return "Singleton [i=" + i + "]";
}
}
输出:
Executing constructor
An instance is returned
After NEW Object creation : Singleton [i=1]
Object modified
After Object 1st Modification : Singleton [i=5]
An instance is returned
Serialized successfully with object state : Singleton [i=5]
Object modified again
After Object 2nd Modification : Singleton [i=10]
Executing readResolve
An instance is returned
Deserialized successfully
After Deserialization : Singleton [i=10]
我知道当前场景将始终返回具有最新Object状态的Singleton的相同实例。
我尝试重写writeObject()和readObject()(在上面的代码中注释)但没有得到所需的结果。 即。
After Deserialization : Singleton [i=5]
但是readResolve()中没有ObjectInputStream的引用,因此我可以在返回之前获取实例并使用序列化对象的状态更新它。
如果我的构思错了,请纠正我并帮助我解决这个问题。
感谢。
答案 0 :(得分:12)
以下是它的实现方式:
public class Singleton implements Serializable {
private static Singleton instance = new Singleton();
private int i;
public static Singleton getInstance() {
return instance;
}
private Singleton() {
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
instance = this;
}
private Object readResolve() {
return instance;
}
public static void main(String[] args) throws Throwable {
Singleton s = Singleton.getInstance();
s.i = 5;
ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
oos.writeObject(getInstance());
oos.close();
s.i = 7; //modified after serialization
InputStream is = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
Singleton deserialized = (Singleton) ois.readObject();
System.out.println(deserialized.i); // prints 5
}
}
答案 1 :(得分:5)
实施Serializable
单身人士的最佳方式是使用枚举。
来自Joshua Bloch的Effective Java:
" 这种方法在功能上等同于公共字段方法,除了它更简洁,免费提供序列化机制,并提供防止多个实例化的铁定保证,即使在面对复杂的序列化或反射攻击。虽然这种方法尚未被广泛采用,但单元素枚举类型是实现单例的最佳方式。"
节省一些时间并使用枚举。
有关同一主题的更多讨论,请参阅this问题。
答案 2 :(得分:3)
试试这个
Object readResolve() {
Singleton s = getInstance();
s.i = i;
return s;
}
请注意,readResolve不需要公开。
答案 3 :(得分:3)
虽然有助于在反序列化对象上检索“i”的值,但是投票的结果是正确的,它违反了单例设计模式。反序列化后,会创建两个“Singleton”类对象。
证明:修改main()方法如下:
public static void main(String[] args) throws Throwable {
Singleton s = Singleton.getInstance();
s.i = 5;
System.out.println("before serialization::"+s.i+" "+ s); //printing value and object
ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
oos.writeObject(getInstance());
oos.close();
s.i = 7; //modified after serialization
System.out.println("modified after serialization::"+s.i+" "+s);
InputStream is = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
Singleton deserialized = (Singleton) ois.readObject();
System.out.println("after deserialization::"+deserialized.i+" "+deserialized); //prints 5, but hashCode is different, which means object is not the same
}
输出是:
串行化前的:: 5 serialization.Singleton@1690726
序列化后修改:: 7 serialization.Singleton@1690726
反序列化后的:: 5 serialization.Singleton@1662dc8
即便是第二个建议也有同样的问题。 我尝试了更多配置,但没有成功。 有没有其他方法可以解决这个问题?
请使用“Singleton”标记主题,以便更广泛的受众群体。
感谢。
答案 4 :(得分:0)
这应该可以解决问题(基于你的初步问题):
public Object readResolve() {
System.out.println("Executing readResolve");
if (obj == null) // optionally use external boolean flag to control this
{
System.out.println("readResolve - assigned obj = this - loaded state");
obj = this;
}
return Singleton.getInstance();
}
如果要强制加载Singleton状态,请在反序列化存储状态之前设置obj = null
。
或者您可以添加boolean
标记,告知readResolve()
方法是保留还是覆盖obj
。
如果您在多线程环境中工作,请注意多线程问题。
答案 5 :(得分:0)
我相信只需在子类中返回它就可以了解
RewriteCond %{REQUEST_URI} !^/news/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]
我知道这是一个非常古老的帖子,但我偶然发现它和其他人也可能。
答案 6 :(得分:0)
我们也可以这样做,在getInstance()
内调用readResolve()
方法,并将结果存储到类型为Singleton
的某个引用变量中,然后返回引用。确保方法的返回类型应为Object
类型,可以提供任何访问修饰符。
private Object readResolve() {
Singleton instance = getInstance();
return instance;
}