什么是序列化和反序列化

序列化:可以将对象转化成一个字节序列,便于存储。
反序列化:将序列化的字节序列还原。
优点:可以实现对象的”持久性”, 所谓持久性就是指对象的生命周期不取决于程序。

序列化方式1: 实现Serializable接口(隐式序列化)

通过实现Serializable接口,这种是隐式序列化(不需要手动),这种是最简单的序列化方式,会自动序列化所有非static和 transient关键字修饰的成员变量。
代码示例

class Student implements Serializable{

	private String name;
	private int age;
	public static int QQ = 1234;
	
	private transient String address = "CHINA";
	Student(String name, int age ){
		this.name = name;
		this.age = age;
	}
	
	public String toString() {
		return "name: " + name + "\n"
		+"age: " + age + "\n"
		+"QQ: " + QQ + "\n"
		+ "address: " + address;
	}
	
	public void SetAge(int age) {
		this.age = age;
	}
}

public class SerializableDemo {

	public static void main(String[] args) throws IOException,
ClassNotFoundException {
	//创建可序列化对象
		System.out.println("原来的对象:");
		Student stu = new Student("Ming", 16);
		System.out.println(stu);
		//创建序列化输出流
		ByteArrayOutputStream buff = new ByteArrayOutputStream();
		ObjectOutputStream out = new ObjectOutputStream(buff);
		//将序列化对象存入缓冲区
		out.writeObject(stu);
		//修改相关值
		Student.QQ = 6666; // 发现打印结果QQ的值被改变
		stu.SetAge(18);  //发现值没有被改变
		//从缓冲区取回被序列化的对象
		ObjectInputStream in = new ObjectInputStream(new
		ByteArrayInputStream(buff.toByteArray()));
		Student newStu = (Student) in.readObject();
		System.out.println("序列化后取出的对象:");
		System.out.println(newStu);
	}
}

打印的结果是:
原来的对象:name: Ming age: 16 QQ: 1234
address: CHINA
序列化后取出的对象:
name: Ming age: 16 QQ: 6666 address: null

发现address(被transient)和QQ(被static)也没有被序列化,中途修改QQ的值是为了以防误会QQ被序列化了。因为序列化可以保存对象的状态,但是QQ的值被改变了,说明没有被序列化。static成员不属于对象实例,可能被别的对象修改没办法序列化,序列化是序列对象。对于address被反序列化后由于没有对应的引用,所以为null。而且Serializable不会调用构造方法。
PS:细心的可能发现序列化很诱人,可以保存对象的初始信息,在以后可以回到这个初始状态

序列化方式2:实现Externalizable接口(显式序列化)

实现Externalizable接口继承自Serializable, 我们在实现该接口时,必须实现writeExternal()和readExternal()方法,而且只能通过手动进行序列化,并且两个方法是自动调用的,因此,这个序列化过程是可控的,可以自己选择哪些部分序列化
代码示例:

public class Blip implements Externalizable{

	private int i ;
	private String s;
	
	public Blip() {}
	public Blip(String x, int a) {
	System.out.println("Blip (String x, int a)");
		s = x;
		i = a;
	}
	
	public String toString() {
		return s+i;
	}
	
	@Override
	public void writeExternal(ObjectOutput out) throws IOException {
		// TODO Auto-generated method stub
		System.out.println("Blip.writeExternal");
		out.writeObject(s);
		out.writeInt(i);
	}
	
	@Override
	public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
	// TODO Auto-generated method stub
		System.out.println("Blip.readExternal");
		s = (String)in.readObject();
		i = in.readInt();
	}
	
	public static void main(String[] args) throws FileNotFoundException,IOException, ClassNotFoundException {
		System.out.println("Constructing objects");
		Blip b = new Blip("A Stirng", 47);
		System.out.println(b);
		ObjectOutputStream o = new ObjectOutputStream(new
		FileOutputStream("F://Demo//file1.txt"));
		System.out.println("保存对象");
		o.writeObject(b);
		o.close();
		//获得对象
		System.out.println("获取对象");
		ObjectInputStream in = new ObjectInputStream(new
		FileInputStream("F://Demo//file1.txt"));
		System.out.println("Recovering b");
		b = (Blip)in.readObject();
		System.out.println(b);
	}
}

