java 反序列化 构造函数_Java反序列化创建对象探析

通过反序列化生成对象的过程主要由以下几个步骤:

1、创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;

2、 通过对象输入流的readObject()方法读取对象。

其中正是readObject方法返回了一个对象,这个对象就是根据序列化生成的文件而创建的对象,所以反序列化如何创建对象关键就在于readObject方法的实现,那就来探析一下它的实现,它的源码如下:

public finalObject readObject()throwsIOException, ClassNotFoundException

{if(enableOverride) {returnreadObjectOverride();

}//if nested read, passHandle contains handle of enclosing object

int outerHandle =passHandle;try{

Object obj= readObject0(false);

handles.markDependency(outerHandle, passHandle);

ClassNotFoundException ex=handles.lookupException(passHandle);if (ex != null) {throwex;

}if (depth == 0) {

vlist.doCallbacks();

}returnobj;

}finally{

passHandle=outerHandle;if (closed && depth == 0) {

clear();

}

}

}

这个方法会从对象输入流中读取一个对象,其中还包括这个对象的类名、类的签名、类的非静态非瞬时属性值、以及它的所有超类。

该对象所引用的对象是传递式读取的,所以readObject方法可以重建对象的完整等效图,也就复刻一个和原来被序列化对象一样的对象。

由于该方法返回值就是一个Object类型,所以我们重点看实际返回的obj这个对象是怎么创建,可以看出它是通过另一个方法创建,继续查看readObject0方法的源码:

private Object readObject0(boolean unshared) throwsIOException {boolean oldMode =bin.getBlockDataMode();if(oldMode) {int remain =bin.currentBlockRemaining();if (remain > 0) {throw newOptionalDataException(remain);

}else if(defaultDataEnd) {/** Fix for 4360508: stream is currently at the end of a field

* value block written via default serialization; since there

* is no terminating TC_ENDBLOCKDATA tag, simulate

* end-of-custom-data behavior explicitly.*/

throw new OptionalDataException(true);

}

bin.setBlockDataMode(false);

}bytetc;while ((tc = bin.peekByte()) ==TC_RESET) {

bin.readByte();

handleReset();

}

depth++;

totalObjectRefs++;try{switch(tc) {caseTC_NULL:returnreadNull();caseTC_REFERENCE:returnreadHandle(unshared);caseTC_CLASS:returnreadClass(unshared);caseTC_CLASSDESC:caseTC_PROXYCLASSDESC:returnreadClassDesc(unshared);caseTC_STRING:caseTC_LONGSTRING:returncheckResolve(readString(unshared));caseTC_ARRAY:returncheckResolve(readArray(unshared));caseTC_ENUM:returncheckResolve(readEnum(unshared));caseTC_OBJECT:returncheckResolve(readOrdinaryObject(unshared));caseTC_EXCEPTION:

IOException ex=readFatalException();throw new WriteAbortedException("writing aborted", ex);caseTC_BLOCKDATA:caseTC_BLOCKDATALONG:if(oldMode) {

bin.setBlockDataMode(true);

bin.peek();//force header read

throw newOptionalDataException(

bin.currentBlockRemaining());

}else{throw newStreamCorruptedException("unexpected block data");

}caseTC_ENDBLOCKDATA:if(oldMode) {throw new OptionalDataException(true);

}else{throw newStreamCorruptedException("unexpected end of block data");

}default:throw newStreamCorruptedException(

String.format("invalid type code: %02X", tc));

}

}finally{

depth--;

bin.setBlockDataMode(oldMode);

}

}

这个方法是readObject方法的底层实现,由于它的返回值类型也是对象类型,所以我们重点看返回的实际对象是哪个,通过观察和debug发现,开关语句执行时下面这行代码,checkResolve方法接收的参数类型是对象类型,返回值类型也是对象类型。

caseTC_OBJECT:return checkResolve(readOrdinaryObject(unshared));

那我们来查看readOrdinaryObject对象:

private Object readOrdinaryObject(booleanunshared)throwsIOException

