为什么在单例中声明所有实例字段都是瞬态的?
Why declare all instance fields transient in singletons?
To make a singleton class that is implemented using either of the previous
approaches serializable (Chapter 11), it is not sufficient merely to add imple-
ments Serializable to its declaration. To maintain the singleton guarantee, you
have to declare all instance fields transient and provide a readResolve method
(Item 77). Otherwise, each time a serialized instance is deserialized, a new
instance will be created
这引出了我的问题:为什么要声明所有实例字段为 transient ?我认为 readResolve 就足够了!
我的问题是:为什么作者说我们应该在单例中声明所有实例字段为瞬态
package com.effective.test;
import java.io.Serializable;
public class NormalBean implements Serializable {
private static final long serialVersionUID = 1L;
private transient int id;
/**
* no matter declare transient or not...nothing is different!why author say that??
*/
private/* transient */String name;
private NormalBean(int id, String name) {
this.id = id;
this.name = name;
}
private static final NormalBean INSTANCE = new NormalBean(12345,"jack");
public static NormalBean getInstance() {
return INSTANCE;
}
/*
* The readResolve method is called when ObjectInputStream has read an
* object from the stream and is preparing to return it to the caller.
* ObjectInputStream checks whether the class of the object defines the
* readResolve method. If the method is defined, the readResolve method is
* called to allow the object in the stream to designate the object to be
* returned.
*
* And in Singleton case we are returning the same instance that was created
* while classloading and no new instances are returned. So singletonness is
* maintained.
*/
private Object readResolve() {
return INSTANCE;
}
@Override
public String toString() {
return "NormalBean [id=" + id + ", name=" + name + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
+ "]";
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestTransientPlusReadResolve {
NormalBean bean=NormalBean.getInstance() ;
public void writeAndRead() throws IOException {
ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream("writeAndRead.txt"));
System.out.println("this is the one "+bean );
outStream.writeObject(bean);
outStream.close();
try {
Thread.sleep(500l);
} catch (InterruptedException e) {
e.printStackTrace();
}
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("writeAndRead.txt"));
try {
NormalBean backBean = (NormalBean) inputStream.readObject();
System.out.println("this is the one "+backBean );
System.out.println("still the One?"+(backBean==bean));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
inputStream.close();
}
}
public static void main(String[] args) throws IOException {
new TestTransientPlusReadResolve().writeAndRead();
}
}
输出为:
this is the one NormalBean [id=12345, name=jack, getClass()=class com.effective.test.NormalBean, hashCode()=366712642]
this is the one NormalBean [id=12345, name=jack, getClass()=class com.effective.test.NormalBean, hashCode()=366712642]
still the One?true
我认为如果您在单个 JVM 中使用它不会突出任何问题(class 将保存静态单例实例的引用,无论您如何序列化它)。也许在序列化后重新启动并读取文件会有所帮助,但我认为 class 加载应该在反序列化之前发生。
它还有性能方面的考虑。如果您不需要序列化字段的值,因为它们对于单身人士来说是相同的,那么为什么要序列化它,例如通过网络发送它,然后执行 readResolve
只是为了忽略您收到的值?
(Chapter 11)
什么第 11 章?
To maintain the singleton guarantee, you have to declare all instance fields transient
不,你不知道。不需要使实例变量 transient
来提供单例保证。提供一个readResolve()
方法就足够了。
my question is :why the author said we shuold declare all instance fields transient in singletons
什么作者?什么的作者?他在哪里说的?他的原话是什么?你的问题是什么?
可能他建议作为性能改进,因为序列化不会使用的数据只是浪费时间,space。
如果您将一个实例变量标记为瞬态,您是在告诉 JVM 跳过
当您尝试序列化包含它的对象时(忽略)这个变量。
序列化是 Java 最酷的功能之一;它可以让你保存(有时称为
"flatten") 一个对象,通过写入它的状态(换句话说,它的实例的值)
变量)到特殊类型的 I/O 流。通过序列化,您可以保存一个对象
到一个文件,甚至通过电线将其运送到另一端重新膨胀(反序列化),在
另一个 JVM。
To make a singleton class that is implemented using either of the previous approaches serializable (Chapter 11), it is not sufficient merely to add imple- ments Serializable to its declaration. To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method (Item 77). Otherwise, each time a serialized instance is deserialized, a new instance will be created
这引出了我的问题:为什么要声明所有实例字段为 transient ?我认为 readResolve 就足够了! 我的问题是:为什么作者说我们应该在单例中声明所有实例字段为瞬态
package com.effective.test;
import java.io.Serializable;
public class NormalBean implements Serializable {
private static final long serialVersionUID = 1L;
private transient int id;
/**
* no matter declare transient or not...nothing is different!why author say that??
*/
private/* transient */String name;
private NormalBean(int id, String name) {
this.id = id;
this.name = name;
}
private static final NormalBean INSTANCE = new NormalBean(12345,"jack");
public static NormalBean getInstance() {
return INSTANCE;
}
/*
* The readResolve method is called when ObjectInputStream has read an
* object from the stream and is preparing to return it to the caller.
* ObjectInputStream checks whether the class of the object defines the
* readResolve method. If the method is defined, the readResolve method is
* called to allow the object in the stream to designate the object to be
* returned.
*
* And in Singleton case we are returning the same instance that was created
* while classloading and no new instances are returned. So singletonness is
* maintained.
*/
private Object readResolve() {
return INSTANCE;
}
@Override
public String toString() {
return "NormalBean [id=" + id + ", name=" + name + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
+ "]";
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestTransientPlusReadResolve {
NormalBean bean=NormalBean.getInstance() ;
public void writeAndRead() throws IOException {
ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream("writeAndRead.txt"));
System.out.println("this is the one "+bean );
outStream.writeObject(bean);
outStream.close();
try {
Thread.sleep(500l);
} catch (InterruptedException e) {
e.printStackTrace();
}
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("writeAndRead.txt"));
try {
NormalBean backBean = (NormalBean) inputStream.readObject();
System.out.println("this is the one "+backBean );
System.out.println("still the One?"+(backBean==bean));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
inputStream.close();
}
}
public static void main(String[] args) throws IOException {
new TestTransientPlusReadResolve().writeAndRead();
}
}
输出为:
this is the one NormalBean [id=12345, name=jack, getClass()=class com.effective.test.NormalBean, hashCode()=366712642]
this is the one NormalBean [id=12345, name=jack, getClass()=class com.effective.test.NormalBean, hashCode()=366712642]
still the One?true
我认为如果您在单个 JVM 中使用它不会突出任何问题(class 将保存静态单例实例的引用,无论您如何序列化它)。也许在序列化后重新启动并读取文件会有所帮助,但我认为 class 加载应该在反序列化之前发生。
它还有性能方面的考虑。如果您不需要序列化字段的值,因为它们对于单身人士来说是相同的,那么为什么要序列化它,例如通过网络发送它,然后执行 readResolve
只是为了忽略您收到的值?
(Chapter 11)
什么第 11 章?
To maintain the singleton guarantee, you have to declare all instance fields transient
不,你不知道。不需要使实例变量 transient
来提供单例保证。提供一个readResolve()
方法就足够了。
my question is :why the author said we shuold declare all instance fields transient in singletons
什么作者?什么的作者?他在哪里说的?他的原话是什么?你的问题是什么?
可能他建议作为性能改进,因为序列化不会使用的数据只是浪费时间,space。
如果您将一个实例变量标记为瞬态,您是在告诉 JVM 跳过 当您尝试序列化包含它的对象时(忽略)这个变量。 序列化是 Java 最酷的功能之一;它可以让你保存(有时称为 "flatten") 一个对象,通过写入它的状态(换句话说,它的实例的值) 变量)到特殊类型的 I/O 流。通过序列化,您可以保存一个对象 到一个文件,甚至通过电线将其运送到另一端重新膨胀(反序列化),在 另一个 JVM。