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

java如何序列化

愛(ài)喝馬黛茶的安東尼
發(fā)布: 2019-11-12 17:44:30
原創(chuàng)
2550人瀏覽過(guò)

java如何序列化

一、序列化與反序列化

序列化:指堆內(nèi)存中的java對(duì)象數(shù)據(jù),通過(guò)某種方式把對(duì)存儲(chǔ)到磁盤(pán)文件中,或者傳遞給其他網(wǎng)絡(luò)節(jié)點(diǎn)(網(wǎng)絡(luò)傳輸)。這個(gè)過(guò)程稱為序列化,通常是指將數(shù)據(jù)結(jié)構(gòu)或?qū)ο筠D(zhuǎn)化成二進(jìn)制的過(guò)程。

即將對(duì)象轉(zhuǎn)化為二進(jìn)制,用于保存,或者網(wǎng)絡(luò)傳輸。
登錄后復(fù)制

反序列化:把磁盤(pán)文件中的對(duì)象數(shù)據(jù)或者把網(wǎng)絡(luò)節(jié)點(diǎn)上的對(duì)象數(shù)據(jù),恢復(fù)成Java對(duì)象模型的過(guò)程。也就是將在序列化過(guò)程中所生成的二進(jìn)制串轉(zhuǎn)換成數(shù)據(jù)結(jié)構(gòu)或者對(duì)象的過(guò)程

與序列化相反,將二進(jìn)制轉(zhuǎn)化成對(duì)象。
登錄后復(fù)制

二、序列化的作用

立即學(xué)習(xí)Java免費(fèi)學(xué)習(xí)筆記(深入)”;

① 想把內(nèi)存中的對(duì)象保存到一個(gè)文件中或者數(shù)據(jù)庫(kù)中時(shí)候;

② 想用套接字在網(wǎng)絡(luò)上傳送對(duì)象的時(shí)候;

③ 想通過(guò)RMI傳輸對(duì)象的時(shí)候

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

三、java的序列化實(shí)現(xiàn)

要實(shí)現(xiàn)對(duì)象的序列化,最直接的操作就是實(shí)現(xiàn)Serializable接口

使用IO流中的對(duì)象流可以實(shí)現(xiàn)序列化操作,將對(duì)象保存到文件,再讀取出來(lái)。

首先創(chuàng)建一個(gè)對(duì)象,并實(shí)現(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 + "]";
    }
}
登錄后復(fù)制

用對(duì)象流寫(xiě)一個(gè)保存對(duì)象與讀取對(duì)象的工具類:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializeUtil {
    // 保存對(duì)象,序列化
    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();
        }
    }
    // 讀取對(duì)象,反序列化
    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();
        }
    }
}
登錄后復(fù)制

測(cè)試:

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("保存時(shí)異常:" + e.getMessage());
        }
        // 讀取
        User userObject;
        try {
            userObject = (User) SerializeUtil.readObject();
            System.out.println(userObject);
        } catch (Exception e) {
            System.out.println("讀取時(shí)異常:" + e.getMessage());
        }
    }
}
登錄后復(fù)制

測(cè)試結(jié)果:

1d23a791ec83fe88511f5a028bec8ba.png

這里我們成功的進(jìn)行了一次將對(duì)象保存到文件中,再讀取了出來(lái)。如果此時(shí),我們不實(shí)現(xiàn)序列化接口,就會(huì)出現(xiàn)異常了。我們?nèi)∠麑?shí)現(xiàn)的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 + "]";
    }
}
登錄后復(fù)制
登錄后復(fù)制

再測(cè)試Main方法:

61ce82282a06d248ef4f6356006238d.png

可以看到此時(shí)報(bào)錯(cuò)了,此時(shí)使用 e.printStackTrace();查看異常的詳細(xì)信息:

0f19ecf6b56cf353c16a440818a5632.png

可以看到Unknown Source,因?yàn)闆](méi)有進(jìn)行序列化,所以無(wú)法進(jìn)行保存與讀取。

四、序列化ID的作用

可以看到,我們?cè)谶M(jìn)行序列化時(shí),加了一個(gè)serialVersionUID字段,這便是序列化ID

private static final long serialVersionUID = 1L;
登錄后復(fù)制

這個(gè)序列化ID起著關(guān)鍵的作用,它決定著是否能夠成功反序列化!java的序列化機(jī)制是通過(guò)判斷運(yùn)行時(shí)類的serialVersionUID來(lái)驗(yàn)證版本一致性的,在進(jìn)行反序列化時(shí),JVM會(huì)把傳進(jìn)來(lái)的字節(jié)流中的serialVersionUID與本地實(shí)體類中的serialVersionUID進(jìn)行比較,如果相同則認(rèn)為是一致的,便可以進(jìn)行反序列化,否則就會(huì)報(bào)序列化版本不一致的異常。

即序列化ID是為了保證成功進(jìn)行反序列化
登錄后復(fù)制

五、默認(rèn)的序列化ID

