当前位置: 首页 > 图灵资讯 > java面试题> 金三银四精选java面试题-什么是 Java 的序列化,如何实现 Java 的序列化?

金三银四精选java面试题-什么是 Java 的序列化,如何实现 Java 的序列化?

来源:图灵教育
时间:2023-11-28 10:22:12
 

什么是 Java 的序列化,如何实现 Java 的序列化?

定义:序列化是指将一个对象转换为字节流,以便在网络上传输或保存到文件中。序列化过程还可以通过反序列化将字节流重新转换为对象。

实现方式:通过实现 java.io.Serializable 接口。该接口是一个标记接口,没有任何方法定义,只要一个类实现了Serializable接口,就表示该类的对象可以被序列化。Java序列化机制会根据对象的类结构自动进行序列化和反序列化操作。

示例代码:

@Test
public void serializableDemo() throws IOException, ClassNotFoundException {
    // 序列化
    User user = new User(1,"baili","baili.com");
    ObjectOutputStream output = new ObjectOutputStream(Files.newOutputStream(new File("D:\\BaiLi\\user.txt").toPath()));
    output.writeObject(user);
    output.close();
    System.out.println("序列化成功:" + user);

    // 反序列化
    ObjectInputStream input = new ObjectInputStream(Files.newInputStream(new File("D:\\BaiLi\\user.txt").toPath()));
    User user1 = (User) input.readObject();
    input.close();
    System.out.println("反序列化成功:" + user1);
}

TIPS1:如果去掉User类实现的Serializable接口,会出现以下报错:

java.io.NotSerializableException: polo.User

	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at BaiLiTest.serializableDemo(BaiLiTest.java:151)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)

TIPS2:serialVersionUID有什么作用?简单来说就是序列化的一个“密码”,序列化与反序列化“密码”需保持一致,否则会抛出异常:

  • 原User类中的serialVersionUID属性
private static final long serialVersionUID = -303793456610254190L;
  • 序列化生成user.txt文件,包含serialVersionUID
@Test
public void serializableDemo() throws IOException, ClassNotFoundException {
    // 序列化
    User user = new User(1,"baili","baili.com");
    ObjectOutputStream output = new ObjectOutputStream(Files.newOutputStream(new File("D:\\BaiLi\\user.txt").toPath()));
    output.writeObject(user);
    output.close();
    System.out.println("序列化成功:" + user);
}
  • 注释或修改User类中的serialVersionUID属性值,然后再反序列化文件出现异常
@Test
public void serializableDemo() throws IOException, ClassNotFoundException {
	// 反序列化
    ObjectInputStream input = new ObjectInputStream(Files.newInputStream(new File("D:\\BaiLi\\user.txt").toPath()));
    User user1 = (User) input.readObject();
    input.close();
    System.out.println("反序列化成功:" + user1);
}
java.io.InvalidClassException: polo.User; local class incompatible: stream classdesc serialVersionUID = -303793456610254190, local class serialVersionUID = 252382001504705380
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
	at BaiLiTest.serializableDemo(BaiLiTest.java:157)

使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。

通常建议:程序创建的每个Javabean类都实现Serializeable接口。