首頁 Java Java入門 java如何序列化

java如何序列化

Nov 12, 2019 pm 05:44 PM
java 序列化

java如何序列化

一、序列化與反序列化

序列化:指堆記憶體中的java物件數據,透過某種方式把對儲存到磁碟檔案中,或傳遞給其他網路節點(網路傳輸)。這個過程稱為序列化,通常是指將資料結構或物件轉換成二進位的過程。

即将对象转化为二进制,用于保存,或者网络传输。
登入後複製

反序列化:把磁碟檔案中的物件資料或是把網路節點上的物件數據,恢復成Java物件模型的過程。也就是將在序列化過程中所產生的二進位串轉換成資料結構或物件的過程

与序列化相反,将二进制转化成对象。
登入後複製

二、序列化的作用

① 想把內存中的物件儲存到一個檔案或資料庫中時候;

##② 想用套接字在網路上傳送物件的時候;

③ 想透過RMI傳輸物件的時候

一些应用场景,涉及到将对象转化成二进制,序列化保证了能够成功读取到保存的对象。
登入後複製

三、java的序列化實作

要實現物件的序列化,最直接的操作就是實作Serializable介面

使用IO流中的對象流可以實現序列化操作,將物件儲存到文件,再讀取出來。

先建立一個對象,並實作Serializable介面:

import java.io.Serializable;
public class User implements Serializable{
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }
}
登入後複製

用物件流寫一個保存物件與讀取物件的工具類別:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializeUtil {
    // 保存对象,序列化
    public static void saveObject(Object object) throws Exception {
        ObjectOutputStream out = null;
        FileOutputStream fout = null;
        try {
            fout = new FileOutputStream("D:/1.txt");
            out = new ObjectOutputStream(fout);
            out.writeObject(object);
        } finally {
            fout.close();
            out.close();
        }
    }
    // 读取对象,反序列化
    public static Object readObject() throws Exception {
        ObjectInputStream in = null;
        FileInputStream fin = null;
        try {
            fin = new FileInputStream("D:/1.txt");
            in = new ObjectInputStream(fin);
            Object object = in.readObject();
            return object;
        } finally {
            fin.close();
            in.close();
        }
    }
}
登入後複製

測試:

public class Main {
    public static void main(String[] args) {
        User user = new User();
        user.setName("旭旭宝宝");
        user.setAge(33);
        // 保存
        try {
            SerializeUtil.saveObject(user);
        } catch (Exception e) {
            System.out.println("保存时异常:" + e.getMessage());
        }
        // 读取
        User userObject;
        try {
            userObject = (User) SerializeUtil.readObject();
            System.out.println(userObject);
        } catch (Exception e) {
            System.out.println("读取时异常:" + e.getMessage());
        }
    }
}
登入後複製

測試結果:

java如何序列化

這裡我們成功的進行了一次將物件儲存到檔案中,再讀取了出來。如果此時,我們不實現序列化接口,就會出現異常了。我們取消實作的Serialiable介面程式碼:

public class User {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }
}
登入後複製
登入後複製

再測試Main方法:

java如何序列化

#可以看到此時報錯了,此時使用e.printStackTrace( );查看異常的詳細資訊:

java如何序列化

可以看到Unknown Source,因為沒有進行序列化,所以無法進行儲存與讀取。

四、序列化ID的作用

可以看到,我們在進行序列化時,加了一個serialVersionUID字段,這就是序列化ID

private static final long serialVersionUID = 1L;
登入後複製

這個序列化ID起著關鍵的作用,它決定著是否能夠成功反序列化! java的序列化機制是透過判斷執行階段類別的serialVersionUID來驗證版本一致性的,在進行反序列化時,JVM會把傳進來的位元組流中的serialVersionUID與本地實體類別中的serialVersionUID進行比較,如果相同則認為是一致的,便可以進行反序列化,否則就會報序列化版本不一致的異常。

即序列化ID是为了保证成功进行反序列化
登入後複製

五、預設的序列化ID

