什么是Java序列化,如何实现java序列化,在java实体类中我们应该实现Serializable接口吗

本文详细解析序列化在Java中的作用,包括对象流的处理机制,如何通过实现Serializable接口进行对象存储和网络传输,以及为何即使不显式序列化也能存储。重点讨论了默认序列化机制和Serializable接口的实际运用场景。
摘要由CSDN通过智能技术生成

简要解释:
  序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。
  序列化是为了解决在对对象流进行读写操作时所引发的问题。序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,

implements Serializable只是为了标注该对象是可被序列化的


然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

概念

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

用途

对象的序列化主要有两种用途:
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

对象序列化

序列化API

java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。只有实现了Serializable和Externalizable接口的类的对象才能被序列化。

java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

代码示例

 1 import java.io.*;
 2 import java.util.Date;
 3 
 4 public class ObjectSaver {
 5     public static void main(String[] args) throws Exception {
 6         /*其中的  D:\\objectFile.obj 表示存放序列化对象的文件*/
 7 
 8         
 9         //序列化对象
10         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:\\objectFile.obj"));
11         Customer customer = new Customer("王麻子", 24);    
12         out.writeObject("你好!");    //写入字面值常量
13         out.writeObject(new Date());    //写入匿名Date对象
14         out.writeObject(customer);    //写入customer对象
15         out.close();
16 
17         
18         //反序列化对象
19         ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\objectFile.obj"));
20         System.out.println("obj1 " + (String) in.readObject());    //读取字面值常量
21         System.out.println("obj2 " + (Date) in.readObject());    //读取匿名Date对象
22         Customer obj3 = (Customer) in.readObject();    //读取customer对象
23         System.out.println("obj3 " + obj3);
24         in.close();
25     }
26 }
27 
28 class Customer implements Serializable {
29     private String name;
30     private int age;
31     public Customer(String name, int age) {
32         this.name = name;
33         this.age = age;
34     }
35 
36     public String toString() {
37         return "name=" + name + ", age=" + age;
38     }
39 }

执行结果
在这里插入图片描述
说明:
读取对象的顺序与写入时的顺序要一致。
对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。

implements Serializable

Java 中我们声明一个实体类时进行序列化操作一般需要实现 Serializable 或 Externalizable 接口。
在Java编程中我们会看到源码中或者别人代码中很多实体Bean都实现了Serializable接口,但是我很多实体在使用中并没有序列化也能正常使用。或者我们有时候感觉自己在项目中并没有进行序列化操作,也一样是存进去了,那么对象需要经过序列化才能存储的说法,似乎从这儿就给阉割了。事实究竟是怎样的呢?
首先看我们常用的数据类型类源码声明:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence
public class Date implements java.io.Serializable, Cloneable, Comparable

而像其他int、long、boolean类型等,都是基本数据类型,数据库里面有与之对应的数据结构。从上面的类声明来看,我们以为的没有进行序列化,其实是在声明的各个不同变量的时候,由具体的数据类型帮助我们实现了序列化操作。
拿到这儿的时候,就又有一个问题,既然实体类的变量都已经帮助我们实现了序列化,为什么我们仍然要显示的让类实现serializable接口呢?

请注意我以上的说法:首先,序列化的目的有两个,第一个是便于存储,第二个是便于传输。我们一般的实体类不需要程序员再次实现序列化的时候,请想两个问题:第一:存储媒体里面,是否是有其相对应的数据结构?第二:这个实体类,是否需要远程传输(或者两个不同系统甚至是分布式模块之间的调用)?

如果有注意观察的话,发现序列化操作用于存储时,一般是对于NoSql数据库,而在使用Nosql数据库进行存储时,用“freeze”这个说法来理解是再恰当不过了,请在NoSql数据库中,给我找出个varchar,int之类的数据结构出来? 如果没有,但我们又确实需要进行存储,那么,此时程序员再不将对象进行序列化,更待何时?

备注:如果有人打开过Serializable接口的源码,就会发现,这个接口其实是个空接口,那么这个序列化操作,到底是由谁去实现了呢?其实,看一下接口的注释说明就知道,当我们让实体类实现Serializable接口时,其实是在告诉JVM此类可被序列化,可被默认的序列化机制序列化。

然后,需要说明的是,当我们在实体类声明实现Serializable接口时,再次进行观察,会发现这些类是需要被远程调用的。也就是说需要或者可能需要被远程调用,这就是序列化便于传输的用途。

序列化案例:
Father.java

public class Father {

    public int f;

}

Son.java

public class Son extends Father implements Serializable {

    public int s;

    public Son() {
        super();
    }
}

SerializableMain.java

public class SerializableMain {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //  如果将序列化对象改成父类,则会抛出异常,没有标记为Serializable接口
//        Father father = new Father();
        Father father = new Son();
        father.f = 5;

        //  序列化
        FileOutputStream fileOutputStream  = new FileOutputStream("temp.o");
        ObjectOutput objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(father);

        //  反序列化
        FileInputStream fileInputStream = new FileInputStream("temp.o");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Object object = objectInputStream.readObject();
        Father f = (Father) object;
        //  由于子类没有f这个变量,是调用的父类的f变量
        System.out.println(f.f);
    }
}

输出结果, f = 0,当父类实现Serializable接口时,f = 5;因此,在实体bean中都应该显示地实现序列化接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值