Java集合02 - Serializable

目录

1.什么是序列化与反序列化

2.Serializable是什么

3.Serializable如何使用

4.序列化ID的作用


笔者JDK版本:1.8.0_202

1.什么是序列化与反序列化

       在Java程序运行期间所创建的对象都暂时保存在内存中,服务端创建的用户session也是如此,假设有一天用户的session过多,并且这些session中有很多僵尸粉,长期不活跃还占用着服务器的内存资源,那么能不能有一种方法可以将处于内存中的对象持久化到硬盘中,等僵尸粉突然活跃后再将其取出重新加载进内存呢?这便用到了序列化技术:

       序列化:把对象转换为字节序列的过程

       反序列化:把字节序列恢复为对象的过程

2.Serializable是什么

The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.

       源码第一段有这么一句话,序列化接口没有方法或字段,并且只用于标识可序列化的语义,简单点说就是Serializable是一个序列化标识接口,无具体实现,目的为通知JVM该类可被序列化。实现了Serializable接口的类可以被ObjectOutputStream转换为字节流,同时也可以通过ObjectInputStream再将其解析为对象。

3.Serializable如何使用

       首先创建一个被序列化的实体User实现Serializable接口:

package com.santbbd.ams.utils;
import lombok.Data;
import java.io.Serializable;

@Data
public class User implements Serializable{

    private static final long serialVersionUID = 896881012930132312L;

    private String userId;
    private String userName; 

    public User(String userId, String userName) { 
        this.userId = userId; 
        this.userName = userName; 
    } 
} 

       然后在主函数内创建一个User实体,并将其序列化到磁盘上:

public static void main(String[] args) {
		User user = new User("0001", "Tom");
		try {
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\user.txt"));
			objectOutputStream.writeObject(user);
			objectOutputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
}

        运行之后我们到生成的文件中查看一下:

         发现写入成功,因为是二进制写入的文件直接查看会乱码,我们看不懂也不要紧,只要可以反序列化拿到这个对象就可以,接下来在Main函数中新增反序列化:

public static void main(String[] args) {
	try {
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\user.txt"));
		Object object = objectInputStream.readObject();
		User user = (User) object;
		System.out.println(user);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

         控制台打印出重新加载到内存中对象的信息并和之前对象的属性一致,证明反序列化成功:

 

         如果不实现Serializable接口就去尝试进行序列化操作会抛出NotSerializableException异常:

4.序列化ID的作用

         我们可以看到上述User类中有这样一个属性,这个序列化ID究竟是做什么的呢,不写可不可以呢?

private static final long serialVersionUID = 896881012930132312L;

         源码中有这样一段话来解释序列化ID的作用:

 

         笔者英文捉急,用百度翻译翻译过大致为:如果可序列化类没有显式声明serialVersionUID,则序列化运行时将根据类的各个方面计算该类的默认serialVersionUID值,如Java(TM)对象序列化规范中所述。但是,强烈建议所有可序列化类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类细节高度敏感,这些细节可能因编译器实现而异,因此在反序列化过程中可能导致意外的InvalidClassException。因此,为了保证不同java编译器实现之间的serialVersionUID值一致,可序列化类必须声明显式serialVersionUID值。还强烈建议显式serialVersionUID声明尽可能使用private修饰符,因为这样的声明只适用于立即声明的类——serialVersionUID字段作为继承成员没有用处。数组类不能声明显式serialVersionUID,因此它们始终具有默认的计算值,但数组类不需要匹配serialVersionUID值。

         简单一点来说,如果没有显示声明serialVersionUID,JVM会自动生成一个。但强烈建议用private显示声明serialVersionUID,private可以保证该属性不会被子类继承,数组类型不能显示声明serialVersionUID

         serialVersionUID的作用为:验证序列化前后的类是否一致,在序列化时系统将serialVersionUID写入到序列化的文件中,当反序列化时系统会先检测文件中的serialVersionUID是否跟当前文件的serialVersionUID一致,如果一致则反序列化成功,否则就说明当前类跟序列化后的类发生了变化,比如新增了某些属性,那么在反序列化时就会抛出InvalidClassException异常

         所以如果我们显示声明了serialVersionUID的值就可以解决这个问题。

猜你喜欢

转载自blog.csdn.net/qq_36756682/article/details/110924264