不少商业项目用到数据库、内存映射文件和普通文件来完成项目中的序列化处理的需求,可是这些方法不多会依靠于Java序列化。本文也不是用来解释序列化的,而是一块儿来看看面试中有关序列化的问题,这些问题你颇有可能不了解。“Java序列化指的是将对象转换程字节格式并将对象状态保存在文件中,一般是.ser扩展名的文件。而后能够经过.ser文件从新建立Java对象,这个过程为返序列化”java
Java序列化的API中提供了开发人员进行序列化对象的机制,经过Serializable和Externalizable接口。面试
一块儿看看这些问题:
1)Java中的Serializable接口和Externalizable接口有什么区别?算法
这个是面试中关于Java序列化问的最多的问题。个人回答是,Externalizable接口提供了两个方法writeExternal()和readExternal()。这两个方法给咱们提供了灵活处理Java序列化的方法,经过实现这个接口中的两个方法进行对象序列化能够替代Java中默认的序列化方法。正确的实现Externalizable接口能够大幅度的提升应用程序的性能。数据库
2)Serializable接口中有借个方法?若是没有方法的话,那么这么设计Serializable接口的目的是什么?编程
Serializable接口在java.lang包中,是Java序列化机制的核心组成部分。它里面没有包含任何方法,咱们称这样的接口为标识接口。若是你的类实现了Serializable接口,这意味着你的类被打上了“能够进行序列化”的标签,而且也给了编译器指示,可使用序列化机制对这个对象进行序列化处理。app
3)什么是serialVersionUID?若是你没有定义serialVersionUID意味着什么?ide
SerialVersionUID应该是你的类中的一个public static final类型的常量,若是你的类中没有定义的话,那么编译器将抛出警告。若是你的类中没有制定serialVersionUID,那么Java编译器会根据类的成员变量和必定的算法生成用来表达对象的serialVersionUID ,一般是用来表示类的哈希值(hash code)。结论是,若是你的类没有实现SerialVersionUID,那么若是你的类中若是加入或者改变成员变量,那么已经序列化的对象将没法反序列化。这是觉得,类的成员变量的改变意味这编译器生成的SerialVersionUID的值不一样。Java序列化过程是经过正确SerialVersionUID来对已经序列化的对象进行状态恢复。函数
4)当对象进行序列化的时候,若是你不但愿你的成员变量进行序列化,你怎么办?性能
这个问题也会这么问,如何使用暂态类型的成员变量?暂态和静态成员变量是否会被序列化等等。若是你不但愿你的对象中的成员变量的状态得以保存,你能够根据需求选择transient或者static类型的变量,这样的变量不参与Java序列化处理的过程。设计
5)若是一个类中的成员变量是其它符合类型的Java类,而这个类没有实现Serializable接口,那么当对象序列化的时候会怎样?
若是你的一个对象进行序列化,而这个对象中包含另一个引用类型的成员编程,而这个引用的类没有实现Serializable接口,那么当对象进行序列化的时候会抛出“NotSerializableException“的运行时异常。
6)若是一个类是可序列化的,而他的超类没有,那么当进行反序列化的时候,那些从超类继承的实例变量的值是什么?
Java中的序列化处理实例变量只会在全部实现了Serializable接口的继承支路上展开。因此当一个类进行反序列化处理的时候,超类没有实现Serializable接口,那么从超类继承的实例变量会经过为实现序列化接口的超类的构造函数进行初始化。
7) Can you Customize Serialization process or can you override default Serialization process in Java?
7)你可以自定义序列化处理的代码吗或者你能重载Java中默认的序列化方法吗?
答案是确定的,能够。咱们都知道能够经过ObjectOutputStream中的writeObject()方法写入序列化对象,经过ObjectInputStream中的readObject()读入反序列化的对象。这些都是Java虚拟机提供给你的两个方法。若是你在你的类中定义了这两个方法,那么JVM就会用你的方法代替原有默认的序列化机制的方法。你能够经过这样的方式类自定义序列化和反序列化的行为。须要注意的一点是,最好将这两个方法定义为private,以防止他们被继承、重写和重载。也只有JVM能够访问到你的类中全部的私有方法,你不用担忧方法私有不会被调用到,Java序列化过程会正常工做。
8)假设一个新的类的超类实现了Serializable接口,那么如何让这个新的子类不被序列化?
若是一个超类已经序列化了,那么没法经过是否实现什么接口的方式再避免序列化的过程了,可是也还有一种方式可使用。那就是须要你在你的类中从新实现writeObject()和readObject()方法,并在方法实现中经过抛出NotSerializableException。
9)在Java进行序列化和反序列化处理的时候,哪些方法被使用了?
这个是面试中常见的问题,主要用来考察你是否对readObject()、writeObject()、readExternal()和writeExternal()方法的使用熟悉。Java序列化是经过java.io.ObjectOutputStream这个类来完成的。这个类是一个过滤器流,这个类完成对底层字节流的包装来进行序列化处理。咱们经过ObjectOutputStream.writeObject(obj)进行序列化,经过ObjectInputStream.readObject()进行反序列化。对writeObject()方法的调用会触发Java中的序列化机制。readObject()方法用来将已经持久化的字节数据反向建立Java对象,该方法返回Object类型,须要强制转换成你须要的正确类型。
10) Suppose you have a class which you serialized it and stored in persistence and later modified that class to add a new field. What will happen if you deserialize the object already serialized?
10)假设你有一个类而且已经将这个类的某一个对象序列化存储了,那么若是你在这个类中加入了新的成员变量,那么在反序列化刚才那个已经存在的对象的时候会怎么样?
这个取决于这个类是否有serialVersionUID成员。经过上面的,咱们已经知道若是你的类没有提供serialVersionUID,那么编译器会自动生成,而这个serialVersionUID就是对象的hash code值。那么若是加入新的成员变量,从新生成的serialVersionUID将和以前的不一样,那么在进行反序列化的时候就会产生java.io.InvalidClassException的异常。这就是为何要建议为你的代码加入serialVersionUID的缘由所在了。