Java 基础面试300题 (291-313)

96 阅读6分钟

Java 基础面试300题 (291-313)

291 . Externalizable接口和Serializable 接口有什么区别?

Serializable 接口是一个标记接口,没有定义任何方法,不必实现。Externalizable接口定义了readExternal()writeExternal()方法,必须实现这些方法。

当实现Serializable 接口时,JVM会和效率低下文件流打交通。 如果不确定如何高效执行IO流,最好使用Serializable 接口实现序列化 。如果能够高效地执行特定于应用程序的IO流,则应考虑通过实现Externalizable接口来实现序列化。

当对象的所有或大部分属性必须序列化时,使用Serializable 接口并根据需要使用瞬态变量实现序列化将更有效率。但是,如果仅仅是序列化一个具有很多属性的大型Java对象的某些动态属性 ,实现Externalizable接口是一种更好的序列化方式,因为可以在其重写方法中指定特定的序列化的内容。

292.什么是serialVersionUID

serialVersionUID 是可序列化类的唯一标识符,用来确保序列化和反序列化对象引用的是同一类版本。如果未在程序中定义,Java编译器会创建一个唯一的serialVersionUID。最好为每个可序列化的类都定义一个serialVersionUID,否则JVM在版本更改时将无法识别该类。每次更改可序列化类的属性时,如果用户没有定义,JVM都会创建一个新的serialVersionUID 。因此,最佳实践是为Java中的所有可序列化类都定义serialVersionUID

293. 列举一些类似对象序列化的技术?

Java使用对象序列化将数据永久存储在系统存储中。同样也可以使用其他方法,如数据库、XML和JSON 。使用数据库存储对象是一种非常常见的方法。可以使用ORM或对象关系映射将对象存储到数据库,然后从数据库检索。许多WebService 普遍使用基于XML的数据存储和传输, 这种方式是通过互联网传输数据的最流行方式。JSON数据传输是一种相对较新的使用很广泛的格式。JSON的实现非常简单,它基于Javascript技术,它已经集成到大多数网络浏览器中。

294.Java对象如何在JVM 的生命周期之外存在?

对象序列化允许Java对象生存超过JVM的生命周期。

295. 如何序列化一个集合, 必须让所有成员都可序列化吗?

集合或数组的所有成员都必须可序列化才能序列化。

296.如何从对象的序列化状态中排除某些变量?

要从序列化过程中排除变量,应该用transient关键字标记这些变量 。如下示例:

transient private String firsName

296 . 如果一个类实现了Serializable接口 ,但它包括一个不可序列化的对象,是否可以对这个类序列化?

对这个类的序列化将失败,运行时会抛出 java.io.NotSerializableException异常 。

297. 反序列化完成后,瞬态变量是什么值?

瞬态变量在反序列化完成后会获得默认值。

298: 通过实现Serializable接口来实现类的序列化,需要实现哪些方法?

不需要实现任何方法。 Serializable接口是一个标记接口,没有定义任何方法,因此实现它的类不需要实现任何方法。

299. 使用serialVersionUID的目的是什么?

serialVersionUID为每个可序列化的类提供版本系统。在反序列化过程中,serialVersionUID用于检查从输入流读取的数据是否与当前类定义兼容。

300.serialVersionUID是一个静态字段, 它也需要序列化吗?

serialVersionUID是一个静态字段,也与其他数据一起序列化。在反序列化期间, 反序列化的serialVersionUID必须与当前类定义中声明的serialVersionUID匹配。

301. 如果反序列化对象的serialVersionUID与类定义中声明的不匹配,会发生什么?

这种情况下,反序列化会失败,抛出java.io.InvalidClassException异常。

302.如果一个可序列化类没有定义 serialVersionUID ,编译器如何处理?

Java编译器根据类中声明的字段自动增加一个serialVersionUID

303.在哪些场景中应该使用序列化?

比如,当需要通过网络发送对象时,对象首先需要序列化,然后才能够(作为数据)发送。

304. 出现NotSerializableException的原因是什么?

如果要序列化一个类,它必须实现Serializable接口。同样重要的是,该类中包含的所有对象也是可序列化的。如果任何一个包含的对象没有实现Serializable接口,则会抛出NotSerializableException

305.如何更改默认的序列化行为?

通过重写ObjectOutputStream对象的writeObject()ObjectInputStreamreadObject()方法可以控制复杂的对象序列化过程,可以提供额外的信息来序列化和反序列化对象。

306.如果想完全控制类的序列化过程,需要实现哪个接口?

如果想完全控制类的序列化过程,应实现 java.io.Externalizable接口。

307. 实现外部序列化时要重写哪些方法?

实现Externizable接口时,应重写该接口定义的两个方法readExternalwriteExternal

308. 考虑以下情况,Child类也是可序列化的吗?

public class Parent implements Serializable
public class Child extends Parent

子类从其对象层次结构中继承了Serializable接口 ,因此也是可序列化的。

309. 反序列化时,会调用对象的构造函数,是正确的吗?

反序列化意味着恢复序列化对象,而不是重建它。在反序列化过程中没有调用构造函数。

310. 考虑如下代码,Student类是可序列化的, 它有一个 String类型的name实例变量, 因为不是基础类型,序列化会失败吗?

public class Student implements Serializable {
private String name; 
...
}

java.lang.String本身是可序列化的,因此Student类是可以序列化的类。

311. 所有基础类型的包装类都是可序列化吗?

是的。所有基础数据类型的包装类都实现了可序列化接口。

312.假设有一个可序列化类,但其超类没有实现 Serializable 接口。超类定义了无参数构造函数和字符串参数构造函数。在反序列化时,超级类的哪个构造函数将被调用?

无参数构造函数将被调用, 实现Serializable的子类应该可以访问这个构造函数。

313. 考虑以下情况,有一个可序列化类,但没有定义serialVersionUID。现在将其序列化,然后在类中添加一个新的实例变量,并将其已序列化的实例反序列化。会发生什么?

由于serialVersionUID没有在类中定义,JVM会基于类中的字段信息自动生成。一旦在类中添加或删除实例变量,JVM会重新生成serialVersionUID 。在上述场景中,当前类中的serialVersionUID和序列化的实例中的serialVersionUID不一致,因为重新增加了实例变量,因此反序例化会失败,抛出java.io.InvalidClassException异常。