Java序列化


对象、文件、数据,有许多不同的格式,很难统一传输和保存
序列化以后就都是字节流了,无论原来是什么东西,都能变成一样的东西,就可以进行通用的格式传输或保存,传输结束以后,要再次使用,就进行反序列化还原,这样对象还是对象,文件还是文件


序列化可以将内存中的类写入文件或数据库中。比如将某个类序列化后存为文件,下次读取时只需将文件中的数据反序列化就可以将原先的类还原到内存中。也可以将类序列化为流数据进行传输总的来说就是将一个已经实例化的类转成文件存储,下次需要实例化的时候只要反序列化即可将类实例化到内存中并保留序列化时类中的所有变量和状态。
例如:hibernate中实体类的钝化就是将类序列化后存入磁盘并释放内存空间。



1、序列化是干什么的?

  简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。

2、什么情况下需要序列化 

a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;

3、当对一个对象实现序列化时,究竟发生了什么?

在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变量(instance ariable)比如:

Foo myFoo = new Foo(); 
myFoo .setWidth(37); 
myFoo.setHeight(70); 

  当通过下面的代码序列化之后,MyFoo对象中的width和Height实例变量的值(37,70)都被保存到foo.ser文件中,这样以后又可以把它 从文件中读出来,重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等以便恢复原来的对 象。

FileOutputStream fs = new FileOutputStream("foo.ser"); 
ObjectOutputStream os = new ObjectOutputStream(fs); 
os.writeObject(myFoo); 

4、实现序列化(保存到一个文件)的步骤

a)Make a FileOutputStream 
java 代码
FileOutputStream fs = new FileOutputStream("foo.ser"); 
b)Make a ObjectOutputStream 

java 代码
ObjectOutputStream os = new ObjectOutputStream(fs); 
c)write the object

java 代码
os.writeObject(myObject1); 
os.writeObject(myObject2); 
os.writeObject(myObject3); 
d) close the ObjectOutputStream

java 代码
os.close(); 

5、举例说明

java 代码
import java.io.*; 

public class Box implements Serializable 
{ 
private int width; 
private int height; 

public void setWidth(int width){ 
this.width = width; 
} 
public void setHeight(int height){ 
this.height = height; 
} 

public static void main(String[] args){ 
Box myBox = new Box(); 
myBox.setWidth(50); 
myBox.setHeight(30); 

try{ 
FileOutputStream fs = new FileOutputStream("foo.ser"); 
ObjectOutputStream os = new ObjectOutputStream(fs); 
os.writeObject(myBox); 
os.close(); 
}catch(Exception ex){ 
ex.printStackTrace(); 
} 
} 

} 

6、相关注意事项

a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
c)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:

  1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输 等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
  2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分 配,而且,也是没有必要这样实现
 
把一个对象完全转成字节序列,方便传输。
就像你寄一箱饼干,因为体积太大,就全压成粉末紧紧地一包寄出去,这就是序列化的作用。
只不过JAVA的序列化是可以完全还原的。

### 序列化的含义 序列化指将堆内存中的 Java 对象数据,通过某种方式存储到磁盘文件中,或者传递给其他网络节点(网络传输),即将对象转化为二进制,用于保存或网络传输。反序列化则是从 IO 流中恢复对象[^1][^4]。 ### 序列化的意义 序列化机制允许将实现序列化Java 对象转换为字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在[^1]。 ### 序列化的使用场景 所有可在网络上传输的对象都必须是可序列化的,比如 RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的 Java 对象都必须是可序列化的。通常建议程序创建的每个 JavaBean 类都实现 Serializable 接口[^1]。 ### 序列化实现的方式 #### Serializable 接口 - **普通序列化**:实现 Serializable 接口后,可使用 ObjectOutputStream 将对象写入流,使用 ObjectInputStream 从流中读取对象。 ```java import java.io.*; class Person implements Serializable { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } } public class SerializationExample { public static void main(String[] args) { Person person = new Person("John", 30); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) { oos.writeObject(person); } catch (IOException e) { e.printStackTrace(); } try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) { Person deserializedPerson = (Person) ois.readObject(); System.out.println(deserializedPerson.name + " " + deserializedPerson.age); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } } ``` - **成员是引用的序列化**:若类的成员是引用类型,该引用类型也必须是可序列化的,否则当前类无法实现序列化。 - **同一对象序列化多次的机制**:Java 序列化算法会保证同一对象多次序列化时,不会重复序列化对象的内容,而是只记录对象的引用。 - **Java 序列化算法潜在的问题**:例如序列化版本号不匹配、性能问题等。 - **可选的自定义序列化**:可通过实现 `writeObject` 和 `readObject` 方法来自定义序列化和反序列化过程。 #### Externalizable 接口 Externalizable 接口强制自定义序列化,需要实现 `writeExternal` 和 `readExternal` 方法。 ```java import java.io.*; class Employee implements Externalizable { String name; int id; public Employee() {} public Employee(String name, int id) { this.name = name; this.id = id; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeInt(id); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); id = in.readInt(); } } ``` ### 序列化版本号 serialVersionUID serialVersionUID 用于确保序列化和反序列化时类的版本一致性。若没有显式定义 serialVersionUID,Java 会根据类的结构自动生成一个。当类的结构发生变化时,可能会导致 serialVersionUID 改变,从而在反序列化时抛出 `InvalidClassException`。建议显式定义 serialVersionUID。 ```java import java.io.Serializable; class MyClass implements Serializable { private static final long serialVersionUID = 1L; // 类的成员和方法 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值