以前看别人博客,设计到操作,都会让实现 Serializable,知道这叫序列化与反序列化,但什么是序列化与反序列化,不得而知,最近在深入学习IO专题,也就学习下序列化与反序列化。也接触到ArrayList源码,再一次佩服写jdk的那些大神。
概要序列化与反序列化,应该叫对象的序列化与反序列化。
对象的序列化,就是将Object转换成byte序列,反之叫对象的反序列化。
序列化流(ObjectOutputStream),是过滤流 ----> writeObject
反序列化流(ObjectInputStream) -----> readObject
对象必须实现序列化接口,才能实现序列化,否则将出现异常。
这个接口,里面没有任何方法,这只是一个标准。
对象序列化1、序列化代码
// 序列化
public static void test1(String file) {
try {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(file));
Student student = new Student(1, "张三", 20);
oos.writeObject(student);
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2、前面说到必须实现序列化接口,那我们实现看看会有什么异常
package com.fengwenyi.demo.io.serialize;
/**
* @author Wenyi Feng
*/
public class Student {
private String no;
private String name;
private int age;
public Student() {
}
public Student(String no, String name, int age) {
this.no = no;
this.name = name;
this.age = age;
}
// getter , setter and toString
}
测试结果:
3、实现序列化接口并完善
对象实现序列化
package com.fengwenyi.demo.io.serialize;
import java.io.Serializable;
/**
* @author Wenyi Feng
*/
public class Student implements Serializable {
private static final long serialVersionUID = 1591370122074648558L;
private String no;
private String name;
private int age;
public Student() {
}
public Student(String no, String name, int age) {
this.no = no;
this.name = name;
this.age = age;
}
// getter , setter and toString
}
反序列化
// 反序列化
public static void test2(String file) {
try {
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(file));
Student student = (Student) ois.readObject();
System.out.println(student.toString());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
测试代码:
public static void main(String[] args) {
String file = "E:\\Workspace\\IdeaStudio\\io-demo\\serialize-demo\\demo\\obj.dat";
test1(file);
test2(file);
}
测试结果:
通过ArrayList源码学习transient关键字transient关键字引入
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
序列化:
/**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
* instance is emitted (int), followed by all of its elements
* (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
反序列化:
/**
* Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
int capacity = calculateCapacity(elementData, size);
SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
为什么要这么做呢?
有两点:
1、String 已实现序列化接口,Ineger并没有实现
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
public final class Integer extends Number implements Comparable<Integer> {
是不是就是这个原因呢?显然不是,因为刚刚我们已经证明了。
2、数组需要提前预定数组大小,当然,我们设定的大小并没有完全填满,这就不需要都去序列化。
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
继承
情形一:父类实现序列化接口
class A implements Serializable {
public A() {
System.out.println("A....");
}
}
class A1 extends A {
public A1() {
System.out.println("A1...");
}
}
class A2 extends A1 {
public A2() {
System.out.println("A2...");
}
}
测试代码:
/**
* A:父类实现序列化
*/
public static void testA() {
try {
String fileA = "E:\\Workspace\\IdeaStudio\\io-demo\\serialize-demo\\demo\\fileA.dat";
ObjectOutputStream oosA = new ObjectOutputStream(new FileOutputStream(fileA));
A2 a2 = new A2();
oosA.writeObject(a2);
System.out.println("------------------------------");
ObjectInputStream oisA = new ObjectInputStream(new FileInputStream(fileA));
A2 aa2 = (A2) oisA.readObject();
System.out.println(aa2);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
测试截图:
情形二:子类实现序列化接口1
class B {
public B() {
System.out.println("B....");
}
}
class B1 extends B implements Serializable {
public B1() {
System.out.println("B1...");
}
}
class B2 extends B1 {
public B2() {
System.out.println("B2...");
}
}
测试代码:
/**
* B1:子类实现序列化
*/
public static void testB1() {
try {
String fileB1 = "E:\\Workspace\\IdeaStudio\\io-demo\\serialize-demo\\demo\\fileB1.dat";
ObjectOutputStream oosB = new ObjectOutputStream(new FileOutputStream(fileB1));
B2 b2 = new B2();
oosB.writeObject(b2);
System.out.println("------------------------------");
ObjectInputStream oisB = new ObjectInputStream(new FileInputStream(fileB1));
B2 bb2 = (B2) oisB.readObject();
System.out.println(bb2);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
测试结果:
情形三:子类实现序列化2
class B3 extends B {
public B3() {
System.out.println("B3...");
}
}
class B4 extends B3 implements Serializable {
public B4() {
System.out.println("B4...");
}
}
测试代码:
/**
* B2:子类实现序列化
*/
public static void testB2() {
try {
String fileB2 = "E:\\Workspace\\IdeaStudio\\io-demo\\serialize-demo\\demo\\fileB2.dat";
ObjectOutputStream oosB = new ObjectOutputStream(new FileOutputStream(fileB2));
B4 b4 = new B4();
oosB.writeObject(b4);
System.out.println("------------------------------");
ObjectInputStream oisB = new ObjectInputStream(new FileInputStream(fileB2));
B4 bb4 = (B4) oisB.readObject();
System.out.println(bb4);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
测试结果:
总结一下:
序列化,不论是父类实现序列化接口,还是子类实现序列化结果,都会调用构成方法。
反序列化,父类实现序列化接口,则不调用构造方法;子类实现序列化接口,父类(所有父类)都会调用构造方法。
后记序列化与反序列化到底有什么用,还不清楚,还得继续学习。
1、本节测试代码:serialize-demo
2、学习视频:文件传输基础——Java IO流