原文档:java序列化:为什么序列化,为什么实现Serializable,serialVersionUID拿来干嘛?
1.序列化的概念:
序列化 :(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程【百度百科】
咋一看,专业术语发懵!!
2.序列化的理解:
问1:为什么序列化,要将对象的状态信息转换为可以“存储或者传输”的形式?
答1:计算机保存的数据是二级制数据(0和1),也就是数字
问2:那么。如何将“对象的状态信息”的信息状态“转化二级制数据”?
答2:如果要将“文本,图片,视频等信息储存在电脑中,就需要序列化(也就是将文本,图片,视频等信息转化为二进制数据,保存在电脑中)”
3.举个例子:
例子1:
之前接触的序列化,将文本信息存到电脑的:D:\test.txt
/*** 将文本写入磁盘*/public class Test {public static void main(String[] args) throws Exception {// 对于java代码,是将信息输出到磁盘中对应----> output流FileOutputStream fileOutputStream = new FileOutputStream("D:\\test.txt");// 写入的内容String text = "序列化";// 将文本转化为字节byte,byte[] bytes = text.getBytes();// 将信息写入磁盘fileOutputStream.write(bytes);// 关闭流fileOutputStream.close();}}// 在盘中,节能看到文件:test.txt
重点:String类型本身有getBytes()方法,将文本转换为字节码
以上的过程,将文本信息转化为字节byte(转化为byte字节序列),然后流对象帮我们写磁盘中
那么反序列化呢?也就相当于我们读取:test.txt中的信息
/*** 读取文本* ASCII码:一个英文字母(不分大小写)占一个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数。换算为十进制 ,最小值-128,最大值127。如一个ASCII码就是一个字节。* UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节* Unicode编码:一个英文等于两个字节,一个中文(含繁体)等于两个字节。中文标点占两个字节,英文标点占两个字节*/public class Test {public static void main(String[] args) throws Exception {FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");// 序列化是三个字,utf-8下,一个字符是三个字节,三个字是九个字节byte[] bytes = new byte[9];// 将D:\test.txt的信息转化为byte字节int length = fileInputStream.read(bytes);// 将字节转化为文本信息String s = new String(bytes, 0, length);System.out.println(s); // 输出:序列化}}
例子2:
在玩游戏的时候,你的信息(玩家昵称,等级信息,玩家年龄等)往往存在电脑中,等你再玩该游戏的时候,再将等级信息等读取出来,那么一个实体类,怎么存到电脑中?
重点:自定义实体类,没有getByte()方法,怎么进行传输?
/*** 将对象信息存储到磁盘中*/public class Test {public static void main(String[] args) throws Exception {// 创建User实例User user = new User("小白",3,99);// 创建文件流对象FileOutputStream fileOutputStream= new FileOutputStream("D:\\user.txt");// 之前是通过对象.getBytes()方法,然后写到流中,但User是我们自己创建的类,没有该方法,用java提供的ObjectOutputStream对象流// 将文件流对象给对象流ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);// 对象流将对象信息写入D:\\user.txt中outputStream.writeObject(user);// 关闭流outputStream.close();fileOutputStream.close();}}/*** user类*/public class User {private String name; // 用户名称private int age; // 用户年龄private int level; // 游戏等级public User(String name, int age, int level) {this.name = name;this.age = age;this.level = level;}public User() {super();}// getter和setter省略}
运行上面的程序:报错!!
Exception in thread "main" java.io.NotSerializableException: serialization.Userat java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)at serialization.Test.main(Test.java:17)
结果告诉我们,User类没序列化!!!怎么办???Java中给我提供一个接口Serializable,源码如下
public interface Serializable {}
问:可是接口什么都没有啊,实现了有什么用?
答:java让你实现该接口,就为了告诉程序,这个能序列化,你不实现,门都没有!!相当于给实现的类一个通行证
实现一下:
/*** user类*/public class User implements Serializable {private String name; // 用户名称private int age; // 用户年龄private int level; // 游戏等级public User(String name, int age, int level) {this.name = name;this.age = age;this.level = level;}public User() {super();}// getter和setter省略}
运行程序,再去看:D:\user.txt文件的信息,这是什么鬼?
我们可以用notepad++ 安装HEX-Editor 查看十六进制(百度一下即可),内容如下:
怎么看懂记事本中的内容?:Java序列化机制和原理
看不懂,不要紧,我们只是要将信息储存在电脑中,目的已经达到了!!!
反序列化一下:**
/*** 读取D:\\user.txt信息*/public class Test {public static void main(String[] args) throws Exception {FileInputStream fileInputStream = new FileInputStream("D:\\user.txt");ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);User user = (User)objectInputStream.readObject();System.out.println(user);objectInputStream.close();fileInputStream.close();}}
输出:serialization.User@58372a00
得到的是一个对象的地址:那我们来toString(),看看他的庐山真面目:
/*** user类*/public class User implements Serializable {private String name;private int age;private int level;public User(String name, int age, int level) {this.name = name;this.age = age;this.level = level;}public User() {super();}// getter和setter省略@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", level=" + level +'}';}}
再次运行:
Exception in thread "main" java.io.InvalidClassException: serialization.User; local class incompatible: stream classdesc serialVersionUID = 4255073330490321173, local class serialVersionUID = -6139716091850480259at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885)at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)at serialization.Test.main(Test.java:15)
serialVersionUID = 4255073330490321173;
这个好像有点熟悉,是什么呢?
报错信息,序列化的id不一致!什么意思?(User类的序列化id和磁盘文件D:\user.txt中的序列化id不一致),Serializable源码注释也有说明。
看看该博客的解释:关于serialVersionUID的说明
我们给实体类,加上序列化id
/*** user类*/public class User implements Serializable {private static final long serialVersionUID = 4125096758372084309L;private String name;private int age;private int level;public User(String name, int age, int level) {this.name = name;this.age = age;this.level = level;}public User() {super();}// getter和setter省略@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", level=" + level +'}';}}
要重新序列化生成D:\user.txt文件,再次反序列化:
输出结果:User{name=’小白’, age=3, level=99}
好啦!!!
问:为什么序列化?
问:为什么实现Serializable?
问:还要加上private static final long serialVersionUID = 4125096758372084309L;
希望能对读者有帮助!
其他:
IDEA实现序列化接口Serializable自动生成serialVersionUID
idea2019位置:Setting->Editor->Inspections->Java->Serialization issues->Serializable class without
serialVersionUID