打印的结果是:
Constructing objects
Blip (String x, int a)
A Stirng47
保存对象:
Blip.writeExternal
获取对象:
Recovering b
Blip.readExternal
A Stirng47
当注释掉writeExternal和readExternal方法后打印结果为:
Constructing objects Blip (String x, int a) A Stirng47 保存对象
Blip.writeExternal 获取对象 Recovering b Blip.readExternal null0
这说明:Externalizable类会调用public的构造函数先初始化对象,在调用所保存的内容将对象还原。假如构造方法不是public则会出现运行时错误

序列化方式3:实现Serializable接口+添加writeObject()和readObject()方法。(显+隐序列化)

如果想将方式1和方式2的优点都用到的话,可以采用方式3, 先实现Serializable接口,并且添加writeObject()和readObject()方法。注意这里是添加,不是重写或者覆盖。但是添加的这两个方法必须有相应的格式。
1. 方法必须要被private修饰 —–>才能被调用
2. 第一行调用默认的defaultRead/WriteObject() —–>隐式序列化非static和transient
3. 调用read/writeObject()将获得的值赋给相应的值 —–>显式序列化
代码示例:

public class SerDemo implements Serializable{
	public transient int age = 23;
	public String name ;
	public SerDemo(){
	System.out.println("默认构造器。。。");
}

public SerDemo(String name) {
	this.name = name;
}

private  void writeObject(ObjectOutputStream stream) throws IOException {
	stream.defaultWriteObject();
	stream.writeInt(age);
}

private void readObject(ObjectInputStream stream) throws
ClassNotFoundException, IOException {
	stream.defaultReadObject();
	age = stream.readInt();
}

public String toString() {
	return "年龄" + age + " " + name;
}

public static void main(String[] args) throws IOException,
ClassNotFoundException {
	SerDemo stu = new SerDemo("Ming");
	ByteArrayOutputStream bout = new ByteArrayOutputStream();
	ObjectOutputStream out = new ObjectOutputStream(bout);
	out.writeObject(stu);
	ObjectInputStream in = new ObjectInputStream(new
	ByteArrayInputStream(bout.toByteArray()));
	SerDemo stu1 = (SerDemo) in.readObject();
	System.out.println(stu1);
	}
}

打印结果为:年龄23 Ming
注释掉stream.writeInt(age)和age= stream.readInt()后:年龄0 Ming
方式3结合了显式和隐式序列化,Ming被正常序列化,由于age被trancient修饰,所以需要显式序列化

最后再说一下 Json序列化

Json序列化一般会使用jackson包,通过ObjectMapper类来进行一些操作,比如将对象转化为byte数组或者将json串转化为对象。现在的大多数公司都将json作为服务器端返回的数据格式。比如调用一个服务器接口,通常的请求为:xxx.json?a=xxx&b=xxx的形式
接着上个例子:

package serialize;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonSerialize {
 	public static void main(String[] args) throws IOException {
    	new JsonSerialize().start();
 }
 
 public void start() throws IOException {
 
	User u = new User();
    List<User> friends = new ArrayList<>();
    u.setUserName("张三");
    u.setPassWord("123456");
    u.setUserInfo("张三是一个很牛逼的人");
    u.setFriends(friends);
    
    User f1 = new User();
    f1.setUserName("李四");
    f1.setPassWord("123456");
    f1.setUserInfo("李四是一个很牛逼的人");
    
    User f2 = new User();
    f2.setUserName("王五");
    f2.setPassWord("123456");
    f2.setUserInfo("王五是一个很牛逼的人");
    friends.add(f1);
    friends.add(f2);
    
    ObjectMapper mapper = new ObjectMapper();
    Long t1 = System.currentTimeMillis();
    byte[] writeValueAsBytes = null;
    for (int i = 0; i < 10; i++) {
    	writeValueAsBytes = mapper.writeValueAsBytes(u);
}
    System.out.println("json serialize: " + (System.currentTimeMillis() -
t1) + "ms; 总大小:" + writeValueAsBytes.length);

    Long t2 = System.currentTimeMillis();
    User user = mapper.readValue(writeValueAsBytes, User.class);
    System.out.println("json deserialize: " + (System.currentTimeMillis() -
t2) + "ms; User: " + user);
	}
}

运行结果:
json serialize: 55ms; 总大小:341 json deserialize: 35ms;
User: User [userId=null, userName=张三, passWord=123456, userInfo=张三是一个很牛逼的人,
friends=[User [userId=null, userName=李四, passWord=123456, userInfo=李四是一个很牛逼的人, friends=null], User [userId=null, userName=王五, passWord=123456,
userInfo=王五是一个很牛逼的人, friends=null]]]