當我們一個實體類別中沒有明確的定義一個名為「serialVersionUID」、類型為long的變數時,Java序列化機制會根據編譯時的class自動產生一個serialVersionUID作為序列化版本比較,這種情況下,只有同一次編譯產生的class才會產生相同的serialVersionUID。譬如,當我們寫一個類別時,隨著時間的推移,我們因為需求改動,需要在本地類別中添加其他的字段,這個時候再反序列化時便會出現serialVersionUID不一致,導致反序列化失敗。那麼如何解決呢?便是在本地類別中加入一個「serialVersionUID」變量,值保持不變,便可進行序列化和反序列化。

如果没有显示指定serialVersionUID,会自动生成一个。
只有同一次编译生成的class才会生成相同的serialVersionUID。
但是如果出现需求变动,Bean类发生改变,则会导致反序列化失败。为了不出现这类的问题,所以我们最好还是显式的指定一个
serialVersionUID。
登入後複製

六、序列化的其他問題

1、靜態變數不會被序列化( static,transient)

2、當一個父類別實作序列化,子類別自動實作序列化,不需要明確實作Serializable介面。

3、當一個對象的實例變數引用其他對象,序列化該對象時也把引用對象進行序列化。

子类序列化时:
如果父类没有实现Serializable接口,没有提供默认构造函数,那么子类的序列化会出错;
如果父类没有实现Serializable接口,提供了默认的构造函数,那么子类可以序列化,父类的成员变量不会被序列化。如果父类
实现了Serializable接口,则父类和子类都可以序列化。
登入後複製

七、使用效率更高的序列化框架—Protostuff

#其實java的原生序列化方式(透過實作Serialiable介面),效率並不是最高的。

github上有一個分析序列化效率的專案:https://github.com/eishay/jvm-serializers/wiki

java如何序列化

其中看的出來性能最優的為google開發的colfer ,但由於colfer的使用難度太大,而更多的都是使用protostuff序列化框架。適用改框架要引入兩個函式庫(core與runtime)。

①github位址:https://github.com/protostuff/protostuff

③如果用Maven,則新增依賴:

<dependency>
  <groupId>io.protostuff</groupId>
  <artifactId>protostuff-core</artifactId>
  <version>1.5.9</version>
</dependency>
登入後複製
登入後複製
<dependency>
  <groupId>io.protostuff</groupId>
  <artifactId>protostuff-core</artifactId>
  <version>1.5.9</version>
</dependency>
登入後複製
登入後複製

修改Main程式碼

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtobufIOUtil;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
public class Main {
    public static void main(String[] args) {
        User user = new User();
        user.setName("旭旭宝宝");
        user.setAge(33);
        Schema<User> schema = RuntimeSchema.getSchema(User.class);
        // 保存对象,序列化,转化二进制数据
        LinkedBuffer buffer = LinkedBuffer.allocate(512);
        final byte[] protostuff;
        try {
            protostuff = ProtobufIOUtil.toByteArray(user, schema, buffer);
        } finally {
            buffer.clear();
        }
        // 读取对象,反序列化
        User userObject = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, userObject, schema);
        System.out.println(userObject);
    }
}
登入後複製

User類,並未實作Serializable介面

public class User {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }
}
登入後複製
登入後複製

測試結果:


#

java如何序列化

若要要整合Redis使用,也可以写成一个工具类:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtobufIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
public class SerializeUtil {
    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<>();
    @SuppressWarnings("unchecked")
    public static <T> byte[] serializer(T obj) {
        Class<T> clazz = (Class<T>) obj.getClass();
        Schema<T> schema = getSchema(clazz);
        return ProtobufIOUtil.toByteArray(obj, schema, LinkedBuffer.allocate(256));
    }
    public static <T> T deSerializer(byte[] bytes, Class<T> clazz) {
        T message;
        try {
            message = clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        Schema<T> schema = getSchema(clazz);
        ProtobufIOUtil.mergeFrom(bytes, message, schema);
        return message;
    }
    @SuppressWarnings("unchecked")
    public static <T> Schema<T> getSchema(Class<T> clazz) {
        Schema<T> schema = (Schema<T>) cachedSchema.get(clazz);
        if (schema == null) {
            schema = RuntimeSchema.createFrom(clazz);
            if (schema != null) {
                cachedSchema.put(clazz, schema);
            }
        }
        return schema;
    }
}
登入後複製

这样即使我们的User类就不用再实现Serialiable接口了,同样可以进行序列化,效率也更高。

php中文网,大量的免费Java入门教程,欢迎在线学习!

以上是java如何序列化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

See all articles