Java的Externalizable接口

在理解Externalizable接口之前,你需要先理解什么是序列化。有关序列化可以读下 这篇文章多了解一些。 Java提供了序列化的机制来把Java对象里持久化成一个有序的字节序列,这里面包括对象的数据及其类型,还有对象本身的类型信息。

Externalizable:
就如名字所说的,这个接口是用来将对象序列化具体化的。如果你想定制自己的序列化机制 的话,它就派上用场了。它通过你自己编码的方式来完成对象的编解码。Externalizable接口继承了Serializable接口。如果你实现了这个接口你得重写下面的方法。

@Override
public void readExternal(ObjectInput arg0) throws IOException,

        ClassNotFoundException {

}

@Override
public void writeExternal(ObjectOutput arg0) throws IOException {

}

现在我们看下序列化是怎么进行的: 发送方: JVM检查类是否实现了externalizable接口。如果实现了则使用writeExternal()方法来进行序列化。如果它没实现externalizable而实现了Serializable接口,就用ObjectOutputStream来进行对象的序列化。 接收方: 当对象被反序列化并且它实现了externalizable接口的话,就会用默认构造方法新建一个实例,然后调用它的readExternal方法。如果没有实现externalizable而实现了Serializable,就用ObjectOutputStream来进行对象的反序列化。 我们还是从Java的序列化中用到过的那个例子讲起。 在src->org.arpit.javapostsforlearning中新建一个Employee.java

package org.arpit.javapostsforlearning;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class Employee implements Externalizable{

int employeeId;
String employeeName;
String department;
String nationality;

public Employee()
{

}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}

public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
employeeId=in.readInt();
employeeName=(String) in.readObject();

}
@Override
public void writeExternal(ObjectOutput out) throws IOException {

out.writeInt(employeeId);
out.writeObject(employeeName);
}
}
如果实现了externalizable就必须有一个无参的构造方法。 在org.arpit.javapostsforlearning中新建一个ExternalizableMain.java。

package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ExternalizableMain {
/**

  • @author Arpit Mandliya
    */
    public static void main(String[] args) {

Employee emp = new Employee();
emp.setEmployeeId(101);
emp.setEmployeeName(“Arpit”);
emp.setDepartment(“CS”);

//Serialize
try
{
FileOutputStream fileOut = new FileOutputStream(“employee.ser”);
ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
outStream.writeObject(emp);
outStream.close();
fileOut.close();
}catch(IOException i)
{
i.printStackTrace();
}

//Deserialize
emp = null;
try
{
FileInputStream fileIn =new FileInputStream(“employee.ser”);
ObjectInputStream in = new ObjectInputStream(fileIn);
emp = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println(“Employee class not found”);
c.printStackTrace();
return;
}
System.out.println(“Deserialized Employee…”);
System.out.println("Emp id: " + emp.getEmployeeId());
System.out.println("Name: " + emp.getEmployeeName());

}
}
运行:当你运行ExternalizableMain.java,你会得到这样的输出结果:

Deserialized Employee…
2Emp id: 101
3Name: Arpit
既然有了serializable,为什么还需要externalizable! 当你用serialize进行序列化时,除了所有字段,属于这个对象MAP的和成员变量能接触到的所有对象都会被序列化。比如: 如果你Employee有个父类是person,那么它会序列化所有的父类直到Object类。 同样的如果Employee有个address类型的成员变量,那么它会把整个address的整个对象集合也序列化进去。 如果你想序列化的只有employeeId和employeeName的话,你会希望增加这么多额外开销吗? 当你用serializable的话JVM会使用反射来进行序列化,这样会很慢。 当使用serializable时,类的描述信息也会存储到流里,包括父类的描述信息,和类关联的成员变量的信息。这也是一个性能问题。

外部序列化里的继承
我们现在来看下继承是怎么影响到外部序列化的。这里会有几种 情况比如 父类有没有实现过externalizable接口。如果没有你应该如何 处理,使得它能正常工作。我们来看个例子。 我们创建一个Employee的父类叫做Person。

场景1:如果父类没有实现externalizable: 如果父类没有实现externalizable,那么你得在实现externalizable的子类里序列化父类的字段。

package org.arpit.javapostsforlearning;
public class Person {

String name=“default”;
String nationality;

public Person()
{
System.out.println(“Person:Constructor”);
}

public Person(String name, String nationality) {
super();
this.name = name;
this.nationality = nationality;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getNationality() {
return nationality;
}

public void setNationality(String nationality) {
this.nationality = nationality;
}

}
在org.arpit.javapostsforlearning中创建Employee。

package org.arpit.javapostsforlearning;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class Employee extends Person implements Externalizable{

int employeeId;
String department;

public Employee()
{

}
public Employee(int employeeId,String name,String department,String nationality)
{
super(name,nationality);
this.employeeId=employeeId;
this.department=department;
System.out.println(“Employee:Constructor”);
}

public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}

public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}

@Override
public void writeExternal(ObjectOutput out) throws IOException {

/since superclass does not implement externalizable, you need to serialize super class field in this class itself/
//superclass fields
out.writeObject(name);
out.writeObject(nationality);

// its own fields
out.writeInt(employeeId);
out.writeObject(department);
}

@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
/since superclass does not implement externalizable, you need to deserialize super class field in this class itself/
//superclass fields
name=(String) in.readObject();
nationality=(String) in.readObject();

