个性化阅读
专注于IT技术分析

Java中的序列化和反序列化

本文概述

Java中的序列化是一种将对象状态写入字节流的机制。它主要用于Hibernate, RMI, JPA, EJB和JMS技术。

序列化的相反操作称为反序列化, 其中字节流被转换为对象。序列化和反序列化过程与平台无关, 这意味着你可以序列化平台中的对象并在不同平台中反序列化。

对于序列化对象, 我们调用writeObject()方法ObjectOutputStream, 对于反序列化, 我们调用ObjectInputStream类的readObject()方法。

我们必须实现Serializable接口才能序列化对象。

Java序列化的优点

它主要用于在网络上传播对象的状态(称为封送处理)。

Java序列化

java.io.Serializable接口

可序列化是标记接口(没有数据成员和方法)。它用于“标记” Java类, 以便这些类的对象可以具有一定的功能。可克隆和远程也是标记器接口。

它必须由要保留其对象的类实现。

默认情况下, String类和所有包装器类都实现java.io.Serializable接口。

让我们看下面的例子:

import java.io.Serializable;
public class Student implements Serializable{
 int id;
 String name;
 public Student(int id, String name) {
  this.id = id;
  this.name = name;
 }
}

在上面的示例中, Student类实现了Serializable接口。现在可以将其对象转换为流。


ObjectOutputStream类

ObjectOutputStream类用于将原始数据类型和Java对象写入OutputStream。只有支持java.io.Serializable接口的对象才能写入流。

建设者

1)public ObjectOutputStream(OutputStream out)抛出IOException {} 创建一个ObjectOutputStream写入指定的OutputStream。

重要方法

方法 描述
1)公共最终void writeObject(Object obj)引发IOException {} 将指定的对象写入ObjectOutputStream。
2)public void flush()引发IOException {} 刷新当前输出流。
3)public void close()引发IOException {} 关闭当前输出流。

ObjectInputStream类

ObjectInputStream反序列化使用ObjectOutputStream编写的对象和原始数据。

建设者

1)public ObjectInputStream(InputStream in)引发IOException {} 创建一个ObjectInputStream, 它从指定的InputStream读取。

重要方法

方法 描述
1)公共最终对象readObject()引发IOException, ClassNotFoundException {} 从输入流中读取一个对象。
2)public void close()引发IOException {} closes ObjectInputStream.

Java序列化示例

在此示例中, 我们将序列化Student类的对象。 ObjectOutputStream类的writeObject()方法提供了序列化对象的功能。我们将对象的状态保存在名为f.txt的文件中。

import java.io.*;
class Persist{
 public static void main(String args[]){
  try{
  //Creating the object
  Student s1 =new Student(211, "ravi");
  //Creating stream and writing the object
  FileOutputStream fout=new FileOutputStream("f.txt");
  ObjectOutputStream out=new ObjectOutputStream(fout);
  out.writeObject(s1);
  out.flush();
  //closing the stream
  out.close();
  System.out.println("success");
  }catch(Exception e){System.out.println(e);}
 }
}
success

Java反序列化的示例

反序列化是从序列化状态重建对象的过程。这是序列化的反向操作。让我们看一个示例, 该示例从反序列化的对象读取数据。

import java.io.*;
class Depersist{
 public static void main(String args[]){
  try{
  //Creating stream to read the object
  ObjectInputStream in=new ObjectInputStream(new FileInputStream("f.txt"));
  Student s=(Student)in.readObject();
  //printing the data of the serialized object
  System.out.println(s.id+" "+s.name);
  //closing the stream
  in.close();
  }catch(Exception e){System.out.println(e);}
 }
}
211 ravi

具有继承的Java序列化(IS-A关系)

如果一个类实现可序列化, 则其所有子类也将可序列化。让我们看下面的例子:

import java.io.Serializable;
class Person implements Serializable{
 int id;
 String name;
 Person(int id, String name) {
  this.id = id;
  this.name = name;
 }
}
class Student extends Person{
 String course;
 int fee;
 public Student(int id, String name, String course, int fee) {
  super(id, name);
  this.course=course;
  this.fee=fee;
 }
}

现在, 你可以序列化扩展了可序列化的Person类的Student类对象。父类属性是继承给子类的, 因此, 如果父类是可序列化的, 则子类也可以。


带有集成的Java序列化(HAS-A关系)

如果一个类具有对另一个类的引用, 则所有引用都必须是可序列化的, 否则将不执行序列化过程。在这种情况下, NotSerializableException将在运行时引发。

class Address{
 String addressLine, city, state;
 public Address(String addressLine, String city, String state) {
  this.addressLine=addressLine;
  this.city=city;
  this.state=state;
 }
}
import java.io.Serializable;
public class Student implements Serializable{
 int id;
 String name;
 Address address;//HAS-A
 public Student(int id, String name) {
  this.id = id;
  this.name = name;
 }
}

由于地址不可序列化, 因此无法序列化Student类的实例。

注意:对象中的所有对象必须可序列化。


使用静态数据成员的Java序列化

如果类中有任何静态数据成员, 则不会被序列化, 因为static是类而非对象的一部分。

class Employee implements Serializable{
 int id;
 String name;
 static String company="SSS IT Pvt Ltd";//it won't be serialized
 public Student(int id, String name) {
  this.id = id;
  this.name = name;
 }
}

具有数组或集合的Java序列化

规则:对于数组或集合, 数组或集合的所有对象必须可序列化。如果任何对象不可序列化, 则序列化将失败。


用Java可外部化

Externalizable接口提供了以压缩格式将对象的状态写入字节流的便利。它不是标记界面。

Externalizable接口提供两种方法:

  • 公共无效writeExternal(ObjectOutput out)引发IOException
  • 公共无效readExternal(ObjectInput in)引发IOException

Java瞬态关键字

如果你不想序列化类的任何数据成员, 则可以将其标记为瞬态。

class Employee implements Serializable{
 transient int id;
 String name;
 public Student(int id, String name) {
  this.id = id;
  this.name = name;
 }
}

现在, id不会被序列化, 因此在序列化后反序列化对象时, 将不会获得id的值。它将始终返回默认值。在这种情况下, 它将返回0, 因为id的数据类型是整数。

请访问下一页以获取更多详细信息。


SerialVersionUID

运行时的序列化过程将一个ID与每个Serializable类相关联, 该类称为SerialVersionUID。它用于验证序列化对象的发送者和接收者。发送者和接收者必须相同。要验证它, 使用SerialVersionUID。发送方和接收方必须具有相同的SerialVersionUID, 否则, 在反序列化对象时将抛出InvalidClassException。我们还可以在Serializable类中声明我们自己的SerialVersionUID。为此, 你需要创建一个字段SerialVersionUID并为其分配一个值。它必须是带有static和final的long类型。建议在类中显式声明serialVersionUID字段, 并将其也设为私有。例如:

private static final long serialVersionUID=1L;

现在, Serializable类将如下所示:

import java.io.Serializable;
class Employee implements Serializable{
 private static final long serialVersionUID=1L;
 int id;
 String name;
 public Student(int id, String name) {
  this.id = id;
  this.name = name;
 }
}
赞(0)
未经允许不得转载:srcmini » Java中的序列化和反序列化

评论 抢沙发

评论前必须登录!