Java序列化之自定义序列化

时间:2021-10-08 19:22:02

背景
进行序列化传输时,有时不仅需要对象本身的数据,还需要传输一些额外的辅助信息,以保证信息的安全、完整和正确。为了做到这点需求,Java提供了一套有效的机制,允许在序列化和反序列化时,使用定制的方法进行相应的处理。

自定义与不自定义的区别在于,不自定义序列化时只是普通地将对象保存到文件中,而自定义时,在讲对象保存到文件前后都可以做一些代码实现。

两个接口
Java为程序员自定义序列化提供了两个接口,一个是Serializeble,另一个是Externalizable,其中externalize是使具体化的意思。

那么这两个接口有什么区别呢,从代码层面来说,Serializeble接口内部没有定义任何方法或字段,而Externalizeble接口内部定义了两个方法用来指定序列化策略和反序列化策略,这两个方法分别是readExternal和writeExternal。但值得一提的是,虽然Serializeble接口没有定义任何方法或字段,但在使用这个接口进行自定义序列化时,必须添加一组方法来实现自定义序列化策略,他们分别如下:

    private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
    在序列化和反序列化时便会自动调用这些规定好的方法进行序列化和反序列化,下面用代码去实现证明。

代码实现

1、通过Serializable
自定义类,这个类实现Serializable,并且添加一组方法

public class Person implements Serializable{
private static final long serialVersionUID = 1L;
private String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject(); //将当前类的非静态和非瞬时字段写入此流
Date date = new Date();
out.writeObject(date);
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject(); //从此流读取当前类的非静态和非瞬态字段
Date date = (Date)in.readObject();
Date now = new Date();
long offset = now.getTime() - date.getTime();

if(offset<100){
System.out.println("在正常的时间内接收到序列化对象");
}else{
System.out.println("接收传输时间过长,请注意");
}
}

}

这里注意两个重要的方法,一个是ObjectInputStream的defaultReadObject()、另一个是ObjectOutputStream的defaultWriteObject()

其实在我们没有在序列化类中添加writeObject(ObjectOutputStream out)和ReadObject(ObjectInputStream)的时候,当我们进行(ObjectOutputStream oos,,,ObjectInputStream ois)oos.writeObject(obj)和ois.readObject()的时候,调用的就是defaultReadObject()和defaultWriteObject();这两个方法的作用就是做常规的读对象和些对象,没有什么神奇的

API文档显示
Java序列化之自定义序列化

Java序列化之自定义序列化

2、通过Java网络编程相关代码测试
Server端代码

public class Server {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ServerSocket server = new ServerSocket(8010);
Socket socket = server.accept();

System.out.println("请求已接受");
InputStream in = socket.getInputStream();
ObjectInputStream objIn = new ObjectInputStream(in);
Person person = (Person)objIn.readObject();
System.out.println("姓名:" + person.getName());

objIn.close();
in.close();
socket.close();
server.close();

}
}

Client端代码

public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1",8010);
//创建一个流套接字并将其连接到指定IP的指定端口号
OutputStream out = socket.getOutputStream();
Person person = new Person();
person.setName("simple");

ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(person);
objOut.flush();
objOut.close();
out.close();
socket.close();
}
}

注意,运行时,先运行Server端,再运行Client端,原因很简单,只有服务器正常运行了,客户端才能对服务器进行请求,这是一对一的通信,结果如图:

Java序列化之自定义序列化

        下篇继续  自定义序列化之Externalizeble