首頁 > Java > java教程 > 主體

JAVA之序列化

黄舟
發布: 2017-02-24 09:44:30
原創
1524 人瀏覽過

1、問題:

  如果想往一個檔案中寫入一個對象,發現位元組流,字元流都不能滿足要求,如何在一個文件中寫入物件?
使用字節字符流,都必須要將物件轉為字節/字符,再寫到文件中,可以字節字符流沒有將物件轉為字節的方法,這要如何做?

2、序列化與反序列化

Java序列化:將物件轉換為位元組的過程,這正好符合我的需求。
Java反序列化:將位元組恢復為對象的過程
這滿足我們想文件中寫對象,和讀取對象

3、序列化和反序列化的使用場景

  • a、寫下物件硬碟中;

  • b、網路間傳輸




    • ##當在網路上傳送文本,音頻,視訊等,都是轉化為二進位序列傳送,我們要在網路上傳送對象,就必須使用序列化和反序列化,滿足資料的發送和接收。
    4、序列化和反序列化的好處
一、實現資料的持久化,透過序列化將資料永久的保存在本地的硬碟上;

二、實現遠端網路通信,利用序列化,使得在網路上可以傳輸物件的位元組序列。

#5、如何實現序列化與反序列化


#5.1 、實作Serializable介面  Serializable介面沒有任何方法,只是提供一個標識, 用來告訴java機制該類別可以被序列化;

     若沒有建立這個標識,java機制將會自動的建立一個,SerialVersionUID是根據
    類別名, 介面名,成員方法及屬性
  • 等來產生一個

    64位元哈希欄位

    • 如果沒有Seri​​alVersionUID, 通常我們會發現,如果在序列化後,修改了類別的屬性, 在進行反序化,會報錯,因為累的屬性修改了,java機制會重新建立一個SerialVersionUID, 導致與原來的ID不一致, 反序列化失敗。

    如果設定了實作SerialVersionUID,保證版本的相容性, 即使新增了屬性或方法, 仍然能進行序列化和反序列化,
只是新加入的屬性值為null,或不顯示被刪除屬性的值。

    package com.chb.test;import java.io.Serializable;public class Student implements Serializable{
        //序列化标识
        private static final long serialVersionUID = 1L;    
        private String name;    
        private int age;    
        private String sex;    
        public Student() {
        }    
        public Student(String name, int age, String sex) {        
        super();        
        this.name = name;        
        this.age = age;        
        this.sex = sex;
        }    
        @Override
        public String toString() {        
        return "Student{"
                    +"姓名:"+this.name
                    +"性别:"+this.sex
                    +"年龄"+this.age
                    + "}";
        }    
        /**setter getter 省略。。。*/    
        }
    登入後複製
  • 5.2、ObjectOutputStream與ObjectInputStream

      Serializalable介面只是提供一個表示,將物件轉為二進位序列,和二進位序列恢復成物件是由ObjectOutputStream和OjbectInputStream提供的兩個方法:writeObject()和readObject()
  • writeObject()

    ##
    public static void write(Student s1) throws Exception {
            FileOutputStream fos = new FileOutputStream(filename);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s1);
            oos.close();
    }
    登入後複製
    登入後複製

readObject()

public static Student read() throws Exception {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Student stu = new Student();        //使用readeObject()进行反序列化
        stu= (Student) ois.readObject();
        ois.close();        return stu;
}
登入後複製
登入後複製
6、transient

在某種場合,我們對某些敏感欄位不要進行序列化,或類別的參考類型的成員不能夠進行序列化, 這是我們需要使用

transient

來修飾這些成員,以避免它們被序列化。如:銀行帳戶對象,不希望對帳戶金額進行序列化。

修改上面的Student類,將sex屬性使用transient修飾

transient private String sex;
登入後複製
登入後複製
JAVA之序列化再進行序列化

Student s1 = new Student("roase",19, "女");
write(s1);
登入後複製
登入後複製

反序列化, 讀取的物件發現:sex為null,說明被transient修飾的屬性不會被序列化。

    6.1 defaultWriteObject和defaultReadObject()
  • 對於上面的被transient的成員age, 如果我們想讓它能夠在此序列化和反序列化,要如何做:

  • 1、去掉transient的修飾

#2、提供兩個方法##

    private void writeObject(ObjectOutputStream out) throws Exception{        
    out.defaultWriteObject();        
    out.writeInt(age);
    }    
    private void  readObject(ObjectInputStream in) throws Exception {        
    in.defaultReadObject();
        age=in.readInt();
    }
登入後複製
登入後複製

在writeObject()方法中會先呼叫ObjectOutputStream中的defaultWriteObject()方法,該方法會執行

預設的序列化機制JAVA之序列化,此時會忽略掉age欄位。然後再呼叫writeInt()方法顯示地將age欄位寫入到ObjectOutputStream。 readObject()的作用則是針對物件的讀取,其原理與writeObject()方法相同。再次執行read()應用程序,則又會有如下輸出:

