java的序列化和反序列化;
定义:序列化是指把一个对象写到一个输出流中;对象的反序列化是指从一个输入流中读取一个对象.只要实现了java.io.Serializable(标识接口)接口的对象才能被序列化和反序列化;
序列化的步骤:
1).创建一个对象输出流,它可以包装一个其他类型的输出流,比如文件输出流.
ObjectOutputStream out=new ObjectOutputStream(new fileOutputStream("c:/a.obj"));
2).通过对象输出流的writeObject()方法写对象
out.writeObject("hello");
out.close;
以上代码将一个String 对象保存到文件中.
对象的反序列化步骤:
1).创建一个对象输入流,他可以包装一个其他类型的输入流,例如文件输入流.
ObjectInputStream in=new ObjectInputStream(new FileInputStream("c:/a.obj"));
2).通过对象输入流的readObject()方法读取对象.
String obj=(String)in.readObject();
in.close();
当写入多个对象时,为了能正确读出数据,必须保证向输出流写对象的顺序与从输入流读对象的顺序相同.
一个简单的序列化 反序列化的例子:
=======================================================================================
Customer类(实现了Serializable标识接口)
import java.io.Serializable;
import java.util.Date;
public class Customer implements Serializable {
private String name;
private Date birthday;
private transientString password; 注释① public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Customer(String name,String password)
{
this.name=name;
this.birthday=new Date();
this.password=password;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ObjectSaver类:执行序列化,将类写到文件中
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
public class ObjectSaver
{
public ObjectSaver()
{
try {
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("c:/a.obj"));
String obj1="序列化对象";
Date obj2=new Date();
Customer obj3=new Customer("jalion","123456");
//序列化对象
out.writeObject(obj1);
out.writeObject(obj2);
out.writeObject(obj3);
out.close();
System.out.println("需要序列化的对象:"+obj1);
System.out.println("需要序列化的对象:"+obj2);
System.out.println("需要序列化的对象:"+obj3.getName()+"生日"+obj3.getBirthday()+"密码:"+obj3.getPassword());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[])
{
new ObjectSaver();
}
}
ObjectRead:反序列化类 从文件中读取对象
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Date;
public class ObjectRead {
public static void main(String args[])
{
// 反序列化对象
ObjectInputStream in;
try {
in = new ObjectInputStream(new FileInputStream("c:/a.obj"));
String obj11=(String)in.readObject();
Date obj22=(Date)in.readObject();
Customer obj33=(Customer)in.readObject();
System.out.println("反序列化的对象:"+obj11);
System.out.println("反序列化的对象:"+obj22);
System.out.println("反序列化的对象:"+obj33.getName()+"生日"+obj33.getBirthday()+"密码:"+obj33.getPassword());
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
说明:由于String和Date类都实现了Serializable接口,所以可以序列化,要进行序列化的类包括其属性中引用的类必须全部实现Serializable接口才能序列化,否则将会抛出java.io.NotSerializableException异常.
========================================================================================
注释①在类Customer中,有个属性password,由于将类序列化保存在文件中,可以通过网络传输,当password比较重要时,很容易通过读取文件或者拦截网络数据来得到password,所以应当禁止对这种属性序列化.解决办法就是将这个属性用transient修饰,例如例子中的注释处.当属性有transient修饰时,不进行序列化.
ObjectRead运行结果如下:
当有transient修饰时:
反序列化的对象:序列化对象
反序列化的对象:Tue May 08 10:56:40 CST 2007
反序列化的对象:jalion生日Tue May 08 10:56:40 CST 2007密码:null
当没有transient修饰时:
反序列化的对象:序列化对象
反序列化的对象:Tue May 08 10:56:40 CST 2007
反序列化的对象:jalion生日Tue May 08 10:56:40 CST 2007密码:123456
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
除了用以上方案,来保证传输过程中的安全,还可以用通过进一步控制序列化和反序列化的方式,来达到将password加密或其他方式来实现序列化.
可以在Costumer类中提供一个readObject()和writeObject()方法,当ObjectOutputStream对一个对象序列化时,如果该对象具有writeObject()方法,那么就会执行这一方法,否则就按默认的方式序列化,在writeObject()方法中,可以调用defaultWriteObject()方法,使得对象输出流执行默认的序列化操作.反序列化同理.在修改后的Costumer类中,提供了readObject()和writeObject()方法,使得transient类型的password属性能够进行特殊的序列化
①private void writeObject(ObjectOutputStream stream){}
②private void readObject (ObjectInputStream stream) {}
以上两个方法并不是在Serializable接口中实现的.如果要进一步控制序列化的方式,就可以实现这两个方法,方法名必须与方法①②完全一致.
=========================================================================
修改后的Customer类
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
public class Customer implements Serializable {
private String name;
private Date birthday;
private transient String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Customer(String name,String password)
{
this.name=name;
this.birthday=new Date();
this.password=password;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private void writeObject(ObjectOutputStream stream)
{
try {
stream.defaultWriteObject();//先按默认的方式序列化
stream.writeObject(jiami(password));
} catch (Exception e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
private void readObject(ObjectInputStream stream)
{
try {
stream.defaultReadObject();//先按默认的方式反序列化
password=jiemi((String)stream.readObject());
} catch (Exception e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
private String jiami(String password) //加密解密示意
{
return "gthgthg"+password;
}
private String jiemi(String password) //解密示意
{
String s=password.substring(7,password.length());
return s;
}
}
posted on 2007-07-01 10:08 李桢 阅读(545) 评论(0) 编辑 收藏 所属分类: java