国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

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

java如何序列化

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

java如何序列化

一、序列化與反序列化

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

即將對象轉(zhuǎn)化為二進制,用于保存,或者網(wǎng)絡(luò)傳輸。

反序列化:把磁碟檔案中的物件資料或是把網(wǎng)路節(jié)點上的物件數(shù)據(jù),恢復(fù)成Java物件模型的過程。也就是將在序列化過程中所產(chǎn)生的二進位串轉(zhuǎn)換成資料結(jié)構(gòu)或物件的過程

與序列化相反,將二進制轉(zhuǎn)化成對象。

二、序列化的作用

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

##② 想用套接字在網(wǎng)路上傳送物件的時候;

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

一些應(yīng)用場景,涉及到將對象轉(zhuǎn)化成二進制,序列化保證了能夠成功讀取到保存的對象。

三、java的序列化實作

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

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

先建立一個對象,並實作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());
        }
    }
}

測試結(jié)果:

java如何序列化

這裡我們成功的進行了一次將物件儲存到檔案中,再讀取了出來。如果此時,我們不實現(xiàn)序列化接口,就會出現(xiàn)異常了。我們?nèi)∠麑嵶鞯腟erialiable介面程式碼:

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

即序列化ID是為了保證成功進行反序列化

五、預(yù)設(shè)的序列化ID

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

如果沒有顯示指定serialVersionUID,會自動生成一個。
只有同一次編譯生成的class才會生成相同的serialVersionUID。
但是如果出現(xiàn)需求變動,Bean類發(fā)生改變,則會導(dǎo)致反序列化失敗。為了不出現(xiàn)這類的問題,所以我們最好還是顯式的指定一個
serialVersionUID。

六、序列化的其他問題

1、靜態(tài)變數(shù)不會被序列化( static,transient)

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

3、當(dāng)一個對象的實例變數(shù)引用其他對象,序列化該對象時也把引用對象進行序列化。

子類序列化時:
如果父類沒有實現(xiàn)Serializable接口,沒有提供默認構(gòu)造函數(shù),那么子類的序列化會出錯;
如果父類沒有實現(xiàn)Serializable接口,提供了默認的構(gòu)造函數(shù),那么子類可以序列化,父類的成員變量不會被序列化。如果父類
實現(xiàn)了Serializable接口,則父類和子類都可以序列化。

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

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

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

java如何序列化

其中看的出來性能最優(yōu)的為google開發(fā)的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);
        // 保存對象,序列化,轉(zhuǎn)化二進制數(shù)據(jù)
        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 + "]";
    }
}

測試結(jié)果:


#

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類就不用再實現(xiàn)Serialiable接口了,同樣可以進行序列化,效率也更高。

php中文網(wǎng),大量的免費Java入門教程,歡迎在線學(xué)習(xí)!

以上是java如何序列化的詳細內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

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

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整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

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

用Python生成序列產(chǎn)生關(guān)鍵字 用Python生成序列產(chǎn)生關(guān)鍵字 Jul 16, 2025 am 04:50 AM

yield關(guān)鍵字用於創(chuàng)建生成器,按需產(chǎn)生值,節(jié)省內(nèi)存。 1.替代return生成有限序列,如斐波那契數(shù)列;2.實現(xiàn)無限序列,如自然數(shù)列;3.處理大數(shù)據(jù)或文件讀取,逐行處理避免內(nèi)存溢出;4.注意生成器只能遍歷一次,可用next()或for循環(huán)調(diào)用。

變量的魔力 變量的魔力 Jul 16, 2025 am 03:26 AM

VariableVariables是PHP中一種將變量值作為另一個變量名使用的特性,它通過$$var的形式實現(xiàn)動態(tài)訪問變量、處理表單輸入和構(gòu)建靈活配置結(jié)構(gòu)等功能。例如$name="age";echo$$name相當(dāng)於輸出$age的值;常見使用場景包括:1.動態(tài)訪問變量,如${$type.'_info'}可根據(jù)條件選擇不同變量;2.處理表單輸入時自動賦值,但需注意安全隱患;3.構(gòu)建靈活的配置結(jié)構(gòu),通過字符串名稱獲取對應(yīng)值;使用時需注意代碼維護性、命名衝突和調(diào)試難度等問題,建議僅

