Java序列化
Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。
Java序列化API提供一种处理对象序列化的标准机制。
Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端。这就需要有一种可以在两端传输数据的协议。Java序列化机制就是为了解决这个问题而产生。
若我们的对象需要序列化,需要实现序列化接口Serializable接口,Serializable接口没有方法,更像是个标记。有了这个标记的Class就能被序列化机制处理。
序列化的作用:
1)该对象保存的数据需要一直使用,我们可以将其序列化后写入硬盘长久保存,下次程序启动后我们还可以将其读取回来继续使用。
2)将对象进行网络传输。
原理:
将Object转换为byte系列,就是系列化,反之是反序列化。
为了在byte流中存储对象。
使用writeObject(Object)/readObject()进行序列化和反序列化。
JavaBean规范,必须实现Serializable接口,JavaAPI中的类大多是JavaBean,基本都实现了Serializable。
1、ObjectOutputStream(序列化)和 ObjectInputStream(反序列化)
如果没有实现Serializable接口,就进行序列化就出现异常。
例子:
public class Demo2_Serializable { public static void main(String[] args) throws Exception { //serializable(); noSerializable(); } /** 反序列化*/ public static void noSerializable() throws IOException, Exception{ ObjectInputStream ois = null; try{ FileInputStream fis = new FileInputStream("person.obj"); /** 使用ObjectInputStream反序列化 */ ois = new ObjectInputStream(fis); /** 读取字节并转换为对象,强制转换,如果有多个要按照系列化的顺序来顺序得到对象*/ Persons person = (Persons)ois.readObject(); Persons person1 = (Persons)ois.readObject(); System.out.println(person); System.out.println(person1); } finally{ if(ois!=null){ ois.close(); } } } /** 序列化 */ public static void serializable() throws IOException{ Persons person = new Persons("boss","123456",16,1); Persons person1 = new Persons("刘德华","123456",16,1); /** * 将对象保存在文件中 * 1、创建用于写文件的字节输出流FileOutputStream * 2、创建用于序列化对象的ObjectOutputStream并让其处理FileOutputStream,这样就可以将对象序列化成字节不保存到文件。 * 3、使用ObjectOutputStream将对象写出。 */ ObjectOutputStream oos = null; try{ FileOutputStream fos = new FileOutputStream("person.obj"); oos = new ObjectOutputStream(fos); //序列化之后写入文件 oos.writeObject(person); oos.writeObject(person1); /** * 注:写出的只有属性值,但实际上写出的字节总量比所有属性值的总字节要大。 */ } finally{ if(oos!=null){ oos.flush(); oos.close(); } } } } class Persons implements Serializable{ private String name; private String password; private int age; private int sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public Persons(String name, String password, int age, int sex) { super(); this.name = name; this.password = password; this.age = age; this.sex = sex; } public Persons() { super(); } @Override public String toString() { return "Persons [name=" + name + ", password=" + password + ", age=" + age + ", sex=" + sex + "]"; } }
2、tarnsient关键字
tarnsient是java关键字,用来表示一个域不是该对象串行化的一部分,当一个对象被串行化的时候,tarnsient型变量的值不包括在串行化的表示中,然而非tarnsient型的变量是被包括进去。
反序列化后的对象,和原对象equals比较为true,但是他们不是同一个对象,且若属性也是引用类型,那么这些属性也不是同一个对象,但是equals比较也是true。
4、ByteArrayInputStream 和 ByteArrayOutStream
都有明确的来源和去向,两个流维护这一个字节数组。读写都在其内部维护的数组上了。
/** * 深度复制对象 */ public static Object deepClone(Object object){ try { /** * 1、创建用于将字节写入字节数组的字节输入流ByteArrayOutputStream * 2、创建用于序列化对象的ObjectOutputStream并处理 * 3、当对象被oos写出后,实际上就是通过ByteArrayOutputStream写到内部维护的字节数组上了,我们获取该数组 * 4、创建一个用于从数组中读取数据的输入流ByteArrayInputStream, * 并将之前保存着的对象序列化后的字节的数组传递给这个流。 * 5、创建用于反序列化对象的ObjectInputStream并处理ByteArrayInputStream * 6、使用OIS读取并反序列化对象达到深度复制的目录。 */ ByteArrayOutputStream baos = new ByteArrayOutputStream();//1 ObjectOutputStream oos = new ObjectOutputStream(baos);//2 oos.writeObject(object);//3 //获取 维护的数组 byte[] data = baos.toByteArray(); //4 转化为输入流 ByteArrayInputStream bais = new ByteArrayInputStream(data); //5 ObjectInputStream ois = new ObjectInputStream(bais); //6 Object copy = ois.readObject(); oos.close(); ois.close(); return copy; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } public static void main(String[] args) { Persons person = new Persons("吴","2332523",25,0); Persons person1 = new Persons("吴g","2332523",25,0); ArrayList<Persons> list = new ArrayList<Persons>(); list.add(person); //list.add(person); ArrayList<Persons> list2 = (ArrayList<Persons>)deepClone(list); //System.out.println(list.get(0)==list.get(1)); System.out.println(list == list2); System.out.println(list.get(0) == list2.get(0)); System.out.println(list.get(0).equals(list2.get(0))); }
此外对于Java序列化的原理算法透析可参考http://developer.51cto.com/art/200908/147650.htm