Externalizable简介
#这里可以看出 它也是直接继承自Serializable,实现它的类必须复写两个方法:
//#1.writeExternal
//#2.readExternal
public interface Externalizable extends java.io.Serializable {
/**
* The object implements the writeExternal method to save its contents
* by calling the methods of DataOutput for its primitive values or
* calling the writeObject method of ObjectOutput for objects, strings,
* and arrays.
*
* @serialData Overriding methods should use this tag to describe
* the data layout of this Externalizable object.
* List the sequence of element types and, if possible,
* relate the element to a public/protected field and/or
* method of this Externalizable class.
*
* @param out the stream to write the object to
* @exception IOException Includes any I/O exceptions that may occur
*/
void writeExternal(ObjectOutput out) throws IOException;
/**
* The object implements the readExternal method to restore its
* contents by calling the methods of DataInput for primitive
* types and readObject for objects, strings and arrays. The
* readExternal method must read the values in the same sequence
* and with the same types as were written by writeExternal.
*
* @param in the stream to read data from in order to restore the object
* @exception IOException if I/O errors occur
* @exception ClassNotFoundException If the class for an object being
* restored cannot be found.
*/
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
2.实现Externalizable 的类,源文件如下
package com.serializer.demo.nativenal.domain;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
public class Department implements Externalizable {
private static final long serialVersionUID = -509314035422L;
private String departmentId;
private String departmentName;
private String password;
// public void writeExternal(ObjectOutput out) throws IOException {
// System.out.println("I am going to write ");
// out.writeObject(departmentId);
// out.writeObject(departmentName);
//
// }
//
// public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// System.out.println("I am going to read");
// //注意这里顺序不能反了,怎么顺序写的,怎么顺序读
// departmentId= (String) in.readObject();
// departmentName= (String) in.readObject();
password= (String) in.readObject(); //这里不能读会报错的:
//
//
// } // java.io.OptionalDataException
public String getDepartmentId() {
return departmentId;
}
public void setDepartmentId(String departmentId) {
this.departmentId = departmentId;
}
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("I am going to write ");
//如果以字节的方式写入时,由于是连续的,这里必须要写入字节长度,才能保证反序列化时,知道从哪个地方切断
byte[] bytes = departmentId.getBytes();
out.writeInt(bytes.length);
out.write(bytes);
bytes = departmentName.getBytes();
out.writeInt(bytes.length);
out.write(bytes);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("I am going to read");
//这里不能用readObject来读,会报错,因此
// departmentId= (String) in.readObject();
// departmentName= (String) in.readObject();
//这里与上述写的顺序和方式保持一致
int available = in.available();
System.out.println("available:" + available);
int len1 = in.readInt();
byte[] bytes = new byte[len1];
in.read(bytes,0, len1);
departmentId = new String(bytes);
int len2 = in.readInt();
bytes = new byte[len2];
in.read(bytes,0, len2);
departmentName = new String(bytes);
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
从上面可以看出,Department 类实现Externalizable接口,因此必须实现两个方法:
1.writeExternal
2.readExternal
在进行数据序列化时,给用户提供的高度的自由,但是必须有所约束:
1.序列化的顺序和方式必须与反序列化的保持一致
序列化和反序列化时,一定会各自走这两个方法吗?
序列化时
//#step1 判断对象是否实现了Serializable接口,如果没实现,抛出异常;否则走序列化流程
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
............
// remaining cases
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
writeEnum((Enum) obj, desc, unshared);
} else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);//会走到这里来
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
.............
}
//#step2 写入序列化标志TC_OBJECT代表是一个新的实例对象;写入类描述符
private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
if (extendedDebugInfo) {
debugInfoStack.push(
(depth == 1 ? "root " : "") + "object (class \"" +
obj.getClass().getName() + "\", " + obj.toString() + ")");
}
try {
desc.checkSerialize();
bout.writeByte(TC_OBJECT);//写入TC_OBJECT代表是一个新的对象
writeClassDesc(desc, false); //写入文件描述符
handles.assign(unshared ? null : obj);
if (desc.isExternalizable() && !desc.isProxy()) {//会走到这里来
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
//#step3 调用对象自己序列化方法,完成序列化
private void writeExternalData(Externalizable obj) throws IOException {
PutFieldImpl oldPut = curPut;
curPut = null;
if (extendedDebugInfo) {
debugInfoStack.push("writeExternal data");
}
SerialCallbackContext oldContext = curContext;
try {
curContext = null;
if (protocol == PROTOCOL_VERSION_1) {
obj.writeExternal(this);
} else {
bout.setBlockDataMode(true);
obj.writeExternal(this); // 这里开始写入数据,调用obj的writeExternal
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
}
} finally {
curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
curPut = oldPut;
}
反序列化时
public final Object readObject()
throws IOException, ClassNotFoundException
{
................
Object obj = readObject0(false);//走到这里
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
..................
}
/**
* Underlying readObject implementation.
*/
private Object readObject0(boolean unshared) throws IOException {
.......
switch (tc) {
case TC_NULL:
return readNull();
case TC_REFERENCE:
return readHandle(unshared);
....
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));//会走到这里
.....
default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
...
}
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
.....
if (desc.isExternalizable()) {//这里由于是实现了Externalizable接口,所以会走到这里
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc); //实现Serializable接口,会走这里
}
handles.finish(passHandle);
.....
return obj;
}
private void readExternalData(Externalizable obj, ObjectStreamClass desc)
throws IOException
{
......
if (obj != null) {
try {
obj.readExternal(this);//这里代码会走到这里来
} catch (ClassNotFoundException ex) {
/*
* In most cases, the handle table has already propagated
* a CNFException to passHandle at this point; this mark
* call is included to address cases where the readExternal
* method has cons'ed and thrown a new CNFException of its
* own.
*/
handles.markException(passHandle, ex);
}
....
}
从上面可知,对象实现了Externalizable,时,虽然间接的实现了Serializable接口,但,Externalizable的优先级要大于Serializable