java序列化:为什么序列化,为什么实现Serializable,serialVersionUID拿来干嘛?

我会带着你远行 2022-03-14 10:26 408阅读 0赞

本文索引:

  • 1.序列化的概念:
  • 2.序列化的理解:
  • 3.举个例子:
    • 例子1:
    • 例子2:

1.序列化的概念:

序列化 :(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程【百度百科】
咋一看,专业术语发懵!!

2.序列化的理解:

问1:为什么序列化,要将对象的状态信息转换为可以“存储或者传输”的形式?
答1:计算机保存的数据是二级制数据(0和1),也就是数字
问2:那么。如何将“对象的状态信息”的信息状态“转化二级制数据”?
答2:如果要将“文本,图片,视频等信息储存在电脑中,就需要序列化(也就是将文本,图片,视频等信息转化为二进制数据,保存在电脑中)”

3.举个例子:

序列化的过程,其实在java IO流中就已经有体会了!!

例子1:

之前接触的序列化,将文本信息存到电脑的:D:\test.txt

  1. /**
  2. * 将文本写入磁盘
  3. */
  4. public class Test {
  5. public static void main(String[] args) throws Exception {
  6. // 对于java代码,是将信息输出到磁盘中对应----> output流
  7. FileOutputStream fileOutputStream = new FileOutputStream("D:\\test.txt");
  8. // 写入的内容
  9. String text = "序列化";
  10. // 将文本转化为字节byte,
  11. byte[] bytes = text.getBytes();
  12. // 将信息写入磁盘
  13. fileOutputStream.write(bytes);
  14. // 关闭流
  15. fileOutputStream.close();
  16. }
  17. }
  18. // 在盘中,节能看到文件:test.txt

重点:String类型本身有getBytes()方法,将文本转换为字节码
以上的过程,将文本信息转化为字节byte(转化为byte字节序列),然后流对象帮我们写磁盘中
那么反序列化呢?也就相当于我们读取:test.txt中的信息

  1. /**
  2. * 读取文本
  3. * ASCII码:一个英文字母(不分大小写)占一个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数。换算为十进制 ,最小值-128,最大值127。如一个ASCII码就是一个字节。
  4. * UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节
  5. * Unicode编码:一个英文等于两个字节,一个中文(含繁体)等于两个字节。中文标点占两个字节,英文标点占两个字节
  6. */
  7. public class Test {
  8. public static void main(String[] args) throws Exception {
  9. FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");
  10. // 序列化是三个字,utf-8下,一个字符是三个字节,三个字是九个字节
  11. byte[] bytes = new byte[9];
  12. // 将D:\test.txt的信息转化为byte字节
  13. int length = fileInputStream.read(bytes);
  14. // 将字节转化为文本信息
  15. String s = new String(bytes, 0, length);
  16. System.out.println(s); // 输出:序列化
  17. }
  18. }

例子2:

在玩游戏的时候,你的信息(玩家昵称,等级信息,玩家年龄等)往往存在电脑中,等你再玩该游戏的时候,再将等级信息等读取出来,那么一个实体类,怎么存到电脑中?
重点:自定义实体类,没有getByte()方法,怎么进行传输?

  1. /**
  2. * 将对象信息存储到磁盘中
  3. */
  4. public class Test {
  5. public static void main(String[] args) throws Exception {
  6. // 创建User实例
  7. User user = new User("小白",3,99);
  8. // 创建文件流对象
  9. FileOutputStream fileOutputStream= new FileOutputStream("D:\\user.txt");
  10. // 之前是通过对象.getBytes()方法,然后写到流中,但User是我们自己创建的类,没有该方法,用java提供的ObjectOutputStream对象流
  11. // 将文件流对象给对象流
  12. ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
  13. // 对象流将对象信息写入D:\\user.txt中
  14. outputStream.writeObject(user);
  15. // 关闭流
  16. outputStream.close();
  17. fileOutputStream.close();
  18. }
  19. }
  20. /**
  21. * user类
  22. */
  23. public class User {
  24. private String name; // 用户名称
  25. private int age; // 用户年龄
  26. private int level; // 游戏等级
  27. public User(String name, int age, int level) {
  28. this.name = name;
  29. this.age = age;
  30. this.level = level;
  31. }
  32. public User() {
  33. super();
  34. }
  35. // getter和setter省略

运行上面的程序:报错!!

  1. Exception in thread "main" java.io.NotSerializableException: serialization.User
  2. at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
  3. at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
  4. at serialization.Test.main(Test.java:17)

结果告诉我们,User类没序列化!!!怎么办???Java中给我提供一个接口Serializable,源码如下

  1. public interface Serializable {
  2. }

:可是接口什么都没有啊,实现了有什么用?
:java让你实现该接口,就为了告诉程序,这个能序列化,你不实现,门都没有!!相当于给实现的类一个通行证
实现一下:

  1. /**
  2. * user类
  3. */
  4. public class User implements Serializable {
  5. private String name; // 用户名称
  6. private int age; // 用户年龄
  7. private int level; // 游戏等级
  8. public User(String name, int age, int level) {
  9. this.name = name;
  10. this.age = age;
  11. this.level = level;
  12. }
  13. public User() {
  14. super();
  15. }
  16. // getter和setter省略

运行程序,再去看:D:\user.txt文件的信息,这是什么鬼?
在这里插入图片描述
我们可以用notepad++ 安装HEX-Editor 查看十六进制(百度一下即可),内容如下:
在这里插入图片描述
怎么看懂记事本中的内容?:
https://www.cnblogs.com/redcreen/articles/1955307.html

看不懂,不要紧,我们只是要将信息储存在电脑中,目的已经达到了!!!

反序列化一下

  1. /**
  2. * 读取D:\\user.txt信息
  3. */
  4. public class Test {
  5. public static void main(String[] args) throws Exception {
  6. FileInputStream fileInputStream = new FileInputStream("D:\\user.txt");
  7. ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
  8. User user = (User)objectInputStream.readObject();
  9. System.out.println(user);
  10. objectInputStream.close();
  11. fileInputStream.close();
  12. }
  13. }
  14. 输出:serialization.User@58372a00

得到的是一个对象的地址:那我们来toString(),看看他的庐山真面目:

  1. /**
  2. * user类
  3. */
  4. public class User implements Serializable {
  5. private String name;
  6. private int age;
  7. private int level;
  8. public User(String name, int age, int level) {
  9. this.name = name;
  10. this.age = age;
  11. this.level = level;
  12. }
  13. public User() {
  14. super();
  15. }
  16. // getter和setter省略
  17. @Override
  18. public String toString() {
  19. return "User{" +
  20. "name='" + name + '\'' +
  21. ", age=" + age +
  22. ", level=" + level +
  23. '}';
  24. }

再次运行:

  1. Exception in thread "main" java.io.InvalidClassException: serialization.User; local class incompatible: stream classdesc serialVersionUID = 4255073330490321173, local class serialVersionUID = -6139716091850480259
  2. at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
  3. at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885)
  4. at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)
  5. at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)
  6. at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
  7. at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
  8. at serialization.Test.main(Test.java:15)

serialVersionUID = 4255073330490321173;这个好像有点熟悉,是什么呢?
报错信息,序列化的id不一致!什么意思?(User类的序列化id和磁盘文件D:\user.txt中的序列化id不一致),Serializable源码注释也有说明
看看该博客的解释:https://blog.csdn.net/jediael_lu/article/details/26813153
我们给实体类,加上序列化id

  1. /**
  2. * user类
  3. */
  4. public class User implements Serializable {
  5. private static final long serialVersionUID = 4125096758372084309L;
  6. private String name;
  7. private int age;
  8. private int level;
  9. public User(String name, int age, int level) {
  10. this.name = name;
  11. this.age = age;
  12. this.level = level;
  13. }
  14. public User() {
  15. super();
  16. }
  17. // getter和setter省略
  18. @Override
  19. public String toString() {
  20. return "User{" +
  21. "name='" + name + '\'' +
  22. ", age=" + age +
  23. ", level=" + level +
  24. '}';
  25. }

要重新序列化生成D:\user.txt文件,再次反序列化:

  1. 输出结果: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’)

发表评论

表情:
评论列表 (有 0 条评论,408人围观)

还没有评论,来说两句吧...

相关阅读