Java序列化
Java提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列化,该字节序列化包括该对象的数据,有关对象的类型的信息和存储在对象中的数据类型。
将序列化对象写入文件后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可用用来在内存中新建对象。
整个过程都是java虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。
一个类的对象想要序列化成功需要满足:
1、该类必须实现java.io.Serializable接口。
2、该类中所有属性必须是可序列化的,如果有一个属性不可序列化,则该属性必须注明是短暂的(transient)
注意
当序列化一个对象到文件时,按照Java的标准约定是给文件一个.ser扩展名(只是约定)
对于jvm可以反序列化对象,它必须是能够找到字节码的类,如果jvm在反序列化对象的过程中找不到该类,则抛出一个ClassNotFoundException异常。
@Data
@ToString
public class SerializeEntiy implements Serializable {
private String name;
private String address;
private transient int SSN;
private int number;
}
public class SerializeDemo {
public static void main(String[] args) {
//序列化
serialize();
//反序列化
deserialization();
}
//反序列化
private static void deserialization() {
SerializeEntiy serialize = null;
try {
FileInputStream fileInput = new FileInputStream("/Users/Desktop/serilaize/serialize.ser");
ObjectInputStream input = new ObjectInputStream(fileInput);
serialize = (SerializeEntiy) input.readObject();
input.close();
fileInput.close();
System.out.println(serialize);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//序列化
private static void serialize() {
SerializeEntiy serialize = new SerializeEntiy();
serialize.setName("序列化");
serialize.setAddress("北京市朝阳区酒仙桥中路24号院");
serialize.setNumber(878);
serialize.setSSN(11);
try {
FileOutputStream fileOut = new FileOutputStream("/Users/Desktop/serilaize/serialize.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(serialize);
out.close();
fileOut.close();
System.out.println("Serialized data is saved in /Users/qiangzhang/Desktop/serilaize/serialize.ser");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字段无法序列化的几种场景:
1、静态变量不会序列化
2、transient关键字指定的属性
3、子类实现Serializable接口而父类没有实现时,父类中的属性是不会序列化的(父类实现了子类可以不用实现)
4、当序列化的类的serializversionUID 发生改变时,反序列化会失败
主流的序列化技术有哪些:
JSON/Hessian(2)/xml/protobuf/kryo/MsgPack/FST/thrift/protosbuff/Avro
FST/kryo不支持跨语言
实现工具:(因环境不同,测试结果也有不同)
JSON
org.codehaus.jackson
jackson-mapper-asl
1.9.2
com.alibaba
fastjson
1.2.74
性能分析:(可能会有差)Google的Jackson的序列化性能比Alibaba的fastjson性能要好,Alibaba的fastjson的反序列化性能比Google的Jackson性能要好,各有长短
public static void main(String[] args) throws IOException {
excuteWithJackson();
excuteWithFastJson();
}
//谷歌
protected static void excuteWithJackson() throws IOException {
User user = new User();
user.setName("zhang");
user.setAge(18);
byte[] bytes = null;
ObjectMapper objectMapper = new ObjectMapper();
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
bytes = objectMapper.writeValueAsBytes(user);
}
System.out.println("Jackson序列化,time:" + (System.currentTimeMillis() - start) + "ms,总大小->" + bytes.length);
long start1 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
User user1 = objectMapper.readValue(bytes, User.class);
}
System.out.println("Jackson反序列化,time:" + (System.currentTimeMillis() - start1) + "ms,总大小->" + bytes.length);
// System.out.println(user1);
}
//alibaba
protected static void excuteWithFastJson() {
User user = new User();
user.setName("zhang");
user.setAge(18);
String json = null;
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
json = JSON.toJSONString(user);
}
System.out.println("FastJson序列化,time:" + (System.currentTimeMillis() - start) + "ms,总大小->" + json.getBytes().length);
long start1 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
User user1 = JSON.parseObject(json, User.class);
}
System.out.println("FastJson反序列化,time:" + (System.currentTimeMillis() - start1) + "ms,总大小->" + json.getBytes().length);
}
结果:
Jackson序列化,time:60ms,总大小->25
Jackson反序列化,time:65ms,总大小->25
FastJson序列化,time:80ms,总大小->25
FastJson反序列化,time:40ms,总大小->25
protobuff(Google)
性能:压缩率高(字节数小),耗时短
com.baidu
jprotobuf
2.4.4
protected static void excuteWithProtoBuff() throws IOException {
User user = new User();
user.setName("zhang");
user.setAge(18);
byte[] encode = null;
Codec userCodec = ProtobufProxy.create(User.class, false);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
encode = userCodec.encode(user);
}
System.out.println("ProtoBuff序列化,time:" + (System.currentTimeMillis() - start) + "ms,总大小->" + encode.length);
long start1 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
User user1 = userCodec.decode(encode);
}
System.out.println("ProtoBuff反序列化,time:" + (System.currentTimeMillis() - start1) + "ms");
}
ProtoBuff序列化,time:29ms,总大小->9
ProtoBuff反序列化,time:2ms
Hessian
性能:压缩率比较低(字节数大),时间短
com.caucho
hessian
4.0.63
protected static void excuteWithHessian() throws IOException {
User user = new User();
user.setName("zhang");
user.setAge(18);
ByteArrayOutputStream os = new ByteArrayOutputStream();
HessianOutput hessianOutput = new HessianOutput(os);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
hessianOutput.writeObject(user);
if(i == 1){
System.out.println("总大小->" +os.toByteArray().length);
}
}
System.out.println("Hessian序列化,time:" + (System.currentTimeMillis() - start) + "ms,");
HessianInput hessianInput = new HessianInput(new ByteArrayInputStream(os.toByteArray()));
long start1 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
User user1 = (User)hessianInput.readObject();
}
System.out.println("Hessian反序列化,time:" + (System.currentTimeMillis() - start1) + "ms");
}
总大小->61
Hessian序列化,time:2ms,
Hessian反序列化,time:5ms