1、問題:
  如果想在一個檔案中寫入一個對象,發現位元組流,字元流都不能滿足要求,

如何寫入物件到一個檔案中? ### ###使用字節字符流,都必須要將物件轉為字節/字符,再寫到文件中,可以字節字符流沒有將物件轉為字節的方法,這要如何做? ###

2、序列化与反序列化

Java序列化:将对象转为字节的过程,这正好符合我的需求。
Java反序列化:将字节恢复为对象的过程
这满足我们想文件中写对象,和读取对象

3、序列化和反序列化的使用场景

  • a、将对象写道硬盘中;

  • b、网络间传输

    • 当在网络上传送文本,音频,视频等,都是转化为二进制序列传送,我们要在网络上传送对象,就必须使用序列化和反序列化,满足数据的发送和接收。
      ###4、序列化和反序列化的好处
      一、实现数据的持久化,通过序列化将数据永久的保存在本地的硬盘上;
      二、实现远程网络通信,利用序列化,使得在网络上可以传输对象的字节序列。

5、如何实现序列化和反序列化

5.1 、实现Serializable接口

  Serializable接口没有任何方法,只是提供一个标识 , 用来告诉java机制该类可以被序列化;
   如果没有创建这个标识,java机制将会自动的创建一个,SerialVersionUID是根据类名, 接口名,成员方法及属性等来生成一个64位哈希字段

  • 如果没有SerialVersionUID, 通常我们会发现,如果在序列化后,修改了类的属性, 在进行反序化,会报错,因为累的属性修改了,java机制会重新创建一个SerialVersionUID, 导致与原来的ID不一致, 反序列化失败。

    • 如果设置了实现SerialVersionUID, 保证版本的兼容性, 即使添加了属性或方法, 仍然能进行序列化和反序列化, 只是新添加的属性值为null,或不显示被删除属性的值。

package com.chb.test;import java.io.Serializable;public class Student implements Serializable{
    //序列化标识
    private static final long serialVersionUID = 1L;    
    private String name;    
    private int age;    
    private String sex;    
    public Student() {
    }    
    public Student(String name, int age, String sex) {        
    super();        
    this.name = name;        
    this.age = age;        
    this.sex = sex;
    }    
    @Override
    public String toString() {        
    return "Student{"
                +"姓名:"+this.name
                +"性别:"+this.sex
                +"年龄"+this.age
                + "}";
    }    
    /**setter getter 省略。。。*/    }
登入後複製

5.2、ObjectOutputStream与ObjectInputStream

  Serializalable接口只是提供一个表示,将对象转为二进制序列,和二进制序列恢复成对象是由ObjectOutputStream和OjbectInputStream提供的两个方法:writeObject()和readObject()

  • writeObject()

public static void write(Student s1) throws Exception {
        FileOutputStream fos = new FileOutputStream(filename);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(s1);
        oos.close();
}
登入後複製
登入後複製
  • readObject()

public static Student read() throws Exception {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Student stu = new Student();        //使用readeObject()进行反序列化
        stu= (Student) ois.readObject();
        ois.close();        return stu;
}
登入後複製
登入後複製

6、transient

在某种场合,我们对某些敏感字段不要进行序列化,或者类的引用类型的成员不能够进行序列化, 这是我们需要使用transient来修饰这些成员, 以避免它们被序列化。如:银行账户对象,不希望对账户金额进行序列化。
修改上面的Student类,将sex属性使用transient修饰

transient private String sex;
登入後複製
登入後複製

再进行序列化

Student s1 = new Student("roase",19, "女");
write(s1);
登入後複製
登入後複製

反序列化, 读取的对象发现:sex为null,说明被transient修饰的属性不会被序列化。
JAVA之序列化

6.1 defaultWriteObject和defaultReadObject()

对于上面的被transient的成员age, 如果我们想让它能够在此序列化和反序列化,要如何做:

  • 1、去掉transient的修饰

  • 2、提供两个方法

    private void writeObject(ObjectOutputStream out) throws Exception{        
    out.defaultWriteObject();        
    out.writeInt(age);
    }    
    private void  readObject(ObjectInputStream in) throws Exception {        
    in.defaultReadObject();
        age=in.readInt();
    }
登入後複製
登入後複製

在writeObject()方法中会先调用ObjectOutputStream中的defaultWriteObject()方法,该方法会执行默认的序列化机制,此时会忽略掉age字段。然后再调用writeInt()方法显示地将age字段写入到ObjectOutputStream中。readObject()的作用则是针对对象的读取,其原理与writeObject()方法相同。再次执行read()应用程序,则又会有如下输出:

JAVA之序列化

 以上就是JAVA之序列化的内容,更多相关内容请关注PHP中文网(www.php.cn)!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板