Java对对象的序列化的支持很简单,只要涉及的类和本类实现了java.io.Serializable接口,有一个serialVersionUID 就可以利用java.io.ObjectOutputStream进行对象的二进制格式输出了:
package
objOutPut;
import java.io. * ;
import java.util.Hashtable;
import java.util.ArrayList;
public class Canvas implements Serializable ... {
private static final long serialVersionUID = -8391639048829504801L;
public Hashtable htLabels = null;
public ArrayList alLabels = null;
public Canvas() ...{
htLabels = new Hashtable();
alLabels = new ArrayList();
}
public void toFile(String fileSpec) throws FileNotFoundException,
IOException ...{
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(
fileSpec));
os.writeObject(this);
}
public Canvas fromFile(String fileSpec) throws FileNotFoundException,
IOException, ClassNotFoundException ...{
ObjectInputStream is = new ObjectInputStream(new FileInputStream(
fileSpec));
return (Canvas) is.readObject();
}
}
import java.io. * ;
import java.util.Hashtable;
import java.util.ArrayList;
public class Canvas implements Serializable ... {
private static final long serialVersionUID = -8391639048829504801L;
public Hashtable htLabels = null;
public ArrayList alLabels = null;
public Canvas() ...{
htLabels = new Hashtable();
alLabels = new ArrayList();
}
public void toFile(String fileSpec) throws FileNotFoundException,
IOException ...{
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(
fileSpec));
os.writeObject(this);
}
public Canvas fromFile(String fileSpec) throws FileNotFoundException,
IOException, ClassNotFoundException ...{
ObjectInputStream is = new ObjectInputStream(new FileInputStream(
fileSpec));
return (Canvas) is.readObject();
}
}
现在问题是:在上述这个类里面,含有2个容器:Hashtable和ArrayList。如他们都同时保存了对象o(我们知道容器只是拷贝保存对象的指针),在序列化的时候,会不会把o存2次呢?感觉起来应该是只保存一次。可是不敢确定,于是验证了下:
在同一个包里面,定义了一个Label类,他的实例会被放在上述容器中,
package
objOutPut;
public class Label implements java.io.Serializable ... {
private static final long serialVersionUID = -4343239993805802185L;
public int id;
public String name;
public Point labelPoint;
public Label(int id, String name, Point labelPoint)...{
this.id = id;
this.name =name;
this.labelPoint = labelPoint;
}
public Label(int id, String name, double x, double y)...{
this(id, name, new Point(x,y));
}
}
public class Label implements java.io.Serializable ... {
private static final long serialVersionUID = -4343239993805802185L;
public int id;
public String name;
public Point labelPoint;
public Label(int id, String name, Point labelPoint)...{
this.id = id;
this.name =name;
this.labelPoint = labelPoint;
}
public Label(int id, String name, double x, double y)...{
this(id, name, new Point(x,y));
}
}
这里还用到了Point类,一个超级简单的类,又是超级有用的类:
package
objOutPut;
public class Point implements java.io.Serializable ... {
private static final long serialVersionUID = 6582745579823418928L;
public double x;
public double y;
public Point(double x, double y)...{
this.x = x;
this.y = y;
}
}
public class Point implements java.io.Serializable ... {
private static final long serialVersionUID = 6582745579823418928L;
public double x;
public double y;
public Point(double x, double y)...{
this.x = x;
this.y = y;
}
}
后面定义的2个类都是Serializable的,而且都有serialVersionUID。那么现在我们在Canvas里面加入Label类的实例,然后导出到文件,然后在导入,看内存地址指的对象是否还是同一个:
在Canvas中加入main方法:
public
static
void
main(String[] argus)
...
{
Canvas c = new Canvas();
Label label1 = new Label(1, "1", 1, 1);
Label label2 = new Label(2, "2", 2, 2);
c.htLabels.put("1", label1);
c.htLabels.put("2", label2);
c.alLabels.add(label1);
c.alLabels.add(label2);
try ...{
c.toFile("C:/Canvas.out");
} catch (FileNotFoundException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
}
try ...{
Canvas cc = c.fromFile("C:/Canvas.out");
System.out.println(cc.htLabels.size());
} catch (FileNotFoundException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Canvas c = new Canvas();
Label label1 = new Label(1, "1", 1, 1);
Label label2 = new Label(2, "2", 2, 2);
c.htLabels.put("1", label1);
c.htLabels.put("2", label2);
c.alLabels.add(label1);
c.alLabels.add(label2);
try ...{
c.toFile("C:/Canvas.out");
} catch (FileNotFoundException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
}
try ...{
Canvas cc = c.fromFile("C:/Canvas.out");
System.out.println(cc.htLabels.size());
} catch (FileNotFoundException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
在Eclipse3.2下设置断点,观察CC中Hashtable和ArrayList中保存的Label实例的内存ID,同时也观察他们包含的Point的内存ID。发现是一样的。
结论:序列化时,即便容器包含2份对象指针,实际只会出现一个实例被序列化了。这个跟java容器本身保存对象指针是一致的。C++的Vector确是保存对象的拷贝了,而且是深拷贝。