探索基本的PHP語法 探索基本的PHP語法 Jul 17, 2025 am 04:11 AM

PHP基礎(chǔ)語法包括:1.使用包裹代碼;2.用echo或print輸出內(nèi)容,其中echo支持多參數(shù);3.變量無需聲明類型,以$開頭,常見類型有字符串、整數(shù)、浮點數(shù)、布爾值、數(shù)組和對象。掌握這些要點有助於快速入門PHP開發(fā)。

了解PHP變量類型 了解PHP變量類型 Jul 17, 2025 am 04:12 AM

PHP有8種變量類型,常用包括Integer、Float、String、Boolean、Array、Object、NULL和Resource。要查看變量類型,可使用gettype()或is_type()系列函數(shù)。 PHP會自動轉(zhuǎn)換類型,但建議關(guān)鍵邏輯用===嚴格比較。手動轉(zhuǎn)換可用(int)、(string)等語法,但注意可能丟失信息。

了解PHP文件 了解PHP文件 Jul 17, 2025 am 04:13 AM

PHP文件是一種服務(wù)器端腳本語言文件,用於動態(tài)網(wǎng)頁開發(fā),能處理表單數(shù)據(jù)、連接數(shù)據(jù)庫、生成動態(tài)內(nèi)容、控制訪問權(quán)限。它以.php結(jié)尾,代碼在服務(wù)器上執(zhí)行後返回結(jié)果給瀏覽器。要運行PHP文件需安裝本地服務(wù)器環(huán)境如XAMPP,把文件放至服務(wù)器目錄並通過瀏覽器訪問。 PHP通常與HTML混合使用,建議學(xué)習(xí)前先掌握HTML、CSS、JavaScript及基本編程概念,多練習(xí)可快速上手。

常見的PHP變量錯誤 常見的PHP變量錯誤 Jul 17, 2025 am 04:08 AM

PHP變量使用常見錯誤包括未定義變量、引用賦值不當(dāng)、類型比較不嚴謹和全局變量混亂。 1.忽略變量未定義會引發(fā)Notice錯誤,應(yīng)使用isset()或empty()檢查;2.引用賦值修改變量會影響其他變量,應(yīng)在循環(huán)後unset()清理;3.使用==會導(dǎo)致類型自動轉(zhuǎn)換,應(yīng)優(yōu)先使用===進行全等判斷;4.全局變量易造成混亂,建議避免或封裝成類屬性以提高代碼清晰度。

了解PHP變量 了解PHP變量 Jul 17, 2025 am 04:11 AM

PHP變量以$開頭,命名需遵循規(guī)則,如不能以數(shù)字開頭、區(qū)分大小寫;變量作用域分為局部、全局和超全局;使用global可訪問全局變量,但建議用參數(shù)傳遞;可變變量和引用賦值需謹慎使用。變量是存儲數(shù)據(jù)的基礎(chǔ),正確掌握其規(guī)則和機制對開發(fā)至關(guān)重要。

進行網(wǎng)絡(luò)掃描儀開發(fā) 進行網(wǎng)絡(luò)掃描儀開發(fā) Jul 17, 2025 am 03:30 AM

開發(fā)Go網(wǎng)絡(luò)掃描器需把握四個核心點:1.選擇合適的庫如net、gopacket;2.理解ICMP、TCP、SYN、UDP等底層協(xié)議;3.利用goroutine和channel設(shè)計並發(fā)機制並控制數(shù)量;4.確保掃描合規(guī)性避免濫用。網(wǎng)絡(luò)掃描基本方式包括ICMP探測主機存活、TCP/SYN/UDP端口檢測等,Go的net庫可實現(xiàn)基礎(chǔ)掃描,gopacket支持原始數(shù)據(jù)包操作。通過限制goroutine數(shù)量配合WaitGroup和緩衝channel可提升效率。注意事項包括合法授權(quán)、速率控制、避免公網(wǎng)大規(guī)模掃

See all articles