java序列化Protostuff和Serializable的区别
发布时间:2025-05-23 00:51:56 发布人:远客网络
一、java序列化Protostuff和Serializable的区别
1、序列化就是将Java Object转成byte[];反序列化就是将byte[]转成Java Object。
2、Java自带序列化机制java.io.Serializable
3、标识一个对象需要系列化,该对象类型需要实现 Serializable接口。
4、1,序列化的类型和反序列化的类型的序列化ID必须一致(远程信息交换时)。
5、2,静态数据不会被序列化,Transient关键字修饰的字段不会被序列化。
6、3,对象序列化存储时,两次存储相同值对象会有优化(第二次对象写入会只存储引用)。
7、Protostuff是一个序列化库,支持一下序列化格式:
8、graph(protostuff with support for cyclic references. See Serializing Object Graphs)
9、smile(binary json useable from the protostuff-json module)
10、@SuppressWarnings("unchecked")
11、public static<T> byte[] serialize(T obj){
12、Class<T> cls=(Class<T>) obj.getClass();//获得对象的类;
13、LinkedBuffer buffer= LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);//使用LinkedBuffer分配一块默认大小的buffer空间;
14、Schema<T> schema= getSchema(cls);//通过对象的类构建对应的schema;
15、return ProtostuffIOUtil.toByteArray(obj, schema, buffer);//使用给定的schema将对象序列化为一个byte数组,并返回。
16、throw new IllegalStateException(e.getMessage(), e);
17、public static<T> T deserialize(byte[] data, Class<T> cls){
18、T message= objenesis.newInstance(cls);//使用objenesis实例化一个类的对象;
19、Schema<T> schema= getSchema(cls);//通过对象的类构建对应的schema;
20、ProtostuffIOUtil.mergeFrom(data, message, schema);//使用给定的schema将byte数组和对象合并,并返回。
21、throw new IllegalStateException(e.getMessage(), e);
22、Serializable使用方便,可序列化所有类速度慢,占空间
23、Protostuff速度快,基于protobuf需静态编译
二、《java类中的serialVersionUID是什么作用》的评论
类中影响Serialization进程的特征,两边的操作使用的类版本不同,但它们的 serialVersionUID必须是一样的。它是用来识别两边的类是否兼容的,两边不同时不应该继续还原状态,而是应该停止下来,因为有人把事情搞错了。如果你的类没有实现 java.io.Serializable或 java.io.Externalizable,这个字段则没有意义。
如果你没听说过 Java Serialization(序列化,有人书翻译成串行化),那去找些 serialization介绍看看,下面说的第2段类结构变化时是中级水平的,理解 Java的一些细节才能理解,多数情况下人们只提到第一种情况(类的结构没有变化时),也只需要第一种情况。
当Serialization两端(比如Socket两端)使用一个类的不同版本时,我们必须提供 serialVersionUID,它可以用JDK自带的 serialver命令行来计算:
private static final long serialVersionUID= xxxx;
如果类中出现了下面两个方法,那么将会被用到,否则使用默认的实现:
private void readObject(ObjectInputStream) throws IOException,ClassNotFoundException;
private void writeObject(ObjectOutputStream)throws IOException;
记住这里出现的方法和字段都是 private.
新版本中仅增加了字段或方法而没有改变旧版本中已有的东西时,我们只要保证两个版本中的 serialVersionUID是一样的就行了.
具体样例可以看 JDK源码中的像 ArrayList这些类的代码的 readObject和 writeObject方法。
类的结构有些变化时,新版本对旧版本中某些东西进行了删减时, Field的变化我们需要在readObject和writeObject方法中进行处理
ObjectOutputStream.PutField类可达到这个目的
只是保证两个版本中的 serialVersionUID一致是行不通的
private static final long serialVersionUID;
private static final ObjectStreamField[] serialPersistentFields
下面样例是当客户端和服务端使用的类的版本不同并且类的结构也改变了,比如:
private static final long serialVersionUID= 12L;
private static final long serialVersionUID= 12L;
/*这是一段代码片段,我们假设新版本的类 name& email两个字段进行了修改
*(这里我们放到一个内部类EntryInternal中),而旧版本中直接属于这个类.
*请注意这里的字段和方法的签名,它们都是 private的或者是常量.
public class Entry12 implements Serializable{
private EntryInternal pair= new EntryInternal();
private static final long serialVersionUID= 12L;
**这也是必要的,否则写 putFields时会抛出异常.
* This field will be used by{@link#writeObject(ObjectOutputStream)},
* if this field is missing, follwing exception will be threw when invoke
*{@link java.io.ObjectOutputStream.PutField#put(String,)}:
* an exception‘java.lang.IllegalArgumentException: No such object field’ will be threw.
private static final ObjectStreamField[] serialPersistentFields= new ObjectStreamField[]{
new ObjectStreamField("name", String.class),//
new ObjectStreamField("email", String.class),//
/*我们在这里不是直接写出字段,而把要写出的字段包装起来,
我们按需交换字段,而不是直接读写pair这个字段.
private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException{
ObjectInputStream.GetField getFields= input.readFields();
/*请注意:使用 Serializable进行交换时不使用构造方法,所以这时 pair还未初始化.*/
pair.name=(String) getFields.get("name", null);
pair.email=(String) getFields.get("email", null);
private void writeObject(ObjectOutputStream output) throws IOException{
ObjectOutputStream.PutField putFields= output.putFields();
putFields.put("name", pair== null? null: pair.name);
putFields.put("email", pair== null? null: pair.email);
三、怎样做才能让Java 序列化机制 更安全
1、Java序列化 serialization主要职责就是将一个对象的状态转化为一个字节序列,以方便对象的持久化或网络传输。反序列化的过程正好相反。开发人员所要做的只是实现Serializable接口,然后调用ObjectOutputStream/ObjectInputStream的WriteObject/ReadObject方法即可,其他的工作 JVM会自动帮你做了。
2、那通过实现Serializable接口所获取的序列化能力是否有安全隐患?由于这些字节序列已经脱离了Java的安全体系存在于磁盘或网络上,我们能否对序列化后的字节序列进行查看和修改,甚至于注入恶意病毒呢? Java反序列化机制是否又会对建立的对象进行验证以确保它的安全性、准确性呢?如果你想到这些问题,那恐怕答案会让你失望了。Java序列化后的字节序列基本都是明文存在的,而且字节序列的组成有很明确的文档进行说明,你可以试着用一些十六进制的文本编辑工具,如Hexeditor查看一下对象序列化后的内容,你都能看到很多私有变量的实际赋值。关于字节序列的说明,可参考对象序列化流协议,这里就不多说了。这篇文章的重点是说一些Java提供的安全机制,通过这些机制,我们能够提升序列化/反序列化的安全指数。