Java对象的序列化

来源:互联网 发布:民族性格知乎 编辑:程序博客网 时间:2024/04/30 09:49

Java对象的序列化

有时候我们有这样的需求:

  1. 将对象(不是文件)在客户端和服务器端进行传递;

  2. 将对象存储到外存的文件中,并能够从文件中回复对象。

概念

序列化:(也叫串行化)就是把对象转换成字节的流的形式(由于对象存储的内容千差万别,这种流不可能是字符流,只能是字节流);

反序列化:从字节流中重构出对象的过程。

对象图:Java的序列机制能够自动搜索与被序列化对象密切相关的对象,并建立起一个描述关系的网络(要序列化a引用的对象,而对象中又有成员引用了B类对象,B类对象中又有成员引用了C类对象,如何处理?除非明确说明不序列化(transient关键字),否则将自动序列化其他的)。

Serializable接口:只有实现了Serializable接口的类,其对象才能被序列化或反序列化;Serializable接口中没有属性和方法,仅仅是一种让JVM解读的标识;实现这一接口的类,将被纳入对象图的搜索范围中。

源码实例

/** * 实现把一个对象写入文件,并且从这个文件恢复这个对象 * @author jin */public class Test1 {public static void main(String[] args) {A a=new A("Joyce", 22);System.out.println("创建一个对象a, name="+a.getName()+", age="+a.getAge());File file=new File("object.odt");try {FileOutputStream fos=new FileOutputStream(file);ObjectOutputStream oos=new ObjectOutputStream(fos);oos.writeObject(a);} catch (FileNotFoundException e) {e.printStackTrace();}catch(IOException e1){e1.printStackTrace();}try {FileInputStream fis=new FileInputStream(file);ObjectInputStream ois=new ObjectInputStream(fis);A b=(A)ois.readObject();System.out.println("从文中读出对象, name="+b.getName()+", age="+a.getAge());} catch (ClassNotFoundException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e1){e1.printStackTrace();}}}class A implements Serializable{private String name;private int age;public String getName(){return this.name;}public int getAge(){return this.age;}public A(String name, int age){this.name=name;this.age=age;}}运行结果:创建一个对象a, name=Joyce, age=22从文中读出对象, name=Joyce, age=22

transient关键字

java中,关键字transient是用来指明不被序列化的对象(该对象关联的其他引用,也将不再被纳入对象图搜索的范围)。

比如说上面的那个代码稍作修改:

/** * 实现把一个对象写入文件,并且从这个文件恢复这个对象 * @author jin */public class Test1 {public static void main(String[] args) {A a=new A("Joyce", 22);a.b=new B();System.out.println("创建一个对象a, name="+a.getName()+", age="+a.getAge());System.out.println("a.b.x="+a.b.x);File file=new File("object.odt");try {FileOutputStream fos=new FileOutputStream(file);ObjectOutputStream oos=new ObjectOutputStream(fos);oos.writeObject(a);} catch (FileNotFoundException e) {e.printStackTrace();}catch(IOException e1){e1.printStackTrace();}try {FileInputStream fis=new FileInputStream(file);ObjectInputStream ois=new ObjectInputStream(fis);A o=(A)ois.readObject();System.out.println("从文中读出对象, name="+o.getName()+", age="+o.getAge());System.out.println("o.b.x="+o.b.x);//注释掉} catch (ClassNotFoundException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e1){e1.printStackTrace();}}}class A implements Serializable{private String name;private int age;B b;//// transient B b;public String getName(){return this.name;}public int getAge(){return this.age;}public B getB(){return this.b;}public A(String name, int age){this.name=name;this.age=age;}}class B {int x=4;}

会报错(抛出NotSerializableException异常),按照注释修改后就不会;

注意:假如在Bb;前添加了关键字transient那么从字节流中读取对象时就没有B类对象b了。

自定义序列化/反序列化

为什么需要自定义序列化/反序列化?对敏感数据进行保护

序列化机制中其实隐藏了两个私有方法writeObject()readObject()。借助这两个方法,我们可以自己定制序列化和反序列化的方式

对可序列化的对象执行序列化或反序列化操作时,会自动调用这两个方法。(换言之,执行public修饰的writeObject()readObject()方法时,会自动调用对应的私有writeObject()readObject()方法)


待续……




反序列化和new创造对象

  • 产生的对象状态不同New是造出初始化的对象;反序列化是恢复对象的原有状态,不会自动调用相关构造函数。

  • 反序列化会触发相关对象图中涉及对象的构造

序列化中的Static属性

  • 静态属性即使未被transient关键字修饰,也不会被序列化。




原创粉丝点击