// its own fields
employeeId=in.readInt();
department=(String) in.readObject();

}
}
在org.arpit.javapostsforlearning新建ExternalizableMain。

package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ExternalizableMain {

/**

  • @author Arpit Mandliya
    */
    public static void main(String[] args) {

//Serialize
Employee emp = new Employee(101,“Arpit”,“CS”,“Indian”);
System.out.println(“Before serializing”);
System.out.println("Emp id: " + emp.getEmployeeId());
System.out.println("Name: " + emp.getName());
System.out.println(“Department: " + emp.getDepartment());
System.out.println(“Nationality: " + emp.getNationality());
System.out.println(”************”);
System.out.println(“Serializing”);
try
{
FileOutputStream fileOut = new FileOutputStream(“employee.ser”);
ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
outStream.writeObject(emp);
outStream.close();
fileOut.close();
}catch(IOException i)
{
i.printStackTrace();
}

//Deserialize
System.out.println("************");
System.out.println(“Deserializing”);
emp = null;
try
{
FileInputStream fileIn =new FileInputStream(“employee.ser”);
ObjectInputStream in = new ObjectInputStream(fileIn);
emp = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println(“Employee class not found”);
c.printStackTrace();
return;
}
System.out.println(“After serializing”);
System.out.println("Emp id: " + emp.getEmployeeId());
System.out.println("Name: " + emp.getName());
System.out.println("Department: " + emp.getDepartment());
System.out.println("Nationality: " + emp.getNationality());
}
}
运行后结果如下:

Employee:Constructor
Before serializing
Emp id: 101
Name: Arpit
Department: CS
Nationality: Indian


Serializing


Deserializing
Person:Constructor
After serializing
Emp id: 101
Name: Arpit
Department: CS
Nationality: Indian
场景二:如果父类实现了Externalizable
如果父类实现了Externalizable,它也有相应的readExternal和writeExternal方法,它会用这些方法序列化自己的字段。 Person.java

package org.arpit.javapostsforlearning;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class Person implements Externalizable{

String name=“default”;
String nationality;

public Person()
{
System.out.println(“Person:Constructor”);
}

public Person(String name, String nationality) {
super();
this.name = name;
this.nationality = nationality;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getNationality() {
return nationality;
}

public void setNationality(String nationality) {
this.nationality = nationality;
}

@Override
public void writeExternal(ObjectOutput out) throws IOException {

out.writeObject(name);
out.writeObject(nationality);
}

@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
name=(String) in.readObject();
nationality=(String) in.readObject();

}

}
Employee.java:

package org.arpit.javapostsforlearning;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class Employee extends Person implements Externalizable{

int employeeId;
String department;

public Employee()
{

}
public Employee(int employeeId,String name,String department,String nationality)
{
super(name,nationality);
this.employeeId=employeeId;
this.department=department;
System.out.println(“Employee:Constructor”);
}

public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}

public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}

@Override
public void writeExternal(ObjectOutput out) throws IOException {

super.writeExternal(out);
out.writeInt(employeeId);
out.writeObject(department);
}

@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {

super.readExternal(in);
employeeId=in.readInt();
department=(String) in.readObject();

}
}
ExternalizableMain.java:

package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ExternalizableMain {

/**

  • @author Arpit Mandliya
    */
    public static void main(String[] args) {

//Serialize
Employee emp = new Employee(101,“Arpit”,“CS”,“Indian”);
System.out.println(“Before serializing”);
System.out.println("Emp id: " + emp.getEmployeeId());
System.out.println("Name: " + emp.getName());
System.out.println(“Department: " + emp.getDepartment());
System.out.println(“Nationality: " + emp.getNationality());
System.out.println(”************”);
System.out.println(“Serializing”);
try
{
FileOutputStream fileOut = new FileOutputStream(“employee.ser”);
ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
outStream.writeObject(emp);
outStream.close();
fileOut.close();
}catch(IOException i)
{
i.printStackTrace();
}

//Deserialize
System.out.println("************");
System.out.println(“Deserializing”);
emp = null;
try
{
FileInputStream fileIn =new FileInputStream(“employee.ser”);
ObjectInputStream in = new ObjectInputStream(fileIn);
emp = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println(“Employee class not found”);
c.printStackTrace();
return;
}
System.out.println(“After serializing”);
System.out.println("Emp id: " + emp.getEmployeeId());
System.out.println("Name: " + emp.getName());
System.out.println("Department: " + emp.getDepartment());
System.out.println("Nationality: " + emp.getNationality());
}
}
运行的结果:

Employee:Constructor
Before serializing
Emp id: 101
Name: Arpit
Department: CS
Nationality: Indian


Serializing


Deserializing
Person:Constructor
After serializing
Emp id: 101
Name: Arpit
Department: CS
Nationality: Indian
在这个例子中,由于Person类用自己的writeExternal和readExternal方法存储和恢复自己的字段,不用再子类中序列化父类的字段。不过如果你仔细观察下Employee 的writeExternal和readExternal方法,你会发现还是先调了下super.xxxx方法,这样说明实现externalizable的对象还得和父类协作才能序列化对象的状态。

Externalizable的缺点:
如果你修改了类的定义,你得对应的修改writeExternal和readExternal方法。 就如示例中如示,子类对象必须 和父类进行协作才能正确存储和恢复自己的状态。

原创文章转载请注明出处:Java的Externalizable接口

英文原文链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值