orkerThread;
private static int population;
public Person(String lastName, String firstName)
{
stName = lastName;
this.firstName = firstName;
synchronized (Person.class)
{
population++;
}
System.out.println("Person's constructor is invoked");
}
public String toString()
{
return "Person " + firstName + " " + lastName;
}
static synchronized public int getPopulation()
{
return population;
}
}
在命令行运行其序列化程序和反序列化程序的结果为:
如何正确的使用Java序列化技术 技术研究系列
可以看到,在从流中读出数据构造Person对象的时候,Person 的父类Humanoid的默认
构造函数被调用了。当然,这点完全不用担心,如果你没有给父类一个默认构造函数,则编
译的时候就会报错。
这里,我们把父类Humanoid做如下的修改:
/**
* 抽象基本类,完成一些基本的定义
*/
public class Humanoid implements java.io.Serializable
{
protected int noOfHeads;
private static int totalHeads;
public Humanoid()
{
this(1);
System.out.println("Human's default constructor is invoked");
}
public Humanoid(int noOfHeads)
{
if (noOfHeads > 10)
throw new Error("Be serious. More than 10 heads?!");
this.noOfHeads = noOfHeads;
synchronized (Humanoid.class)
{
totalHeads += noOfHeads;
}
}
public int getHeadCount()
{
return totalHeads;
}
}
我们把父类标记为可以序列化, 再来看运行的结果:
如何正确的使用Java序列化技术 技术研究系列
可以看到,在反序列化的时候,如果父类也是可序列化的话,则其默认构造函数也不会
调用。这是为什么呢?
这是因为Java 对序列化的对象进行反序列化的时候,直接从流里获取其对象数据来生
成一个对象实例,而不是通过其构造函数来完成,毕竟我们的可序列化的类可能有多个构造
函数,如果我们的可序列化的类没有默认的构造函数,反序列化机制并不知道要调用哪个构
造函数才是正确的。
1.5 序列化带来的问题
我们可以看到上面的例子,在Person 类里,其字段population 很明显是想跟踪在一个
JVM里Person类有多少实例,这个字段在其构造函数里完成赋值,当我们在同一个JVM 里
序列化Person 并反序列化时,因为反序列化的时候Person 的构造函数并没有被调用,所以
这种机制并不能保证正确获取Person在一个JVM的实例个数,在后面的部分我们将要详细
探讨这个问题及给出比较好的解决方案。
2 控制序列化技术
2.1 使用readObject 和writeObject方法
由于我们对
于对象的序列化是采用如下的类来实现具体的序列化过程:
java.io.ObjectOutputStream
而该类主要是通过其writeObject 方法来实现对象的序列化过程,改类同时也提供了一
种机制来实现用户自定义writeObject 的功能。方法就是在我们的需要序列化的类