静态内部类可以达到线程安全问题,但是如果遇到序列化对象时,使用默认的方式运行得到的结果
坑你还是多例的。
package test;
import java.io.ObjectStreamException;
import java.io.Serializable;
public class MyObject implements Serializable {
private static final long serialVersionUID = 888L;
// 内部类方式
private static class MyObjectHandler {
private static final MyObject myObject = new MyObject();
}
private MyObject() {
}
public static MyObject getInstance() {
return MyObjectHandler.myObject;
}
protected Object readResolve() throws ObjectStreamException {
System.out.println("调用了readResolve方法!");
return MyObjectHandler.myObject;
}
}
这里主要要指出readResolve方法,有关这个方法的疑惑,可以看我这篇: Java序列化之readObjectNoData、readResolve方法
我们知道java 对象的序列化操作是实现Serializable接口,我们就可以把它往内存地写再从内存里读出而"组装"成一个跟原来一模一样的对象. 但是当我们遇到单例序列化的时候,就出现问题了。当从内存读出而组装的对象破坏了单例的规则,会创建新的对象。单例要求JVM只有一个对象,而通过反序化时就会产生一个克隆的对象,这就打破了单例的规则。
而当实现了readResolve方法后,jvm就会有readResolve返回指定对象,也就保证了单例性。
实验证明,如果没有声明readResolve方法,存入对象的hashcode和取出对象的hashcode不一致。
如下的测试代码:
package test.run;
import java.io.File;
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 test.MyObject;
public class SaveAndRead {
public static void main(String[] args) {
try {
MyObject myObject = MyObject.getInstance();
FileOutputStream fosRef = new FileOutputStream(new File(
"myObjectFile.txt"));
ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
oosRef.writeObject(myObject);
oosRef.close();
fosRef.close();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fisRef = new FileInputStream(new File(
"myObjectFile.txt"));
ObjectInputStream iosRef = new ObjectInputStream(fisRef);
MyObject myObject = (MyObject) iosRef.readObject();
iosRef.close();
fisRef.close();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
结果: