关于序列化的文字已经是汗牛充栋了,这里我就讲一下我个人理解到的java序列化.
什么是序列化?
序列化是将对象变成一连串的字节的过程,反序列化就是把一连串字节变成对象的过程.
什么情况下需要序列化
希望把对象变成文件和数据库数据的时候
在网络上以套接字的方式传输的时候
通过RIM远程传输对象的时候
首先,要理解为什么要用到序列化?如果我们有需要把对象永久的保存起来,就可以把java对象序列化文件,当需要的时候就可以反序列化成对象使用.
java类实现序列化接口Serializable,这个类就可以实现序列化了
代码实现序列化
创建一个普通类
package org.fkjava.oa.base;import java.io.Serializable;public class Chen implements Serializable{ private String name; private int age; public Chen(){ System.out.println("无参"); } public Chen(String name,int age){ System.out.println("有参"); this.name = name; this.age = age; } @Override public String toString(){ return "[" + name + " " + age + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}
序列化和反序列代码
package org.fkjava.oa.base;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class Jia { public static void main(String[] args) throws Exception { File file = new File("a.out"); ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(file)); Chen chen = new Chen("chen",19); oo.writeObject(chen); System.out.println("--------"); ObjectInputStream oi = new ObjectInputStream(new FileInputStream(file)); Chen c = (Chen) oi.readObject(); System.out.println(c); }}
可以看出,反序列的时候,没有调用对象的无参构造函数
看看writeObject()代码到底做了什么
............// remaining cases if (obj instanceof String) { writeString((String) obj, unshared); } else if (cl.isArray()) { writeArray(obj, desc, unshared); } else if (obj instanceof Enum) { writeEnum((Enum) obj, desc, unshared); } else if (obj instanceof Serializable) { writeOrdinaryObject(obj, desc, unshared); } else { if (extendedDebugInfo) { throw new NotSerializableException( cl.getName() + "\n" + debugInfoStack.toString()); } else { throw new NotSerializableException(cl.getName()); } }..........
可以看出只要是string,数组,枚举和实现了Serializable
如果希望某个属性不被序列化的,需要怎么做呢.
使用transient
package org.fkjava.oa.base;import java.io.Serializable;public class Chen implements Serializable{ private String name; private transient int age; public Chen(){ System.out.println("无参"); } public Chen(String name,int age){ System.out.println("有参"); this.name = name; this.age = age; } @Override public String toString(){ return "[" + name + " " + age + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}
如果不去掉transient,但是又想把对象的属性序列化到文件,怎么做呢.
private void writeObject(ObjectOutputStream oo) throws IOException{ System.out.println("write"); oo.defaultWriteObject(); oo.writeInt(age); } private void readObject(ObjectInputStream oi) throws IOException, ClassNotFoundException{ System.out.println("read"); oi.defaultReadObject(); int age = oi.readInt(); }
当序列化和反序列化对象的时候,默认是调用对象的writeObject和readObject方法,但是他们都是private,怎么调用你,明显是使用了反射.
如果实现序列化单例,当时反序列化出来的对象就不是单例了,这时候怎么办
private Object readResolve(){ System.out.println("redResolve"); return Chen.getInstance(); }
ObjectInputStream会提供一个方法readResolve,只要实现了这个方法,用户在设置返回的对象,这个对象就作为readObject返回的对象,如果没有实现,系统默认选取
writeObject的对象.