将对象的状态写入文件的过程称为序列化,但严格来说,是将对象从Java支持的形式转换为文件支持的形式或网络支持的形式的过程。通过使用 fileOutputStream 和 objectOutputStream 类,我们可以实现序列化。
但是我们只能序列化可序列化的对象。当且仅当相应的类实现了 Serializable 接口时,才说对象是可序列化的。 Java.io 包中存在的可序列化接口,它不包含任何方法,因此它是一个标记接口。如果我们试图序列化一个不可序列化的对象,那么我们会得到运行时异常,提示 notSerializableException。
例子:
Java
// Java Program to illustrate Serializable
// Importing utility classes
// Importing input output classes
import java.io.*;
import java.util.*;
// Main Class
// Class implementing serializable interface
class serializableDemo implements Serializable {
// Member variables of this class
String name;
int age;
int jobId;
// Default constructor
public serializableDemo(String name, int age, int jobId)
{
// This keyword is used to refer
// current object instance
this.name = name;
this.age = age;
this.jobId = jobId;
}
// Method 2
// Main driver method
public static void main(String[] args) throws Exception
{
// Creating an object of class in main() method
serializableDemo t1
= new serializableDemo("Ram", 34, 2364);
// Serialization
// Saving of object in a file
FileOutputStream fos
= new FileOutputStream("abc1.ser");
ObjectOutputStream oos
= new ObjectOutputStream(fos);
// Method for serialization of object
oos.writeObject(t1);
System.out.println("Object has been serialized");
// Deserialization
// Reading the object from a file
FileInputStream fis
= new FileInputStream("abc1.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
// Method for deserialization of object
serializableDemo t2
= (serializableDemo)ois.readObject();
// Display message only
System.out.println("Object has been deserialized ");
// Print and display the name and age
// to illustrate Serializable
System.out.println("Name:" + t2.name + "\n"
+ "Age:" + t2.age + "\n"
+ t2.jobId);
}
}
Java
// Java Program to illustrate Externalizable
// Importing input output classes
import java.io.*;
// Importing utility classes
import java.util.*;
// Main Class
// Class implementing externalizable class
public class ExternalizableDemo implements Externalizable {
// Member variables of this class
String name;
int age;
int jobId;
// Constructors of this class
// Constructor 1
// No-argument constructor
public ExternalizableDemo()
{
// Display message
System.out.println(
"Public no-argument constructor");
}
// Constructor 2
// Default constructor
public ExternalizableDemo(String name, int age,
int jobId)
{
// This keyword refers to current object itself
this.name = name;
this.age = age;
this.jobId = jobId;
}
// Implementing write external method
public void writeExternal(ObjectOutput out)
throws IOException
{
// Writing name and age to file
out.writeObject(name);
out.writeInt(age);
}
// Implementing readExternal method
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
// Reading name from file
name = (String)in.readObject();
// Reading age from file
age = in.readInt();
}
// Main method
public static void main(String[] args) throws Exception
{
// Creating an object of type ExternalizableDemo
ExternalizableDemo t1
= new ExternalizableDemo("Ram", 35, 23675);
// Serialization of object
FileOutputStream fos
= new FileOutputStream("abc.ser");
ObjectOutputStream oos
= new ObjectOutputStream(fos);
oos.writeObject(t1);
// Deserlization
FileInputStream fis
= new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
ExternalizableDemo t2
= (ExternalizableDemo)ois.readObject();
// Display message
System.out.println("Name :"
+ " " + t2.name + " "
+ "Age :"
+ " " + t2.age);
}
}
输出:
Object has been serialized
Object has been deserialized
Name:Ram
Age:34
2364
可外化
在序列化中,一切都由 JVM 处理,程序员没有任何控制权。在序列化中,总是可以将整个对象解决到文件中,而无法保存可能会产生性能问题的部分对象。为了克服这个问题,我们应该去外化。
序列化的主要优点是一切都由程序员负责,JVM 没有任何控制权。根据我们的要求,我们可以保存整个对象或部分对象,从而提高系统的性能。要为任何强制Java对象提供可泛化能力,相应的类应该实现可泛化接口。
该接口定义了如下两个方法:
方法一
public void writeExternal( ObjectIOutput obj ) throws IOException
这个方法会在序列化的时候自动执行,这个方法内我们要写代码把需要的变量保存到文件中。
方法二
public void readExternal(ObjectInput in )throws IOException , ClassNotFoundException
这个方法会在反序列化的时候自动执行。在这个方法中,我们必须编写代码从文件中读取所需的变量并将其分配给当前对象。但严格来说,在反序列化时,JVM 将通过执行公共无参数构造函数来创建一个单独的新对象,然后在该对象上,JVM 将调用readExternal方法。
因此,每个 Externalizable 实现的类都应该强制包含一个公共的无参数构造函数,否则我们会得到运行时异常,说 InvalidClassException。
例子:
Java
// Java Program to illustrate Externalizable
// Importing input output classes
import java.io.*;
// Importing utility classes
import java.util.*;
// Main Class
// Class implementing externalizable class
public class ExternalizableDemo implements Externalizable {
// Member variables of this class
String name;
int age;
int jobId;
// Constructors of this class
// Constructor 1
// No-argument constructor
public ExternalizableDemo()
{
// Display message
System.out.println(
"Public no-argument constructor");
}
// Constructor 2
// Default constructor
public ExternalizableDemo(String name, int age,
int jobId)
{
// This keyword refers to current object itself
this.name = name;
this.age = age;
this.jobId = jobId;
}
// Implementing write external method
public void writeExternal(ObjectOutput out)
throws IOException
{
// Writing name and age to file
out.writeObject(name);
out.writeInt(age);
}
// Implementing readExternal method
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
// Reading name from file
name = (String)in.readObject();
// Reading age from file
age = in.readInt();
}
// Main method
public static void main(String[] args) throws Exception
{
// Creating an object of type ExternalizableDemo
ExternalizableDemo t1
= new ExternalizableDemo("Ram", 35, 23675);
// Serialization of object
FileOutputStream fos
= new FileOutputStream("abc.ser");
ObjectOutputStream oos
= new ObjectOutputStream(fos);
oos.writeObject(t1);
// Deserlization
FileInputStream fis
= new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
ExternalizableDemo t2
= (ExternalizableDemo)ois.readObject();
// Display message
System.out.println("Name :"
+ " " + t2.name + " "
+ "Age :"
+ " " + t2.age);
}
}
输出:
Public no-argument constructor
Name : Ram Age : 35
现在,我们已经完成了对它们的讨论,让我们总结一下表格中的所有差异,以便更好地理解。
Serializable | Externalizable |
---|---|
A serializable interface is used to implement serialization. | An externalizable interface used to implement Externalization |
Serializable is a marker interface i.e. it does not contain any method. | The externalizable interface is not a marker interface and thus it defines two methods writeExternal() and readExternal(). |
Serializable interface passes the responsibility of serialization to JVM and the programmer has no control over serialization, and it is a default algorithm. | The externalizable interface provides all serialization responsibilities to a programmer and hence JVM has no control over serialization. |
Serialization using a serializable interface has bad performance. | Serialization using an externalizable interface has better performance. |
Default serialization does not require any no-arg constructor. | A public no-arg constructor is required while using an Externalizable interface. |
It is hard to analyze and modify class structure because any change in structure may break serialization. | It is relatively easy to analyze and modify class structure because of complete control over serialization logic. |
Using a serializable interface we save the total object to a file, and it is not possible to save part of the object. | Base on our requirements we can save either the total object or part of the object. |
Transient keyword play an important role here. | Transient keyword won’t play any role. |