一.对象序列化的作用
我们都知道Java是一门面向对象的语言,自然很多地方,都要有这种思想,网络传输数据,或者保存到磁盘文件中,是否可以以直接保存或则传输一个对象,数据都封装在对象里面(这样可以大大减少我们传输数据的操作),答案是一定的,对象的序列化就提供这样的作用。
二. 怎么实现序列化
对象序列化:把对象转换成字节流的过程 。
反序列化:从字节流中重构一个对象的过程。
让一个对象成为可序列化的,必须要该对象实现Serializable标记接口。默认的序列化处理过程是序列化对象中所有不是transient 和static的字段。这个Name类可以由writeObject直接写入ObjectOutputStream流里面去,name和id可以被写进去,而hash,hashset,nextId不能写入流中。通常,在我们转换成字节流,系统会为该类同时写入一个64位的serialVersionUID一个ID唯一标识这个类,一般我们最好手动标注,如果将来改动一下类,这个ID就会改变,反序列化就读取这个UID,就会不一致,出错抛出 InvalidClassException异常,我们应该标注出来(该UID必须为静态final字段而且是private),最好调出刚开始系统匹配出的UID值,就用他
ObjectStreamClass osc2 = ObjectStreamClass.lookup(Name.class);
// 获取到SerialVersionUID的值
System.out.println("" + osc2.getSerialVersionUID());
public class Name implements java.io.Serializable{
private static final long serialVersionUID=-1307795172754062330L;
private String name;
private long id;
private transient int hash;
private transient boolean hashSet=false;
private static long nextID=0;
public Name(String name){
this.name=name;
}
}
//通过流写入
ObjectOutputStream out=new ObjectOutputStream(in)//(进行流链接);
out.writeObject(name);//name是一个对象
怎么定制序列化?
有时候,我们不需要什么数据都写进去或则想要写入静态变量,这个时候就要重写writeObject()和readObject()
public class BeterName implements Serializable{
private static final long serialVersionUID=-1307795172754062330L;
private String name;
private long id;
private static long nextId=0;
public BeterName(String name,long id){
this.name=name;
this.id=id;
}
private void writeObject(ObjectOutputStream out){
throws IOException{
out.writeUTF(name);
out.writeLong(id);//这里可以控制转换成字节流里面的数据
}
}
private void readObject(ObjectInputStream in){
throws IOException{
name=in.readUTF();
id=in.readLong();//和writeObject相对应
}
}
}
下面是一个实际运用:
// StoreNode.java文件
import java.io.Serializable;
import org.omg.PortableInterceptor.IORInterceptor;
public class StoreNode implements Serializable{
private String ip;
public static String name="data";
private transient int hash;
public StoreNode(String ip){
this.ip=ip;
}
public String getIp(){
return ip;
}
public String getName(){
return name;
}
}
// main执行文件
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import main.StoreNode;
public class main {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("Data.txt");
StoreNode node = new StoreNode("192.0.0.1");
node.name="Hello World";
try {
if(file.exists()){
file.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(file);
ObjectOutputStream outputStream=new ObjectOutputStream(fileOutputStream);
outputStream.writeObject(node);
System.out.println("写入成功");
outputStream.close();
FileInputStream inputStream=new FileInputStream(file);
ObjectInputStream stream = new ObjectInputStream(inputStream);
StoreNode node2 = (StoreNode)stream.readObject();
System.out.println("node 2 读出来的ip地址为: "+node2.getIp()+"\t node 2读出来的name: "+ node2.getName());
stream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行结果
(解释一下: 如果直接运行这个文件 name=’Hello world’ 你会以为name这个属性写进去去了,因为测试都在同一个机器(而且是同一个进程),因为这个jvm已经把name加载进来了,所以获取的是加载好的name),这时候要想获得正确结果,可以先执行写入文件,写入到data.txt中,然后关闭Eclipse,再执行readObject部分就会发现结果不一样)