深入探索Java对象的序列化
Android IT:
对象序列化就是把对象写入到输出流中,用来存储或者传输。
对象的反序列化就是从输入流中读取对象。
要序列化的对象应该实现Serializable接口。
Serializable接口是一个标识接口,没有抽象方法。
Serializable有一个子接口Externalizable,实现Externalizable接口的类可以自行控制对象序列化荷反序列化过程。
一般来说,没有必要自己实现序列化接口,直接交给Java虚拟机是上策。
实现了序列化接口的类,如果其成员不需要序列化进去,则使用transient关键字进行修饰。
下面给出个例子:
import java.io.*;
/**
* Java对象的序列化测试
* File: ObjectStreamTest.java
* User: leizhimin
* Date: 2008-3-12 20:41:43
*/
public class ObjectStreamTest {
public static void main(String args[]) {
testObjectSeri();
testObjectInSeri();
}
/**
* 对象序列化测试
*/
public static void testObjectSeri() {
Person person = new Person("熔岩", "341022225562156", "lavasoft");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream("Q:\\study\\java5study\\src\\io\\person.dat");
oos = new ObjectOutputStream(fos);
oos.writeObject(person);
} catch (FileNotFoundException e) {
System.out.println("找不到指定的文件!");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 对象反序列化测试
*/
public static void testObjectInSeri() {
FileInputStream fis = null;
ObjectInputStream ois = null;
Person person = null;
try {
fis = new FileInputStream("Q:\\study\\java5study\\src\\io\\person.dat");
ois = new ObjectInputStream(fis);
person = (Person) ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(person.toString());
}
}
/**
* 测试序列化所用的类
*/
class Person implements Serializable {
private String username;
private String cardNumber;
private transient String password;
public Person(String username, String cardNumber, String password) {
this.username = username;
this.cardNumber = cardNumber;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String toString() {
StringBuffer sb = new StringBuffer(this.getClass().getName());
sb.append("[");
sb.append("\n\t");
sb.append("username=" + this.username);
sb.append("\n\t");
sb.append("cardNumber=" + this.cardNumber);
sb.append("\n\t");
sb.append("password=" + this.password);
sb.append("]");
return sb.toString();
}
}
运行结果为:
io.Person[
username=熔岩
cardNumber=341022225562156
password=null]
Process finished with exit code 0
属性password=null,说明在序列化过程中忽略了。
说到此,还有一个容易忽略的问题--serialVersionUID :
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修改器显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于立即声明类 -- serialVersionUID 字段作为继承成员没有用处。
serialVersionUID 在Eclipse里可以自动生成,可是在其他大部分IDE工具里面都不能自动生成。但是这个long型值取多少,心里没底,与其写还不如不写。
分享到:
相关推荐
### Java序列化与反序列化的深入解析 #### Java序列化的重要性及应用场景 Java序列化是一项核心功能,它允许程序员将对象的状态转化为字节流的形式,从而实现对象的持久化存储或者在网络之间进行传递。这对于诸如...
为了将可序列化的对象序列化到文件或其他存储介质中,需要使用 `java.io.ObjectOutputStream` 和 `java.io.ObjectInputStream` 类。以下是一个简单的序列化示例: ```java import java.io.*; public class ...
用户可以编写.proto文件,定义消息类型,然后编译成各种目标语言(如C++、Java或Python)的类,这些类可以用于序列化和反序列化数据。 在处理Proto文件时,序列化意味着将根据.proto文件定义的消息实例转换为二进制...
### 基于JSON的对象序列化算法 #### 摘要 随着Web应用程序系统的不断发展,XML作为数据交换格式被广泛采用,特别是在基于Ajax(异步JavaScript和XML)的技术框架下。然而,作为一种结构化的文档,XML在服务器端与...
1. 实现一个简单的Java或Python程序,序列化一个包含嵌套对象的复杂数据结构,并将其保存到磁盘。 2. 使用不同的序列化库(如pickle和json)对比Python对象的序列化和反序列化效果。 3. 考虑安全问题,编写一个防范...
Serializable是Java提供的一个标准序列化接口,任何实现了此接口的类的对象都可以被序列化。序列化过程通过`ObjectOutputStream`的`writeObject()`方法实现,反序列化则通过`ObjectInputStream`的`readObject()`完成...
1. **忽略未知字段**:在反序列化时,如果JSON中存在Java对象中没有的字段,可以设置忽略这些字段,避免抛出异常。 ```java mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); ``` 2. ...
Java序列化则用于持久化对象,它是网络传输和跨进程通信的重要手段。 除此之外,你还需要关注Java并发编程,理解线程同步、锁机制,以及并发容器如ConcurrentHashMap的使用。Java集合框架的深入理解,如ArrayList、...
反序列化是将从磁盘或网络中读取的序列化数据转换回内存中的对象的过程。在Java中,这一过程涉及到`java.io.Serializable`接口以及常见的库如fastjson、jackson和gson。 反序列化漏洞通常发生在以下两个关键命题中...
3. 探索UML的序列图和协作图,理解Java中的对象间交互和消息传递。 4. 学习如何将UML状态图应用于Java中的对象生命周期,以描述对象在不同条件下的行为变化。 5. 了解如何使用UML活动图来表示复杂的业务流程或算法,...
Java中的json-lib库是处理JSON数据的一个常用工具,它提供了将Java对象转换为JSON字符串以及从JSON字符串反序列化回Java对象的功能。然而,在处理复杂的嵌套数据结构时,如果不小心可能会导致无限循环的问题。 在...
这一部分介绍Java的I/O流系统,包括文件读写、对象序列化以及网络I/O。学生将学习使用FileReader、FileWriter以及BufferedReader、BufferedWriter等类进行文件操作,同时也将接触Socket编程的基础知识。 第六章:...
包括字节流、字符流、缓冲流、对象序列化等,这对于数据持久化和文件操作至关重要。 10. **第15章:JDBC连接数据库** JDBC(Java Database Connectivity)是Java访问数据库的标准API。这一章将介绍如何使用JDBC...
本课程将引导学习者从基础到高级,逐步探索Java的世界,为他们提供在实际开发环境中运用Java所需的知识和技能。 1. **Java概述**: Java是一种跨平台、面向对象的编程语言,由Sun Microsystems(现已被Oracle收购...
5. **序列化**:序列化是将对象的状态转化为字节流的过程,便于存储和网络传输。了解Serializable接口,掌握如何实现序列化和反序列化,以及理解ObjectInputStream和ObjectOutputStream的使用,对于数据持久化和远程...
在聊天程序中,可能需要将用户的聊天消息序列化后再发送,服务器端接收到字节流后进行反序列化恢复原对象。 在源码中,`ObjectOutputStream`和`ObjectInputStream`用于对象的序列化和反序列化。例如: ```java // ...
而JAXB(Java Architecture for XML Binding)是Java提供的一种标准API,它允许我们轻松地在Java对象(javabean)和XML文档之间进行转换。通过JAXB,开发者可以避免手动编写XML解析和序列化代码,极大地提高了开发...