1.传输对象
package com.study.serializable;
/**
* Created by chenli on 2019/11/9.
*/
public class User {
private String name;
private int 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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.ClientSocket–客户端
package com.study.serializable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
/**
* Created by chenli on 2019/11/9.
*/
public class ClientSocket {
public static void main(String[] args) throws IOException {
Socket socket=new Socket("localhost",8080);
ObjectOutputStream objectOutputStream=new ObjectOutputStream(socket.getOutputStream());
User user=new User();
user.setAge(12);
user.setName("chenli");
objectOutputStream.writeObject(user);
objectOutputStream.flush();
}
}
3.SocketService服务端
package com.study.serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by chenli on 2019/11/9.
*/
public class SocketService {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ServerSocket serverSocket=null;
serverSocket=new ServerSocket(8080);
Socket socket= serverSocket.accept();
ObjectInputStream objectInputStream=new ObjectInputStream(socket.getInputStream());
User user=(User) objectInputStream.readObject();
System.out.println("server:接收到的user:"+user);
}
}
由于对象未序列话,则报出的错误
Exception in thread "main" java.io.NotSerializableException: com.study.serializable.User
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.study.serializable.ClientSocket.main(ClientSocket.java:18)
表示该对象未序列话,解决错误的方法是给user实现Serializable序列话
接受数据成功。
给User对象加上Serializable接口 就可以实现远程传输;
序列话是把对象的状态信息转化为可储存或者传输的形式过程。把对象转化为字节序列的过程称为序列化。
反序列话是把字节组反序列化恢复为对象的过程为反序列化。
java原生序列化
主 要通过输出流java.io.ObjectOutputStream和对象输入流java.io.ObjectInputStream来实现。
java.io.ObjectOutputStream:表示对象输出流 , 它的writeObject(Object obj)方法可以对参 数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。 java.io.ObjectInputStream:表示对象输入流 ,它的readObject()方法源输入流中读取字节序 列,再把它们反序列化成为一个对象,并将其返回。需要注意的是被序列化的对象要实现Serializable接口。
序列化版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识 符的静态变量
一是默认的 1L ,比如: private static final long serialVersionUID = 1L; 二是根据类名、接口名、成员方法及属性等来生成一个 64 位的哈希字段 ;
当序列化接口没有显示的定义这个属性时,则java序列化机制会自动根据编译的 Class 自动生成一个 serialVersionUID 作 序 列 化 版 本 比 较 用 ,这 种 情 况 下,如果 Class 文件 ( 类名,方法明等 ) 没有发生变化 ( 增加空格,换行,增加注释等等 ) ,就算 再编译多次, serialVersionUID 也不会变化的。
Transient 是控制变量序列化,在属性上加上这个关键字,则不能被序列化,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
虽然name被transient修饰,但是通过我们写的这两个方法依然能够使得name字段正确 被序列化和反序列化
writeObject 和 readObject 是两个私有的方法,他们是什么时候被调用的呢?从运行结果来 看,它确实被调用。而且他们并不存在于Java.lang.Object,也没有在Serializable中去声明。 我们唯一的猜想应该还是和 ObjectInputStream 和 ObjectOutputStream 有关系,所以基于 这个入口去看看在哪个地方有调用
从源码层面来分析可以看到,readObject是通过反射来调用的。 其实我们可以在很多地方看到readObject和writeObject的使用,比如HashMap。
1.java序列化只针对对象的状态保存,对象的方法,序列化不关心
2.当一个父类实现了序列化,它的子类会自动实现序列化,不需要显示到接口上。
3.当一个对象的实例变量引用的其他对象,序列化这个对象的时候会自动把引用的对象序列化。
4.当某个字段被申明为transient后,默认的序列化机制会忽略这个字段
5. 被申明为 transient 的字段,如果需要序列化,可以添加两个私有方法:writeObject 和 readObject ;
随着分布式架构、微服务架构的普及。服务与服务之间的通信成了最基本的需求。这个时候, 我们不仅需要考虑通信的性能,也需要考虑到语言多元化问题 所以,对于序列化来说,如何去提升序列化性能以及解决跨语言问题,就成了一个重点考虑 的问题。
由于Java本身提供的序列化机制存在两个问题:
1.序列化数据比较大,传输效率低
2.其他语言无法实现对接
1.xml序列化的可读性好,方便阅读和调试;字节码文件比价大,不方便阅读;
2. JSON序列化
Jackson /FastJson /Google的GSON ;Jackson 与 fastjson 要比 GSON 的性能要好,但是 Jackson、 GSON的稳定性要比Fastjson好。而fastjson的优势在于提供的api非常容易使用 ;
3.Hessian 序列化
Hessian 是一个支持二进制序列化协议,Hessian 具有更好的性能和易用性;支持不同的语言;实际上dubbo采用的是Hessian 序列化来实现,只不过dubbo对Hessian 进行重构,性能高;
4.Avro 序列化
支持 二进制序列化方式,可以便捷,快速地处理大量数据;
5.kyro 序列化框架
kyro 是一种非常成熟的序列化实现,已经在Hive、Storm)中使用得比较广泛,不过它不能 跨语言. 目前 dubbo 已经在 2.6 版本支持 kyro 的序列化机制。它的性能要优于之前的 hessian2
6.Protobuf 序列化
Protobuf是Google的一种数据交换格式,它独立于语言、独立于平Protobuf使用比较广泛,主要是空间开销小和性能比较好,非常适合用于公司内部对性能要 求高的 RPC 调用。 另外由于解析性能比较高,序列化以后数据量相对较少,所以也可以应 用在对象的持久化场景中 。