Java对象序列化研究

 

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();

    }

}

现在问题是:在上述这个类里面,含有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));        
    }

}

这里还用到了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;
    }

}

后面定义的2个类都是Serializable的,而且都有serialVersionUID。那么现在我们在Canvas里面加入Label类的实例,然后导出到文件,然后在导入,看内存地址指的对象是否还是同一个:

在Canvas中加入main方法:

public   static   void  main(String[] argus)  {
        Canvas c 
= new Canvas();
        Label label1 
= new Label(1"1"11);
        Label label2 
= new Label(2"2"22);

        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确是保存对象的拷贝了,而且是深拷贝。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值