A. java中對象序列化與反序列化的幾種形式及各自的特點
這項技術主要應用於RMI(對象作為參數遠程傳遞及返回)和JavaBeans中。 Java中還提供了XMLEncoder和XMDecoder類來將JavaBeans對象序列化到XML文件,但是此種方法有諸多不便對Java類有很多限制(要滿足get/set方法等等,否則可能丟失該屬性值)。一個很強大的開源工具XStream,也能夠將對象保存到一個XML文件,並能從中恢復而且沒有那麼多限制。將XML作為一種進行對象傳遞的公共數據格式實現跨平台的進程通信。序列化和反序列化機制的強大在於能夠自動處理序列化對象之間的復雜關系(對象之間的相互引用,形成了復雜的對象網,因此要保證這種關系准確無誤的存儲起來。)。通過反序列化獲取對象的方式可以達到深度克隆對象一樣的效果,當然在性能上肯定有較大損失。
B. 關於java的序列化
那要看這個類的成員是啥樣的,如果存在private成員那就沒法處理了,protected和public成員可以通過繼承讀出,但多個類時就要繼承出多個,也可通過反射機制讀出,反射機制可對多個類統一處理,
C. java中關於對象序列化和反序列化的問題!
這項技術主要應用於RMI(對象作為參數遠程傳遞及返回)和JavaBeans中。
Java中還提供了XMLEncoder和XMDecoder類來將JavaBeans對象序列化到XML文件,但是此種方法有諸多不便對Java類有很多限制(要滿足get/set方法等等,否則可能丟失該屬性值)。一個很強大的開源工具XStream,也能夠將對象保存到一個XML文件,並能從中恢復而且沒有那麼多限制。將XML作為一種進行對象傳遞的公共數據格式實現跨平台的進程通信。序列化和反序列化機制的強大在於能夠自動處理序列化對象之間的復雜關系(對象之間的相互引用,形成了復雜的對象網,因此要保證這種關系准確無誤的存儲起來。)。通過反序列化獲取對象的方式可以達到深度克隆對象一樣的效果,當然在性能上肯定有較大損失。
滿意請採納。
D. java反序列化工具有哪些
json,dom4j
E. 幾種Java序列化 對比
在java中socket傳輸數據時,數據類型往往比較難選擇。可能要考慮帶寬、跨語言、版本的兼容等問題。比較常見的做法有兩種:一是把對象包裝成JSON字元串傳輸,二是採用java對象的序列化和反序列化。隨著Google工具protoBuf的開源,protobuf也是個不錯的選擇。對JSON,Object Serialize,ProtoBuf 做個對比。
定義一個待傳輸的對象UserVo:
Java代碼
public class User{
private String name;
private int age;
private long phone;
private List<User> friends;
}
初始化User的實例src:
Java代碼
User user1 = new UserVo();
user1 .setName("user1 ");
user1 .setAge(30);
user1 .setPhone(13789126278L);
UserVo f1 = new UserVo();
f1.setName("tmac");
f1.setAge(32);
f1.setPhone(123L);
User user2 = new User();
user2 .setName("user2 ");
user2 .setAge(29);
user2 .setPhone(123L);
List<User> friends = new ArrayList<User>();
friends.add(user1 );
friends.add(user2 );
user1 .setFriends(friends);
JSON格式
採用Google的gson-2.2.2.jar 進行轉義
Java代碼
Gson gson = new Gson();
String json = gson.toJson(src);
得到的字元串:
Js代碼
{"name":"user1 ","age":30,"phone":123,"friends":[{"name":"user1 ","age":32,"phone":123},{"name":"user2 ","age":29,"phone":123}]}
位元組數為153
Json的優點:明文結構一目瞭然,可以跨語言,屬性的增加減少對解析端影響較小。缺點:位元組數過多,依賴於不同的第三方類庫。
Object Serialize
UserVo實現Serializalbe介面,提供唯一的版本號:
Java代碼
public class User implements Serializable{
private static final long serialVersionUID = -5726374138698742258L;
private String name;
private int age;
private long phone;
private List<User> friends;
序列化方法:
Java代碼
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(src);
os.flush();
os.close();
byte[] b = bos.toByteArray();
bos.close();
位元組數是238
反序列化:
Java代碼
ObjectInputStream ois = new ObjectInputStream(fis);
vo = (UserVo) ois.readObject();
ois.close();
fis.close();
Object Serializalbe 優點:java原生支持,不需要提供第三方的類庫,使用比較簡單。缺點:無法跨語言,位元組數佔用比較大,某些情況下對於對象屬性的變化比較敏感。
對象在進行序列化和反序列化的時候,必須實現Serializable介面,但並不強制聲明唯一的serialVersionUID
是否聲明serialVersionUID對於對象序列化的向上向下的兼容性有很大的影響。我們來做個測試:
思路一
把User中的serialVersionUID去掉,序列化保存。反序列化的時候,增加或減少個欄位,看是否成功。
Java代碼
public class User implements Serializable{
private String name;
private int age;
private long phone;
private List<UserVo> friends;
保存到文件中:
Java代碼
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(src);
os.flush();
os.close();
byte[] b = bos.toByteArray();
bos.close();
FileOutputStream fos = new FileOutputStream(dataFile);
fos.write(b);
fos.close();
增加或者減少欄位後,從文件中讀出來,反序列化:
Java代碼
FileInputStream fis = new FileInputStream(dataFile);
ObjectInputStream ois = new ObjectInputStream(fis);
vo = (User) ois.readObject();
ois.close();
fis.close();
結果:拋出異常信息
Java代碼
Exception in thread "main" java.io.InvalidClassException: serialize.obj.UserVo; local class incompatible: stream classdesc serialVersionUID = 3305402508581390189, local class serialVersionUID = 7174371419787432394
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:560)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at serialize.obj.ObjectSerialize.read(ObjectSerialize.java:74)
at serialize.obj.ObjectSerialize.main(ObjectSerialize.java:27)
思路二
eclipse指定生成一個serialVersionUID,序列化保存,修改欄位後反序列化
略去代碼
結果:反序列化成功
結論
如果沒有明確指定serialVersionUID,序列化的時候會根據欄位和特定的演算法生成一個serialVersionUID,當屬性有變化時這個id發生了變化,所以反序列化的時候就會失敗。拋出「本地classd的唯一id和流中class的唯一id不匹配」。
jdk文檔關於serialVersionUID的描述:
寫道
如果可序列化類未顯式聲明 serialVersionUID,則序列化運行時將基於該類的各個方面計算該類的默認 serialVersionUID 值,如「Java(TM) 對象序列化規范」中所述。不過,強烈建議 所有可序列化類都顯式聲明 serialVersionUID 值,原因是計算默認的 serialVersionUID 對類的詳細信息具有較高的敏感性,根據編譯器實現的不同可能千差萬別,這樣在反序列化過程中可能會導致意外的 InvalidClassException。因此,為保證 serialVersionUID 值跨不同 java 編譯器實現的一致性,序列化類必須聲明一個明確的 serialVersionUID 值。還強烈建議使用 private 修飾符顯示聲明 serialVersionUID(如果可能),原因是這種聲明僅應用於直接聲明類 -- serialVersionUID 欄位作為繼承成員沒有用處。數組類不能聲明一個明確的 serialVersionUID,因此它們總是具有默認的計算值,但是數組類沒有匹配 serialVersionUID 值的要求。
Google ProtoBuf
protocol buffers 是google內部得一種傳輸協議,目前項目已經開源(http://code.google.com/p/protobuf/)。它定義了一種緊湊得可擴展得二進制協議格式,適合網路傳輸,並且針對多個語言有不同得版本可供選擇。
以protobuf-2.5.0rc1為例,准備工作:
下載源碼,解壓,編譯,安裝
Shell代碼
tar zxvf protobuf-2.5.0rc1.tar.gz
./configure
./make
./make install
測試:
Shell代碼
MacBook-Air:~ ming$ protoc --version
libprotoc 2.5.0
安裝成功!進入源碼得java目錄,用mvn工具編譯生成所需得jar包,protobuf-java-2.5.0rc1.jar
1、編寫.proto文件,命名UserVo.proto
Text代碼
package serialize;
option java_package = "serialize";
option java_outer_classname="UserVoProtos";
message User{
optional string name = 1;
optional int32 age = 2;
optional int64 phone = 3;
repeated serialize.UserVo friends = 4;
}
2、在命令行利用protoc 工具生成builder類
Shell代碼
protoc -IPATH=.proto文件所在得目錄 --java_out=java文件的輸出路徑 .proto的名稱
得到UserProtos類
3、編寫序列化代碼
Java代碼
UserVoProtos.User.Builder builder = UserVoProtos.User.newBuilder();
builder.setName("Yaoming");
builder.setAge(30);
builder.setPhone(13789878978L);
UserVoProtos.UserVo.Builder builder1 = UserVoProtos.UserVo.newBuilder();
builder1.setName("tmac");
builder1.setAge(32);
builder1.setPhone(138999898989L);
UserVoProtos.UserVo.Builder builder2 = UserVoProtos.UserVo.newBuilder();
builder2.setName("liuwei");
builder2.setAge(29);
builder2.setPhone(138999899989L);
builder.addFriends(builder1);
builder.addFriends(builder2);
UserVoProtos.UserVo vo = builder.build();
byte[] v = vo.toByteArray();
位元組數53
4、反序列化
Java代碼
UserVoProtos.UserVo uvo = UserVoProtos.UserVo.parseFrom(dstb);
System.out.println(uvo.getFriends(0).getName());
結果:tmac,反序列化成功
google protobuf 優點:位元組數很小,適合網路傳輸節省io,跨語言 。缺點:需要依賴於工具生成代碼。
工作機制
proto文件是對數據的一個描述,包括欄位名稱,類型,位元組中的位置。protoc工具讀取proto文件生成對應builder代碼的類庫。protoc xxxxx --java_out=xxxxxx 生成java類庫。builder類根據自己的演算法把數據序列化成位元組流,或者把位元組流根據反射的原理反序列化成對象。官方的示例:https://developers.google.com/protocol-buffers/docs/javatutorial。
proto文件中的欄位類型和java中的對應關系:
詳見:https://developers.google.com/protocol-buffers/docs/proto
.proto Type java Type c++ Type
double double double
float float float
int32 int int32
int64 long int64
uint32 int uint32
unint64 long uint64
sint32 int int32
sint64 long int64
fixed32 int uint32
fixed64 long uint64
sfixed32 int int32
sfixed64 long int64
bool boolean bool
string String string
bytes byte string
欄位屬性的描述:
寫道
required: a well-formed message must have exactly one of this field.
optional: a well-formed message can have zero or one of this field (but not more than one).
repeated: this field can be repeated any number of times (including zero) in a well-formed message. The order of the repeated values will be preserved.
protobuf 在序列化和反序列化的時候,是依賴於.proto文件生成的builder類完成,欄位的變化如果不表現在.proto文件中就不會影響反序列化,比較適合欄位變化的情況。做個測試:
把UserVo序列化到文件中:
Java代碼
UserProtos.User vo = builder.build();
byte[] v = vo.toByteArray();
FileOutputStream fos = new FileOutputStream(dataFile);
fos.write(vo.toByteArray());
fos.close();
為User增加欄位,對應的.proto文件:
Text代碼
package serialize;
option java_package = "serialize";
option java_outer_classname="UserVoProtos";
message User{
optional string name = 1;
optional int32 age = 2;
optional int64 phone = 3;
repeated serialize.UserVo friends = 4;
optional string address = 5;
}
從文件中反序列化回來:
Java代碼
FileInputStream fis = new FileInputStream(dataFile);
byte[] dstb = new byte[fis.available()];
for(int i=0;i<dstb.length;i++){
dstb[i] = (byte)fis.read();
}
fis.close();
UserProtos.User uvo = UserProtos.User.parseFrom(dstb);
System.out.println(uvo.getFriends(0).getName());
成功得到結果。
三種方式對比傳輸同樣的數據,google protobuf只有53個位元組是最少的。結論:
方式 優點 缺點
JSON 跨語言、格式清晰一目瞭然
位元組數比較大,需要第三方類庫
Object Serialize java原生方法不依賴外部類庫 位元組數比較大,不能跨語言
Google protobuf 跨語言、位元組數比較少
編寫.proto配置用protoc工具生成對應的代碼
F. 怎樣做才能讓Java 序列化機制 更安全
Java 序列化 serialization主要職責就是將一個對象的狀態轉化為一個位元組序列,以方便對象的持久化或網路傳輸。反序列化的過程正好相反。開發人員所要做的只是實現Serializable介面,然後調用ObjectOutputStream/ObjectInputStream的WriteObject/ReadObject方法即可,其他的工作 JVM會自動幫你做了。
那通過實現Serializable 介面所獲取的序列化能力是否有安全隱患?由於這些位元組序列已經脫離了Java的安全體系存在於磁碟或網路上,我們能否對序列化後的位元組序列進行查看和修改,甚至於注入惡意病毒呢? Java 反序列化機制是否又會對建立的對象進行驗證以確保它的安全性、准確性呢? 如果你想到這些問題,那恐怕答案會讓你失望了。Java序列化後的位元組序列基本都是明文存在的,而且位元組序列的組成有很明確的文檔進行說明,你可以試著用一些十六進制的文本編輯工具,如Hexeditor 查看一下對象序列化後的內容,你都能看到很多私有變數的實際賦值。關於位元組序列的說明,可參考對象序列化流協議 ,這里就不多說了。這篇文章的重點是說一些Java提供的安全機制,通過這些機制,我們能夠提升序列化/反序列化的安全指數。
G. Java jsontools 序列化問題
讓變數transient。
//不讓變數j序列化
transient Set sets;
不知道是不是你想要的答案
H. 為什麼說Java的序列化不適合Hadoop
java序列化很全面, 包含所有類的信息, 但是這樣的代價就是導致序列化後的對象佔用很大的空間, 而hadoop這樣的大數據的運算會將這種代價放大, 所以會採用一些比較簡單模式對對象的內容進行描述, 比如 avro這樣的序列化工具, 只包含對象中的信息就可以了。
I. java反序列化終極測試工具怎麼用
Java反序列化終極測試工具是一款檢測java反序列化漏洞工具,直接將Jboss、Websphere和weblogic的反序列化漏洞的利用集成到了一起。
J. java反序列化漏洞工具怎麼使用
反序列化顧名思義就是用二進制的形式來生成文件,由於common-collections.jar幾乎在所有項目里都會被用到,所以當這個漏洞被發現並在這個jar包內實現攻擊時,幾乎影響了一大批的項目,weblogic的中槍立刻提升了這個漏洞的等級(對weblogic不熟悉的可以網路)。
至於如何使用這個漏洞對系統發起攻擊,舉一個簡單的例子,我通過本地java程序將一個帶有後門漏洞的jsp(一般來說這個jsp里的代碼會是文件上傳和網頁版的SHELL)序列化,將序列化後的二進制流發送給有這個漏洞的伺服器,伺服器會自動根據流反序列化的結果生成文件,然後就可以大搖大擺的直接訪問這個生成的JSP文件把伺服器當後花園了。
如果Java應用對用戶輸入,即不可信數據做了反序列化處理,那麼攻擊者可以通過構造惡意輸入,讓反序列化產生非預期的對象,非預期的對象在產生過程中就有可能帶來任意代碼執行。
所以這個問題的根源在於類ObjectInputStream在反序列化時,沒有對生成的對象的類型做限制;假若反序列化可以設置Java類型的白名單,那麼問題的影響就小了很多。