代码分析(十)

2021SC@SDUSC

在我们进行apijson的分析时,出现了很多的“parser”类,这些类的大致作用就是去将一些对象去进行序列化,或者解析其序列化,我们在前面分析的时候也多次遇见,所以是和本项目息息相关的东西,而序列化与反序列化又具体是什么呢?我们这次便来分析一下序列化与反序列化,以及与此项目的一些关系,和具体的使用

基本概念

(1)序列化和反序列化的定义

   Java序列化就是指把Java对象转换为字节序列的过程

   Java反序列化就是指把字节序列恢复为Java对象的过程。

(2)序列化最重要的作用

   在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。

   反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。

核心作用就是对象状态的保存和重建。

举个例子:
现在我们都会在网上买桌子,桌子这种很不规则不东西,是怎么从一个城市运输到另一个城市的?我们一般都会把它拆掉成一个一个的板子,再装到箱子里面,就可以快递寄出去了,这个过程就类似我们的序列化的过程(把数据转化为可以存储或者传输的形式)。当买家收到时,就需要自己把这些板子组装成桌子的样子,这个过程就像反序列 的过程(转化成当初的数据对象)。

那是怎么进行序列化的呢?

Java实现序列化和反序列化的过程

1、实现序列化的必备要求:

   只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常) 

2、JDK中序列化和反序列化的API:

  ①java.io.ObjectInputStream:对象输入流。

      该类的readObject()方法从输入流中读取字节序列,然后将字节序列反序列化为一个对象并返回。

 ②java.io.ObjectOutputStream:对象输出流。

      该类的writeObject(Object obj)方法将将传入的obj对象进行序列化,把得到的字节序列写入到目标输出流中进行输出。

3、实现序列化和反序列化的三种实现:

①若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化。

         ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。 
         ObjcetInputStream采用默认的反序列化方式,对Student对象的非transient的实例变量进行反序列化。

②若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。

       ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。 
       ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。

③若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

       ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。 
       ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。

序列化和反序列化的注意点:

①序列化时,只对对象的状态进行保存,而不管对象的方法;

②当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

③当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

④对象序列化的安全性问题,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

⑤声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。

⑥序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为它赋予明确的值。显式地定义serialVersionUID有两种用途:

⑦Java有很多基础类已经实现了serializable接口,比如String,Vector等。

⑧如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!这是能用序列化解决深拷贝的重要原因;

测试

我们来看一下在我们的apijson里面是如何使用的,我们直接简化一个例子

public class Student implements Serializable{                             
                                                                          
    private static final long serialVersionUID = -6060343040263809614L;   
                                                                          
    private String userName;                                              
    private String password;                                                                                               
                                                                          
    public String getUserName() {                                         
        return userName;                                                  
    }                                                                     
                                                                          
    public String getPassword() {                                         
        return password;                                                  
    }                                                                     
                                                                          
    public void setUserName(String userName) {                            
        this.userName = userName;                                         
    }                                                                     
                                                                          
    public void setPassword(String password) {                            
        this.password = password;                                         
    }                                                                     
                                                                                                                                                                                               
    public Student(String userName, String password) {       
        this.userName = userName;                                         
        this.password = password;                                                                                   
    }                                                                     
}                                                                         
public class SerializableTest {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            //序列化
            FileOutputStream fos = new FileOutputStream("object.out");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            Student student1 = new Student("张三", "123456");
            oos.writeObject(student1);
            oos.flush();
            oos.close();
            //反序列化
            FileInputStream fis = new FileInputStream("object.out");
            ObjectInputStream ois = new ObjectInputStream(fis);
            Student student2 = (Student) ois.readObject();
            System.out.println("Name is: "+student2.getUserName());
            System.out.println("Password is: "+student2.getPassword());
    }
 
}

这里面student类去实现了序列化,那么我们经过测试得到的结果就是

Name is:张三
Password is:123456

这也就是我们的apijso里面使用序列化时的概念


与小组成员讨论
关于这个序列化与反序列化的概念以及在本项目的重要作用,我本来是想和组员一起探究,但是发现他们都比较了解这一块。我便听取队友的一些经验和理解,然后结合网上的专业性解释,自己便进行了改变性解释,在获取组员的认可后,便结合着本项目,想出了一些基本的例子,这次的分析,让我对网络信息的传输又有了一个很深刻的理解,信息都是这样在客户端转译后经过物理链路端发送到另一个客户端,然后转译得到相应的对象或者数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值