当前位置: 首页 > 后端技术 > Java

序列化与反序列化

时间:2023-04-01 17:48:30 Java

简述序列化是将对象转换成特定的数据格式,反序列化是序列化的返回操作。一般将序列化后的数据通过网络传输或保存到数据库中。Java的序列化操作在Java中,如果要序列化一个对象,需要实现Serializable接口。并且尽量标注属性serialVersionUID(后面测试会解释为什么要标注这个属性),IDEA一般会自动生成。例如,我有一个列classOrderimplementsSerializable{privatestaticfinallongserialVersionUID=1L;私人字符串订单号;私人整数金额;//Construct//gettersetter...@OverridepublicStringtoString(){//所有属性}}现在会使用java.io包下的ObjectOutputStream和FileOutputStream来演示如何将Order对象序列化成文件并保存publicclassSerializableTest{publicfinalstaticStringPATH="/tmp/order.txt";@Testpublicvoidtest_serializable()throwsIOException{Ordero=newOrder("abc",1299,newAddress("安徽"),newPerson("Savey"));try(FileOutputStreamfstream=newFileOutputStream(PATH);ObjectOutputStreamobjectOutputStream=newObjectOutputStream(fstream)){//接收一个对象并将该对象转换为字节流objectOutputStream.writeObject(o);//刷新到输出fstreamobjectOutputStream.flush();}}}此时Order对象已经序列化为/tmp/order.txt文件。上面提到Java的反序列化操作,Order已经被我们保存到了指定的文件中。这个时候如果我们要读取数据,就这样处理@Testpublicvoidtest_covert_object()throwsIOException,ClassNotFoundException{try(FileInputStreamfileInputStream=newFileInputStream(PATH);ObjectInputStreamobjectInputStream=newObjectInputStream(fileInputStream)){//从一个输入流中读取数据并转为对象,这里添加对Order的强转换Ordero=(Order)objectInputStream.readObject();System.out.println(o);此时我们使用了几个重要的对象来帮助我们进行排序和取消排序操作导入java.io.Serializable;serialVersionUID注意事项如果我序列化前的Order对象是这样的类OrderimplementsSerializable{privatestaticfinallongserialVersionUID=1L;}serialVersionUID在反序列化后发生变化classOrderimplementsSerializable{privatestaticfinallongserialVersionUID=2L;}Sosorry,会报错如下:java.io.InvalidClassException:Order;localclassincompatible:streamclassdescserialVersionUID=1,localclassserialVersionUID=2序列化对象中还有其他自定义对象。例如,我在Order类中添加了一个Person对象OrderimplementsSerializable{privatestaticfinallongserialVersionUID=1L;//其他属性privatePersonperson;//gettersetterconstructtoString}classPersonimplementsSerializable{privatestaticfinallongserialVersionUID=2L;}如果Person没有实现Serializable接口,也会报错,如下:java.io.NotSerializableException:Person但是可以修改Person声明privatetransientPersonperson的方式;使用关键字transient来修改你不想序列化的属性!你在ArrayList源代码中见过这个关键字吗???/***存储ArrayList元素的数组缓冲区。*ArrayList的容量就是这个数组缓冲区的长度。任何*elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA*的空ArrayList*将在添加第一个元素时扩展为DEFAULT_CAPACITY。*/transientObject[]elementData;//非sim私有plify嵌套类访问自定义序列化就好了,你也可以自定义你要序列化的内容,Java很优雅的给我们提供了两个重写序列化的方法privatevoidwriteObject(ObjectOutputStreamoos)privatevoidreadObject(ObjectInputStreamois)这两个方法分别为顾名思义,一写一读上面说了一个属性被keywritetransient修改了,但是我还是想序列化它~classOrderimplementsSerializable{//其他属性privatetransientPersonperson;privatevoidwriteObject(ObjectOutputStreamoos)抛出IOException{oos.defaultWriteObject();//自定义写入Person对象,即使你是瞬态修改的!!oos.writeObject(人);}privatevoidreadObject(ObjectInputStreamois)throwsClassNotFoundException,IOException{ois.defaultReadObject();//读取并转换为Person对象Personperson=(Person)ois.readObject();this.setPerson(人);}//gettersetterconstruct}上面代码演示了如果自定义序列化和反序列化,如果有多个属性自定义操作,请注意写的顺序和读的顺序一一对应,否则会有会失误!java.lang.ClassCastException:XXX无法转换为GitHub中的XXX代码