{if (bin.readByte() !=TC_OBJECT) {throw newInternalError();

}

ObjectStreamClass desc= readClassDesc(false);

desc.checkDeserialize();

Class> cl =desc.forClass();if (cl == String.class || cl == Class.class

|| cl == ObjectStreamClass.class) {throw new InvalidClassException("invalid class descriptor");

}

Object obj;try{

obj= desc.isInstantiable() ? desc.newInstance() : null;

}catch(Exception ex) {throw (IOException) newInvalidClassException(

desc.forClass().getName(),"unable to create instance").initCause(ex);

}

passHandle= handles.assign(unshared ?unsharedMarker : obj);

ClassNotFoundException resolveEx=desc.getResolveException();if (resolveEx != null) {

handles.markException(passHandle, resolveEx);

}if(desc.isExternalizable()) {

readExternalData((Externalizable) obj, desc);

}else{

readSerialData(obj, desc);

}

handles.finish(passHandle);if (obj != null &&handles.lookupException(passHandle)== null &&desc.hasReadResolveMethod())

{

Object rep=desc.invokeReadResolve(obj);if (unshared &&rep.getClass().isArray()) {

rep=cloneArray(rep);

}if (rep !=obj) {//Filter the replacement object

if (rep != null) {if(rep.getClass().isArray()) {

filterCheck(rep.getClass(), Array.getLength(rep));

}else{

filterCheck(rep.getClass(),-1);

}

}

handles.setObject(passHandle, obj=rep);

}

}returnobj;

}

此处我们重点看的还应该是产生实际返回值的地方,也就是这块:

obj = desc.isInstantiable() ? desc.newInstance() : null;

desc.newInstance()方法原理是利用反射创建了一个对象,本质是调用非序列化父类的无参构造器。

如果该类是Externalizable类型的,则调用它自身的访问权限是public无参构造方法。

如果该类是Serializable类型的,则调用该类的第一个非Serializable类型的父类的无参构造方法。

所以这就是为什么通过反序列化创建对象的时候,并不会执行被序列化对象的构造方法。

对于实现Serializable接口的类,并不要求该类具有一个无参的构造方法, 因为在反序列化的过程中实际上是去其继承树上找到一个没有实现Serializable接口的父类(最终会找到Object),然后构造该类的对象,再逐层往下的去设置各个可以反序列化的属性(也就是没有被transient修饰的非静态属性)。

我们通过一个具体的案例就可以看出来:

importjava.io.Serializable;public class Users implementsSerializable {privateString username;private intage;privateString sex;publicUsers() {

System.out.println("调用了构造方法");

}

/*

get和set方法

*/

…………}

创建一个测试类:

import java.io.*;public classTestUsers {public static voidmain(String[] args) {try{

System.out.println("开始序列化。。。。。");

Users users= newUsers();

users.setUsername("fym");

users.setAge(23);

users.setSex("nan");

FileOutputStream fs= new FileOutputStream("users.ser");

ObjectOutputStream os= newObjectOutputStream(fs);

os.writeObject(users);

os.close();

fs.close();

System.out.println("开始反序列化。。。。。");

FileInputStream fileInputStream= new FileInputStream("users.ser");

ObjectInputStream objectInputStream= newObjectInputStream(fileInputStream);

Users o=(Users)objectInputStream.readObject();

System.out.println(o);

fileInputStream.close();

objectInputStream.close();

}catch(Exception e) {

e.printStackTrace();

}

}

}

输出结果:

开始序列化。。。。。

调用了构造方法

开始反序列化。。。。。

Users{username='fym', age=23, sex='nan'}

我们将其改造一下,让User类继承一个没有序列化的父类:

classParentsUser{publicParentsUser(){

System.out.println("调用了父类构造方法");

}

}public class Users extends ParentsUser implementsSerializable {

……

}

再一次执行上面的测试类,输出结果如下:

开始序列化。。。。。

调用了父类构造方法

调用了构造方法

开始反序列化。。。。。

调用了父类构造方法

Users{username='fym', age=23, sex='nan'}

发现,反序列化创建对象的时候,果然调用了离User类最近的没有序列化的超类的无参构造函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值