Java基础进阶IO流-序列化和反序列化

本文涉及的产品
系统运维管理,不限时长
简介: Java基础进阶IO流-序列化和反序列化

1、java.io.NotSerializableException:


Student对象不支持序列化!!!!

2、参与序列化和反序列化的对象,必须实现Serializable接口。


3、注意:通过源代码发现,Serializable接口只是一个标志接口:


public interface Serializable {
   }


这个接口当中什么代码都没有。

那么它起到一个什么作用呢?

起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。

Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成

一个序列化版本号。


4、序列化版本号有什么用呢?


java.io.InvalidClassException:
       com.bjpowernode.java.bean.Student;
       local class incompatible:
           stream classdesc serialVersionUID = -684255398724514298(十年后),
           local class serialVersionUID = -3463447116624555755(十年前)


java语言中是采用什么机制来区分类的?


第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类。

第二:如果类名一样,再怎么进行类的区别?靠序列化版本号进行区分。

张三编写了一个类:com.bjpowernode.java.bean.Student implements Serializable

李四编写了一个类:com.bjpowernode.java.bean.Student implements Serializable

不同的人编写了同一个类,但“这两个类确实不是同一个类”。这个时候序列化版本就起上作用了。

对于java虚拟机来说,java虚拟机是可以区分开这两个类的,因为这两个类都实现了Serializable接口,

都有默认的序列化版本号,他们的序列化版本号不一样。所以区分开了。(这是自动生成序列化版本号的好处)


思考:

这种自动生成序列化版本号有什么缺陷?


这种自动生成的序列化版本号缺点是:一旦代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。(这样就不好了!)

最终结论:


凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。

这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类。

图解(引自b站老杜Java零基础);


0a2653c851af460fa595bd959398a8f1.png


示例代码01:


public class Student implements Serializable {
    // IDEA工具自动生成序列化版本号。
    //private static final long serialVersionUID = -7998917368642754840L;
    // Java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号。
    // 这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。
    // 建议将序列化版本号手动的写出来。不建议自动生成
    private static final long serialVersionUID = 2280880218502988510L;// java虚拟机识别一个类的时候先通过类名,如果类名一致,再通过序列化版本号。
    //private String name;
    // 过了很久,Student这个类源代码改动了。
    // 源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。
    // 并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变。
    int no;
    String name;
    private int age;
    private String email;
    private String address;
    public Student(){}
    public Student(int no,String name){
        this.no = no;
        this.name = name;
    }
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}


示例代码02:


public class ObjectOutputStreamTest01 {
    public static void main(String[] args) {
        //创建Student对象
        Student s = new Student(1111,"zahngsan");
        //序列化
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("students"));
            //序列化对象
            out.writeObject(s);
            //刷新
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


运行结果:


2d65d23f6d4748949b924e4057485923.png


示例代码03:


public class ObjectInputStreamTest01 {
    public static void main(String[] args) {
        //反序列化
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("students"));
            //反序列化
            Object o = ois.readObject();
            // 反序列化回来是一个学生对象,所以会调用学生对象的toString方法。
            System.out.println(o);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally{
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


运行结果:


6de278e6d6694ce5bb08e7e842b7e74b.png


一次序列化多个对象

可以,可以将对象放到集合当中,序列化集合。

提示:

参与序列化的ArrayList集合以及集合中的元素User都需要实现 java.io.Serializable接口。

transient关键字表示游离的,不参与序列化。


示例代码04:


public class User implements Serializable {
    private static final long serialVersionUID = -203337022093748667L;
    private int no;
    // transient关键字表示游离的,不参与序列化。
    private transient String name;// name不参与序列化操作!
    public User() {
    }
    public User(int no, String name) {
        this.no = no;
        this.name = name;
    }
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}


示例代码05:


public class ObjectOutputStreamTest02 {
    public static void main(String[] args) {
        //序列化多个对象,可以把对象放在集合中操作
        List<User> list = new ArrayList<>();
        list.add(new User(1111,"zhangsan"));
        list.add(new User(2222,"lisi"));
        list.add(new User(3333,"wangwu"));
        list.add(new User(4444,"zhaoliu"));
        //序列化集合
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("user"));
            oos.writeObject(list);
            //流刷新
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(oos != null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


运行结果:


8ec4f2997fb246878c34ecd6d122b7c6.png


示例代码06:


/*
反序列化集合
 */
public class ObjectInputStreamTest02 {
    public static void main(String[] args) {
        //反序列化
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("user"));
            //反序列化
            List<User> userList = (List<User>) ois.readObject();
            //Object obj = ois.readObject();
            //System.out.println(obj instanceof List);
            //System.out.println(userList);
            for(User users : userList){
                System.out.println(users);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


运行结果:


12c3b7f3f8814309a195c64f051d4445.png

相关文章
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
72 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
28天前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
2月前
|
存储 Java
序列化流 ObjectInputStream 和 ObjectOutputStream 的基本使用【 File类+IO流知识回顾④】
这篇文章介绍了Java中ObjectInputStream和ObjectOutputStream类的基本使用,这两个类用于实现对象的序列化和反序列化。文章解释了序列化的概念、如何通过实现Serializable接口来实现序列化,以及如何使用transient关键字标记不需要序列化的属性。接着,通过示例代码演示了如何使用ObjectOutputStream进行对象的序列化和ObjectInputStream进行反序列化。
序列化流 ObjectInputStream 和 ObjectOutputStream 的基本使用【 File类+IO流知识回顾④】
|
1月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
1月前
|
消息中间件 存储 Java
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
46 3
|
28天前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
27 0
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
存储 Java 开发者
Java编程中的对象序列化与反序列化
【9月更文挑战第20天】在本文中,我们将探索Java编程中的一个核心概念——对象序列化与反序列化。通过简单易懂的语言和直观的代码示例,你将学会如何将对象状态保存为字节流,以及如何从字节流恢复对象状态。这不仅有助于理解Java中的I/O机制,还能提升你的数据持久化能力。准备好让你的Java技能更上一层楼了吗?让我们开始吧!
|
2月前
|
存储 Java
Java编程中的对象序列化与反序列化
【9月更文挑战第12天】在Java的世界里,对象序列化与反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何通过实现Serializable接口来标记一个类的对象可以被序列化,并探索ObjectOutputStream和ObjectInputStream类的使用,以实现对象的写入和读取。我们还将讨论序列化过程中可能遇到的问题及其解决方案,确保你能够高效、安全地处理对象序列化。
下一篇
无影云桌面