📅  最后修改于: 2020-09-27 08:18:17             🧑  作者: Mango
Java中的序列化是一种将对象状态写入字节流的机制。它主要用于Hibernate,RMI,JPA,EJB和JMS技术。
序列化的反向操作称为反序列化,其中字节流被转换为对象。序列化和反序列化过程与平台无关,这意味着您可以序列化平台中的对象并在不同平台中反序列化。
对于序列化对象,我们调用writeObject()方法ObjectOutputStream,对于反序列化,我们调用ObjectInputStream类的readObject()方法。
我们必须实现Serializable接口才能序列化对象。
它主要用于在网络上传播对象的状态(称为封送处理)。
可序列化是标记接口(没有数据成员和方法)。它用于“标记” Java类,以便这些类的对象可以具有一定的功能。可克隆和远程也是标记器接口。
它必须由要保留其对象的类实现。
默认情况下,String类和所有包装器类都实现java.io.Serializable接口。
让我们看下面的例子:
import java.io.Serializable;
public class Student implements Serializable{
int id;
String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
在上面的示例中,Student类实现了Serializable接口。现在可以将其对象转换为流。
ObjectOutputStream类用于将原始数据类型和Java对象写入OutputStream。只有支持java.io.Serializable接口的对象才能写入流。
1) public ObjectOutputStream(OutputStream out) throws IOException {} | creates an ObjectOutputStream that writes to the specified OutputStream. |
Method | Description |
---|---|
1) public final void writeObject(Object obj) throws IOException {} | writes the specified object to the ObjectOutputStream. |
2) public void flush() throws IOException {} | flushes the current output stream. |
3) public void close() throws IOException {} | closes the current output stream. |
ObjectInputStream反序列化使用ObjectOutputStream编写的对象和原始数据。
1) public ObjectInputStream(InputStream in) throws IOException {} | creates an ObjectInputStream that reads from the specified InputStream. |
Method | Description |
---|---|
1) public final Object readObject() throws IOException, ClassNotFoundException{} | reads an object from the input stream. |
2) public void close() throws IOException {} | closes ObjectInputStream. |
在此示例中,我们将序列化Student类的对象。 ObjectOutputStream类的writeObject()方法提供了序列化对象的功能。我们将对象的状态保存在名为f.txt的文件中。
import java.io.*;
class Persist{
public static void main(String args[]){
try{
//Creating the object
Student s1 =new Student(211,"ravi");
//Creating stream and writing the object
FileOutputStream fout=new FileOutputStream("f.txt");
ObjectOutputStream out=new ObjectOutputStream(fout);
out.writeObject(s1);
out.flush();
//closing the stream
out.close();
System.out.println("success");
}catch(Exception e){System.out.println(e);}
}
}
success
反序列化是从序列化状态重建对象的过程。这是序列化的反向操作。让我们看一个示例,该示例从反序列化的对象读取数据。
import java.io.*;
class Depersist{
public static void main(String args[]){
try{
//Creating stream to read the object
ObjectInputStream in=new ObjectInputStream(new FileInputStream("f.txt"));
Student s=(Student)in.readObject();
//printing the data of the serialized object
System.out.println(s.id+" "+s.name);
//closing the stream
in.close();
}catch(Exception e){System.out.println(e);}
}
}
211 ravi
如果一个类实现可序列化,则其所有子类也将可序列化。让我们看下面的例子:
import java.io.Serializable;
class Person implements Serializable{
int id;
String name;
Person(int id, String name) {
this.id = id;
this.name = name;
}
}
class Student extends Person{
String course;
int fee;
public Student(int id, String name, String course, int fee) {
super(id,name);
this.course=course;
this.fee=fee;
}
}
现在,您可以序列化扩展扩展可序列化的Person类的Student类对象。父类属性是继承给子类的,因此,如果父类是可序列化的,则子类也可以。
如果一个类具有对另一个类的引用,则所有引用都必须是可序列化的,否则将不执行序列化过程。在这种情况下,NotSerializableException在运行时引发。
class Address{
String addressLine,city,state;
public Address(String addressLine, String city, String state) {
this.addressLine=addressLine;
this.city=city;
this.state=state;
}
}
import java.io.Serializable;
public class Student implements Serializable{
int id;
String name;
Address address;//HAS-A
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
由于地址不可序列化,因此无法序列化Student类的实例。
注意:对象中的所有对象必须可序列化。
如果类中有任何静态数据成员 ,则不会被序列化,因为static是类而非对象的一部分。
class Employee implements Serializable{
int id;
String name;
static String company="SSS IT Pvt Ltd";//it won't be serialized
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
规则:对于数组或集合,数组或集合的所有对象必须可序列化。如果任何对象不可序列化,则序列化将失败。
Externalizable接口提供了以压缩格式将对象的状态写入字节流的便利。它不是标记界面。
Externalizable接口提供两种方法:
如果您不想序列化类的任何数据成员 ,则可以将其标记为瞬态。
class Employee implements Serializable{
transient int id;
String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
现在,将不会序列化id,因此在序列化后反序列化对象时,将不会获得id的值。它将始终返回默认值。在这种情况下,它将返回0,因为id的数据类型是整数。
请访问下一页以获取更多详细信息。
运行时的序列化过程将一个ID与每个Serializable类相关联,该类称为SerialVersionUID。它用于验证序列化对象的发送者和接收者。发送者和接收者必须相同。要进行验证,请使用SerialVersionUID。发送方和接收方必须具有相同的SerialVersionUID,否则,在反序列化对象时将抛出InvalidClassException。我们还可以在Serializable类中声明我们自己的SerialVersionUID。为此,您需要创建一个字段SerialVersionUID并为其分配一个值。它必须是带有static和final的long类型。建议在类中显式声明serialVersionUID字段,并将其设置为私有。例如:
private static final long serialVersionUID=1L;
现在,Serializable类将如下所示:
import java.io.Serializable;
class Employee implements Serializable{
private static final long serialVersionUID=1L;
int id;
String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}