package com.my.web.server; 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 com.my.web.model.UserInfo; /** * 序列化ser * @author zhangxiuxiu * */ public class SerializableSer { public static void main(String[] args) throws IOException, ClassNotFoundException { SerializableSer ser = new SerializableSer(); ser.serializable(); ser.deserialize(); } /** * 序列化 * @throws IOException */ public void serializable() throws IOException{ UserInfo u = new UserInfo("1", "zxx"); u.setPassword("zxx"); File file = new File("userinfo.txt"); file.createNewFile(); //序列化的过程 FileOutputStream fileOutputStream = new FileOutputStream(file); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(u); objectOutputStream.flush(); objectOutputStream.close(); fileOutputStream.close(); } /** * 反列化 * @throws IOException * @throws ClassNotFoundException */ public void deserialize() throws IOException, ClassNotFoundException{ File file = new File("userinfo.txt"); FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); UserInfo ui = (UserInfo)ois.readObject(); System.out.println(ui.toString()); ois.close(); fis.close(); } }
package com.my.web.model; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Serializable; import java.sql.Date; public class UserInfo implements Serializable{ /** * */ private static final long serialVersionUID = -7448507529918501715L; private String id; private String userName; private Date date; private transient String password; public UserInfo(String id,String userName){ System.out.println("有参数的构造方法:"+id+"--------"+userName); this.id = id; this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String toString(){ return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime()); } }
执行上面的test方法,结果如下
有参数的构造方法:1--------zxx
id:1;userName:zxx;password:null;date:
使用实现Serializable的方法进行序列化的时候,最好在model类中增加serialVersionUID的属性。如果model中没有该属性,在进行序列化的时候,会根据model中的属性、方法通过算法生成一个serialVersionUID。这样会存在一个问题:如果先将该model序列化到了一个文件中,然后中间修改了model中的属性,比如新增了一个属性,在用该文件中的流进行反序列化的时候,会出现一个错误,这是因为序列化和反序列的时候算法生成的serialVersionUID不一致。所以如果生成了一个固定的serialVersionUID,就可以正确进行反序列化。
报错如下图:
Exception in thread "main" java.io.InvalidClassException: com.my.web.model.UserInfo; local class incompatible: stream classdesc serialVersionUID = -7448507529918501715, local class serialVersionUID = 7932322403676295014
model里面可以新增writeObject和readObject方法,注意这里是用的新增,不是重写,因为Serializable中是没有这两个方法的。如果新增了这两个方法,在进行序列化的时候会执writeObject这个方法,就会不去执行默认的序列化方法,如果需要执行默认的方法,只需要增加out.defaultWriteObject();即可。反序列过程有类似的ois.defaultReadObject();方法,具体事例见下图
package com.my.web.model; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.sql.Date; public class UserInfo implements Serializable{ /** * */ private static final long serialVersionUID = -7448507529918501715L; private String id; private String userName; private String password; private Date date; private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); System.out.println("-----序列化-----"); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{ ois.defaultReadObject(); System.out.println("-----反序列化-----"); } public UserInfo(String id,String userName){ System.out.println(id+"--------"+userName); this.id = id; this.userName = userName; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String toString(){ return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime()); } }
打印结果如下图
1--------zxx
-----序列化-----
-----反序列化-----
id:1;userName:zxx;password:zxx;date:
当某个字段被声明为transient后,默认序列化机制就会忽略该字段。
package com.my.web.model; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.sql.Date; public class UserInfo implements Serializable{ /** * */ private static final long serialVersionUID = -7448507529918501715L; private String id; private String userName; private Integer age; private String address; private Date date; private transient String password; private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); //just do it out.writeObject(password); System.out.println("-----序列化-----"); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{ ois.defaultReadObject(); //just do it this.password = (String)ois.readObject(); System.out.println("-----反序列化-----"); } public UserInfo(String id,String userName){ System.out.println(id+"--------"+userName); this.id = id; this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String toString(){ return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime()); } }
在上面的代码中,运行的结果如下
1--------zxx
-----序列化-----
-----反序列化-----
id:1;userName:zxx;password:zxx;date:
但是,如果将just do it 下面红色的代码注释掉,运行的结果如下
1--------zxx
-----序列化-----
-----反序列化-----
id:1;userName:zxx;password:null;date:
二、实现Externalizable
通过实现Externalizable进行序列化和反序列的操作。这个在进行反序列的过程的时候,需要调用model的默认构造方法的,所以model一定要有public的无参构造方法,如果没有无参构造方法,在进行反序列化的时候,会提示错误。
Exception in thread "main" java.io.InvalidClassException: com.my.web.model.UserInfo; no valid constructor
有了无参数的构造方法,可以保证该model正常的进行序列化和反序列化,但是反序列化并不能取到值,必须在方法readExternal()中进行手动赋值。
package com.my.web.model; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.sql.Date; public class UserInfo implements Externalizable{ /** * */ private static final long serialVersionUID = -7448507529918501715L; private String id; private String userName; private Date date; private transient String password; public UserInfo(){ System.out.println("无参数的构造方法"); } public UserInfo(String id,String userName){ System.out.println("有参数的构造方法:"+id+"--------"+userName); this.id = id; this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String toString(){ return "id:"+id+";userName:"+userName+";password:"+password+";date:"+(date==null?"":date.getTime()); } @Override public void writeExternal(ObjectOutput out) throws IOException { // TODO Auto-generated method stub out.writeObject(id); out.writeObject(userName); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // TODO Auto-generated method stub this.id = (String)in.readObject(); this.userName = (String)in.readObject(); } }
上述的执行结果
有参数的构造方法:1--------zxx 无参数的构造方法 id:1;userName:zxx;password:null;date:
如果把上面红色的代码注释掉,执行结果
有参数的构造方法:1--------zxx 无参数的构造方法 id:null;userName:null;password:null;date: