Java實(shí)現(xiàn)幾種序列化方式總結(jié)
0、前言
本文主要對(duì)幾種常見Java序列化方式進(jìn)行實(shí)現(xiàn)。包括Java原生以流的方法進(jìn)行的序列化、Json序列化、FastJson序列化、Protobuff序列化。
1、Java原生序列化
Java原生序列化方法即通過Java原生流(InputStream和OutputStream之間的轉(zhuǎn)化)的方式進(jìn)行轉(zhuǎn)化。需要注意的是JavaBean實(shí)體類必須實(shí)現(xiàn)Serializable接口,否則無法序列化。Java原生序列化代碼示例如下所示:
運(yùn)行結(jié)果:
java serialize: 8ms; 總大小:420
java deserialize: 1ms; User: User [userId=null, userName=張三, passWord=123456, userInfo=張三是一個(gè)很牛的人, friends=[User [userId=null, userName=李四, passWord=123456, userInfo=李四是一個(gè)很牛的人, friends=null], User [userId=null, userName=王五, passWord=123456, userInfo=王五是一個(gè)很牛的人, friends=null]]]
2、Json序列化
Json序列化一般會(huì)使用jackson包,通過ObjectMapper類來進(jìn)行一些操作,比如將對(duì)象轉(zhuǎn)化為byte數(shù)組或者將json串轉(zhuǎn)化為對(duì)象。現(xiàn)在的大多數(shù)公司都將json作為服務(wù)器端返回的數(shù)據(jù)格式。比如調(diào)用一個(gè)服務(wù)器接口,通常的請(qǐng)求為xxx.json?a=xxx&b=xxx的形式。Json序列化示例代碼如下所示:
package serialize; import java.io.IOException; import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; /** * * @author liqqc * */ public class JsonSerialize { public static void main(String[] args) throws IOException { new JsonSerialize().start(); } public void start() throws IOException { User u = new User(); List<User> friends = new ArrayList<>(); u.setUserName("張三"); u.setPassWord("123456"); u.setUserInfo("張三是一個(gè)很牛的人"); u.setFriends(friends); User f1 = new User(); f1.setUserName("李四"); f1.setPassWord("123456"); f1.setUserInfo("李四是一個(gè)很牛的人"); User f2 = new User(); f2.setUserName("王五"); f2.setPassWord("123456"); f2.setUserInfo("王五是一個(gè)很牛的人"); friends.add(f1); friends.add(f2); ObjectMapper mapper = new ObjectMapper(); Long t1 = System.currentTimeMillis(); byte[] writeValueAsBytes = null; for (int i = 0; i < 10; i++) { writeValueAsBytes = mapper.writeValueAsBytes(u); } System.out.println("json serialize: " + (System.currentTimeMillis() - t1) + "ms; 總大小:" + writeValueAsBytes.length); Long t2 = System.currentTimeMillis(); User user = mapper.readValue(writeValueAsBytes, User.class); System.out.println("json deserialize: " + (System.currentTimeMillis() - t2) + "ms; User: " + user); } }
運(yùn)行結(jié)果:
json serialize: 55ms; 總大?。?41
json deserialize: 35ms; User: User [userId=null, userName=張三, passWord=123456, userInfo=張三是一個(gè)很牛的人, friends=[User [userId=null, userName=李四, passWord=123456, userInfo=李四是一個(gè)很牛的人, friends=null], User [userId=null, userName=王五, passWord=123456, userInfo=王五是一個(gè)很牛的人, friends=null]]]
3、FastJson序列化
fastjson 是由阿里巴巴開發(fā)的一個(gè)性能很好的Java 語言實(shí)現(xiàn)的 Json解析器和生成器。特點(diǎn):速度快,測(cè)試表明fastjson具有極快的性能,超越任其他的Java json parser。功能強(qiáng)大,完全支持java bean、集合、Map、日期、Enum,支持范型和自省。無依賴,能夠直接運(yùn)行在Java SE 5.0以上版本
支持Android。使用時(shí)候需引入FastJson第三方j(luò)ar包。FastJson序列化代碼示例如下所示:
package serialize; import java.util.ArrayList; import java.util.List; import com.alibaba.fastjson.JSON; /** * * @author liqqc * */ public class FastJsonSerialize { public static void main(String[] args) { new FastJsonSerialize().start(); } public void start(){ User u = new User(); List<User> friends = new ArrayList<>(); u.setUserName("張三"); u.setPassWord("123456"); u.setUserInfo("張三是一個(gè)很牛的人"); u.setFriends(friends); User f1 = new User(); f1.setUserName("李四"); f1.setPassWord("123456"); f1.setUserInfo("李四是一個(gè)很牛的人"); User f2 = new User(); f2.setUserName("王五"); f2.setPassWord("123456"); f2.setUserInfo("王五是一個(gè)很牛的人"); friends.add(f1); friends.add(f2); //序列化 Long t1 = System.currentTimeMillis(); String text = null; for(int i = 0; i<10; i++) { text = JSON.toJSONString(u); } System.out.println("fastJson serialize: " +(System.currentTimeMillis() - t1) + "ms; 總大?。? + text.getBytes().length); //反序列化 Long t2 = System.currentTimeMillis(); User user = JSON.parseObject(text, User.class); System.out.println("fastJson serialize: " + (System.currentTimeMillis() -t2) + "ms; User: " + user); } }
運(yùn)行結(jié)果:
fastJson serialize: 284ms; 總大?。?69
fastJson serialize: 26ms; User: User [userId=null, userName=張三, passWord=123456, userInfo=張三是一個(gè)很牛的人, friends=[User [userId=null, userName=李四, passWord=123456, userInfo=李四是一個(gè)很牛的人, friends=null], User [userId=null, userName=王五, passWord=123456, userInfo=王五是一個(gè)很牛的人, friends=null]]]
4、ProtoBuff序列化
ProtocolBuffer是一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式,可以用于結(jié)構(gòu)化數(shù)據(jù)序列化。適合做數(shù)據(jù)存儲(chǔ)或 RPC 數(shù)據(jù)交換格式??捎糜谕ㄓ崊f(xié)議、數(shù)據(jù)存儲(chǔ)等領(lǐng)域的語言無關(guān)、平臺(tái)無關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)格式。
優(yōu)點(diǎn):跨語言;序列化后數(shù)據(jù)占用空間比JSON小,JSON有一定的格式,在數(shù)據(jù)量上還有可以壓縮的空間。
缺點(diǎn):它以二進(jìn)制的方式存儲(chǔ),無法直接讀取編輯,除非你有 .proto 定義,否則無法直接讀出 Protobuffer的任何內(nèi)容。
其與thrift的對(duì)比:兩者語法類似,都支持版本向后兼容和向前兼容,thrift側(cè)重點(diǎn)是構(gòu)建跨語言的可伸縮的服務(wù),支持的語言多,同時(shí)提供了全套R(shí)PC解決方案,可以很方便的直接構(gòu)建服務(wù),不需要做太多其他的工作。 Protobuffer主要是一種序列化機(jī)制,在數(shù)據(jù)序列化上進(jìn)行性能比較,Protobuffer相對(duì)較好。
ProtoBuff序列化對(duì)象可以很大程度上將其壓縮,可以大大減少數(shù)據(jù)傳輸大小,提高系統(tǒng)性能。對(duì)于大量數(shù)據(jù)的緩存,也可以提高緩存中數(shù)據(jù)存儲(chǔ)量。原始的ProtoBuff需要自己寫.proto文件,通過編譯器將其轉(zhuǎn)換為java文件,顯得比較繁瑣。百度研發(fā)的jprotobuf框架將Google原始的protobuf進(jìn)行了封裝,對(duì)其進(jìn)行簡(jiǎn)化,僅提供序列化和反序列化方法。其實(shí)用上也比較簡(jiǎn)潔,通過對(duì)JavaBean中的字段進(jìn)行注解就行,不需要撰寫.proto文件和實(shí)用編譯器將其生成.java文件,百度的jprotobuf都替我們做了這些事情了。
一個(gè)帶有jprotobuf注解的JavaBean如下所示,如果你想深入學(xué)習(xí)可以參照https://github.com/google/protobuf。
package serialize; import java.io.Serializable; import java.util.List; import com.baidu.bjf.remoting.protobuf.FieldType; import com.baidu.bjf.remoting.protobuf.annotation.Protobuf; public class User implements Serializable { private static final long serialVersionUID = -7890663945232864573L; @Protobuf(fieldType = FieldType.INT32, required = false, order = 1) private Integer userId; @Protobuf(fieldType = FieldType.STRING, required = false, order = 2) private String userName; @Protobuf(fieldType = FieldType.STRING, required = false, order = 3) private String passWord; @Protobuf(fieldType = FieldType.STRING, required = false, order = 4) private String userInfo; @Protobuf(fieldType = FieldType.OBJECT, required = false, order = 5) private List<User> friends; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassWord() { return passWord; } public void setPassWord(String passWord) { this.passWord = passWord; } public String getUserInfo() { return userInfo; } public void setUserInfo(String userInfo) { this.userInfo = userInfo; } public List<User> getFriends() { return friends; } public void setFriends(List<User> friends) { this.friends = friends; } @Override public String toString() { return "User [userId=" + userId + ", userName=" + userName + ", passWord=" + passWord + ", userInfo=" + userInfo + ", friends=" + friends + "]"; } }
jprotobuf序列化代碼示例如下所示:
package serialize; import java.io.IOException; import java.util.ArrayList; import java.util.List; import com.baidu.bjf.remoting.protobuf.Codec; import com.baidu.bjf.remoting.protobuf.ProtobufProxy; /** * * @author liqqc * */ public class ProtoBuffSerialize { public static void main(String[] args) throws IOException { new ProtoBuffSerialize().start(); } public void start() throws IOException { Codec<User> studentClassCodec = ProtobufProxy.create(User.class, false); User u2 = new User(); List<User> friends = new ArrayList<>(); u2.setUserName("張三"); u2.setPassWord("123456"); u2.setUserInfo("張三是一個(gè)很牛的人"); u2.setFriends(friends); User f1 = new User(); f1.setUserName("李四"); f1.setPassWord("123456"); f1.setUserInfo("李四是一個(gè)很牛的人"); User f2 = new User(); f2.setUserName("王五"); f2.setPassWord("123456"); f2.setUserInfo("王五是一個(gè)很牛的人"); friends.add(f1); friends.add(f2); Long stime_jpb_encode = System.currentTimeMillis(); byte[] bytes = null; for(int i = 0; i<10; i++) { bytes = studentClassCodec.encode(u2); } System.out.println("jprotobuf序列化耗時(shí):" + (System.currentTimeMillis() - stime_jpb_encode) + "ms; 總大?。? + bytes.length); Long stime_jpb_decode = System.currentTimeMillis(); User user = studentClassCodec.decode(bytes); Long etime_jpb_decode = System.currentTimeMillis(); System.out.println("jprotobuf反序列化耗時(shí):"+ (etime_jpb_decode-stime_jpb_decode) + "ms; User: " + user); } }
運(yùn)行結(jié)果:
jprotobuf序列化耗時(shí):9ms; 總大小:148
jprotobuf反序列化耗時(shí):0ms; User: User [userId=null, userName=張三, passWord=123456, userInfo=張三是一個(gè)很牛的人, friends=[User [userId=null, userName=李四, passWord=123456, userInfo=李四是一個(gè)很牛的人, friends=null], User [userId=null, userName=王五, passWord=123456, userInfo=王五是一個(gè)很牛的人, friends=null]]]
5、總結(jié)
我們通過Main方法來進(jìn)行對(duì)比測(cè)試,(但是通過測(cè)試發(fā)現(xiàn)少量數(shù)據(jù)無法準(zhǔn)確顯示每種序列化方式的優(yōu)劣,故這里無法給出比較好的答案,僅供參考)。示例代碼如下所示:
package serialize; import java.io.IOException; /** * @author liqqc */ public class Main { public static void main(String[] args) throws IOException, ClassNotFoundException { ProtoBuffSerialize protoBuffSerialize = new ProtoBuffSerialize(); protoBuffSerialize.start(); System.err.println(); System.err.println(); JavaSerialize javaSerialize = new JavaSerialize(); javaSerialize.start(); System.err.println(); JsonSerialize jsonSerialize = new JsonSerialize(); jsonSerialize.start(); System.err.println(); FastJsonSerialize fastJsonSerialize = new FastJsonSerialize(); fastJsonSerialize.start(); } }
運(yùn)行結(jié)果:
jprotobuf序列化耗時(shí):7ms; 總大?。?48
jprotobuf反序列化耗時(shí):0ms
java serialize: 6ms; 總大?。?20
java deserialize: 1ms
json serialize: 37ms; 總大?。?41
json deserialize: 27ms
fastJson serialize: 173ms; 總大?。?69
fastJson serialize: 35ms
上面的測(cè)試僅供參考,并不能代表通過大量數(shù)據(jù)進(jìn)行測(cè)試的結(jié)果??梢园l(fā)現(xiàn):序列化后對(duì)象的所占大小上:protobuff序列化所占總大小是最少的;其次是fastJson序列化;最后是json序列化和java原生序列化。對(duì)于序列化耗時(shí),上面的測(cè)試不準(zhǔn)。
還是去看看專業(yè)測(cè)試分析吧,具體情況可以進(jìn)去看看https://github.com/eishay/jvm-serializers/wiki
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java中transient關(guān)鍵字用法分析
- 說一說java關(guān)鍵字final和transient
- Java中的transient關(guān)鍵字介紹
- Java transient關(guān)鍵字使用小記
- Java transient 關(guān)鍵字詳解及實(shí)例代碼
- java 序列化對(duì)象 serializable 讀寫數(shù)據(jù)的實(shí)例
- 深入理解Java對(duì)象的序列化與反序列化的應(yīng)用
- Java中對(duì)象序列化與反序列化詳解
- Java實(shí)現(xiàn)序列化與反序列化的簡(jiǎn)單示例
- java對(duì)象序列化與反序列化的默認(rèn)格式和json格式使用示例
- Java transient關(guān)鍵字與序列化操作實(shí)例詳解
相關(guān)文章
一個(gè)MIDP俄羅斯方塊游戲的設(shè)計(jì)和實(shí)現(xiàn)
一個(gè)MIDP俄羅斯方塊游戲的設(shè)計(jì)和實(shí)現(xiàn)...2006-12-12使用maven?shade插件解決項(xiàng)目版本沖突詳解
這篇文章主要為大家介紹了使用maven?shade插件解決項(xiàng)目版本沖突詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09使用Idea快速搭建SpringMVC項(xiàng)目的詳細(xì)步驟記錄
這篇文章主要給大家介紹了關(guān)于使用Idea快速搭建SpringMVC項(xiàng)目的詳細(xì)步驟,Spring?MVC是一種基于MVC模式的框架,它是Spring框架的一部分,它提供了一種更簡(jiǎn)單和更有效的方式來構(gòu)建Web應(yīng)用程序,需要的朋友可以參考下2024-05-05Java?通過手寫分布式雪花SnowFlake生成ID方法詳解
SnowFlake是twitter公司內(nèi)部分布式項(xiàng)目采用的ID生成算法,開源后廣受國內(nèi)大廠的好評(píng)。由這種算法生成的ID,我們就叫做SnowFlakeID,下面我們來詳細(xì)看看2022-04-04優(yōu)化Java虛擬機(jī)總結(jié)(jvm調(diào)優(yōu))
這篇文章主要介紹了優(yōu)化Java虛擬機(jī)總結(jié)(jvm調(diào)優(yōu)),具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01