把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。java
在java中socket传输数据时,数据类型每每比较难选择。可能要考虑带宽、跨语言、版本的兼容等问题。比较常见的作法有两种:一是把对象包装成JSON字符串传输,二是采用java对象的序列化和反序列化。随着Google工具protoBuf的开源,protobuf也是个不错的选择。对JSON,Object Serialize,ProtoBuf 作个对比。算法
实现了Serializable或Externalizable接口的类的对象才能被序列化,不然抛出异常。安全
import java.io.Serializable; public class Info implements Serializable { private static final long serialVersionUID = -7927179583519945413L; private String name=null; 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; } public Info(String name, int age) { this.name = name; this.age = age; } }
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class UseInfo { public static void main(String[] args) throws Exception { //序列化info对象 //1) 建立一个对象输出流,它能够包装一个其余类型的目标输出流,如文件输出流; Info info1 =new Info("张三",18); Info info2 =new Info("李四",19); File file =new File("info.txt"); System.out.println("文件是否已建立:"+file.exists()); FileOutputStream fos =new FileOutputStream(file); //2) 经过对象输出流的writeObject()方法写对象。 ObjectOutputStream oos =new ObjectOutputStream(fos); oos.writeObject(info1); oos.writeObject(info2); oos.flush(); oos.close(); fos.close(); //反序列化info对象 //1) 建立一个对象输入流,它能够包装一个其余类型的源输入流,如文件输入流; ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file)); Info i1=(Info)ois.readObject(); System.out.println(i1.getName()+" "+i1.getAge()); Info i2=(Info)ois.readObject(); System.out.println(i2.getName()+" "+i2.getAge()); //2) 经过对象输入流的readObject()方法读取对象。 ois.close(); } }
对象序列化包括以下步骤:
1) 建立一个对象输出流,它能够包装一个其余类型的目标输出流,如文件输出流;
2) 经过对象输出流的writeObject()方法写对象。socket
对象反序列化的步骤以下:
1) 建立一个对象输入流,它能够包装一个其余类型的源输入流,如文件输入流;
2) 经过对象输入流的readObject()方法读取对象。工具
serialVersionUID: 字面意思上是序列化的版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量this
实现Serializable接口的类若是类中没有添加serialVersionUID,那么就会出现以下的警告提示spa
采用这种方式生成的serialVersionUID是1Lcode
当咱们若是想要在序列化后改变类的属性而后反序列化,好比:在Info类里再加入一个sex属性,而后执行反序列化刚才的对象,在这个时候就会抛出异常。对象
文件流中的class和classpath中的class,也就是修改事后的class,不兼容了,处于安全机制考虑,程序抛出了错误,而且拒绝载入。那么若是咱们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是本身去指定serialVersionUID。接口
即
Java编译器会自动给这个class进行一个摘要算法,相似于指纹算法,只要这个文件 多一个空格,获得的UID就会大相径庭的,能够保证在这么多类中,这个编号是惟一的。因此,添加了一个字段后,因为没有显指定 serialVersionUID,编译器又为咱们生成了一个UID,固然和前面保存在文件中的那个不会同样了,因而就出现了2个序列化版本号不一致的错误。所以,只要咱们本身指定了serialVersionUID,就能够在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可使用,并且还多了方法或者属性能够用。
serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。若是对类的源代码做了修改,再从新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
类的serialVersionUID的默认值彻底依赖于Java编译器的实现,对于同一个类,用不一样的Java编译器编译,有可能会致使不一样的 serialVersionUID,也有可能相同。为了提升serialVersionUID的独立性和肯定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。
显式地定义serialVersionUID有两种用途:
① 在某些场合,但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备相同的serialVersionUID;
② 在某些场合,不但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备不一样的serialVersionUID。
1)Java序列化就是把对象转换成字节序列,而Java反序列化就是把字节序列还原成Java对象。
2)采用Java序列化与反序列化技术,一是能够实现数据的持久化,在MVC模式中非常有用;二是能够对象数据的远程通讯。