當(dāng)我們一個(gè)實(shí)體類中沒(méi)有顯式的定義一個(gè)名為“serialVersionUID”、類型為long的變量時(shí),Java序列化機(jī)制會(huì)根據(jù)編譯時(shí)的class自動(dòng)生成一個(gè)serialVersionUID作為序列化版本比較,這種情況下,只有同一次編譯生成的class才會(huì)生成相同的serialVersionUID。譬如,當(dāng)我們編寫(xiě)一個(gè)類時(shí),隨著時(shí)間的推移,我們因?yàn)樾枨蟾膭?dòng),需要在本地類中添加其他的字段,這個(gè)時(shí)候再反序列化時(shí)便會(huì)出現(xiàn)serialVersionUID不一致,導(dǎo)致反序列化失敗。那么如何解決呢?便是在本地類中添加一個(gè)“serialVersionUID”變量,值保持不變,便可以進(jìn)行序列化和反序列化。

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

六、序列化的其他問(wèn)題

1、靜態(tài)變量不會(huì)被序列化( static,transient)

2、當(dāng)一個(gè)父類實(shí)現(xiàn)序列化,子類自動(dòng)實(shí)現(xiàn)序列化,不需要顯式實(shí)現(xiàn)Serializable接口。

3、當(dāng)一個(gè)對(duì)象的實(shí)例變量引用其他對(duì)象,序列化該對(duì)象時(shí)也把引用對(duì)象進(jìn)行序列化。

子類序列化時(shí):
如果父類沒(méi)有實(shí)現(xiàn)Serializable接口,沒(méi)有提供默認(rèn)構(gòu)造函數(shù),那么子類的序列化會(huì)出錯(cuò);
如果父類沒(méi)有實(shí)現(xiàn)Serializable接口,提供了默認(rèn)的構(gòu)造函數(shù),那么子類可以序列化,父類的成員變量不會(huì)被序列化。如果父類
實(shí)現(xiàn)了Serializable接口,則父類和子類都可以序列化。
登錄后復(fù)制

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

其實(shí)java的原生序列化方式(通過(guò)實(shí)現(xiàn)Serialiable接口),效率并不是最高的。

github上有一個(gè)分析序列化效率的項(xiàng)目:https://github.com/eishay/jvm-serializers/wiki

0fa6fad1fded2e2d3d4e3f650d7854f.png

其中看的出來(lái)性能最優(yōu)的為google開(kāi)發(fā)的colfer ,但是由于colfer的使用難度太大,而更多的都是使用protostuff序列化框架。適用改框架要引入兩個(gè)庫(kù)(core與runtime)。

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

③如果用Maven,則添加依賴:

<dependency>
  <groupId>io.protostuff</groupId>
  <artifactId>protostuff-core</artifactId>
  <version>1.5.9</version>
</dependency>
登錄后復(fù)制
登錄后復(fù)制
<dependency>
  <groupId>io.protostuff</groupId>
  <artifactId>protostuff-core</artifactId>
  <version>1.5.9</version>
</dependency>
登錄后復(fù)制
登錄后復(fù)制

修改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);
        // 保存對(duì)象,序列化,轉(zhuǎn)化二進(jìn)制數(shù)據(jù)
        LinkedBuffer buffer = LinkedBuffer.allocate(512);
        final byte[] protostuff;
        try {
            protostuff = ProtobufIOUtil.toByteArray(user, schema, buffer);
        } finally {
            buffer.clear();
        }
        // 讀取對(duì)象,反序列化
        User userObject = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, userObject, schema);
        System.out.println(userObject);
    }
}
登錄后復(fù)制

User類,并未實(shí)現(xiàn)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 + "]";
    }
}
登錄后復(fù)制
登錄后復(fù)制

測(cè)試結(jié)果:

07078b0e6c791b4a32b1650ae800811.png

若要要整合Redis使用,也可以寫(xiě)成一個(gè)工具類:

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;
    }
}
登錄后復(fù)制

這樣即使我們的User類就不用再實(shí)現(xiàn)Serialiable接口了,同樣可以進(jìn)行序列化,效率也更高。

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

以上就是java如何序列化的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!

java速學(xué)教程(入門(mén)到精通)
java速學(xué)教程(入門(mén)到精通)

java怎么學(xué)習(xí)?java怎么入門(mén)?java在哪學(xué)?java怎么學(xué)才快?不用擔(dān)心,這里為大家提供了java速學(xué)教程(入門(mén)到精通),有需要的小伙伴保存下載就能學(xué)習(xí)啦!

下載
來(lái)源:php中文網(wǎng)
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn
最新問(wèn)題
開(kāi)源免費(fèi)商場(chǎng)系統(tǒng)廣告
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板
關(guān)于我們 免責(zé)申明 意見(jiàn)反饋 講師合作 廣告合作 最新更新
php中文網(wǎng):公益在線php培訓(xùn),幫助PHP學(xué)習(xí)者快速成長(zhǎng)!
關(guān)注服務(wù)號(hào) 技術(shù)交流群
PHP中文網(wǎng)訂閱號(hào)
每天精選資源文章推送
PHP中文網(wǎng)APP
隨時(shí)隨地碎片化學(xué)習(xí)
PHP中文網(wǎng)抖音號(hào)
發(fā)現(xiàn)有趣的

Copyright 2014-2025 http://www.miracleart.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號(hào)