下面和大家分享的是java序列化的一些基础知识,希望能够带给大家帮助。
1 Java 序列化技术概述
Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方
把该Byte 流里的数据读出来。重新构造一个相同的对象。这种机制允许你将对象通过网络
进行传播,并可以随时把对象持久化到数据库、文件等系统里。Java的序列化机制是RMI、
EJB、JNNI等技术的技术基础。
1.1 序列化技术基础
并非所有的Java 类都可以序列化,为了使你指定的类可以实现序列化,你必须使该类
实现如下接口:
java.io.Serializable
需要注意的是,该接口什么方法也没有。实现该类只是简单的标记你的类准备支持序列
化功能。我们来看如下的代码:
/**
* 抽象基本类,完成一些基本的定义
*/
public abstract class Humanoid
{
protected int noOfHeads;
private static int totalHeads;
public Humanoid()
{
this(1);
}
public Humanoid(int noOfHeads)
{
如何正确的使用Java序列化技术 技术研究系列
if (noOfHeads > 10)
throw new Error("Be serious. More than 10 heads?!");
this.noOfHeads = noOfHeads;
synchronized (Humanoid.class)
{
totalHeads += noOfHeads;
}
}
public int getHeadCount()
{
return totalHeads;
}
}
该类的一个子类如下:
/**
* Humanoid的实现类,实现了序列化接口
*/
import java.io.*;
public class Person extends Humanoid
implements java.io.Serializable
{
private String lastName;
private String firstName;
private transient Thread workerThread;
private static int population;
public Person(String lastName, String firstName)
{
this.lastName = lastName;
this.firstName = firstName;
synchronized (Person.class)
{
population++;
}
}
public String toString()
{
return "Person " + firstName + " " + lastName;
}
static synchronized public int getPopulation()
{
return population;
}
}
1.2 对象的序列化及反序列化
上面的类Person 类实现了Serializable 接口,因此是可以序列化的。我们如果要把一个
可以序列化的对象序列化到文件里或者数据库里,需要下面的类的支持:
java.io.ObjectOutputStream
如何正确的使用Java序列化技术 技术研究系列
下面的代码负责完成Person类的序列化操作:
/**
* Person的序列化类,通过该类把Person写入文件系统里。
*/
import java.io.*;
public class WriteInstance
{
public static void main(String [] args) throws Exception
{
if (args.length != 1)
{
System.out.println("usage: java WriteInstance file");
System.exit(-1);
}
FileOutputStream fos = new FileOutputStream(args[0]);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person p = new Person("gaoyanbing", "haiger");
oos.writeObject(p);
}
}
如果我们要序列化的类其实是不能序列化的,则对其进行序列化时会抛出下面的异常:
java.io.NotSerializableException
当我们把Person 序列化到一个文件里以后,如果需要从文件中恢复Person 这个对象,
我们需要借助如下的类:
java.io.ObjectInputStream
从文件里把Person类反序列化的代码实现如下:
/**
* Person的反序列化类,通过该类从文件系统中读出序列化的数据,并构造一个
* Person对象。
*/
import java.io.*;
public class ReadInstance
{
public static void main(String [] args) throws Exception
{
if (args.length != 1)
{
System.out.println("usage: java ReadInstance filename");
System.exit(-1);
}
FileInputStream fis = new FileInputStream(args[0]);
ObjectInputStream ois = new ObjectInputStream(fis);
Object o = ois.readObject();
如何正确的使用Java序列化技术 技术研究系列
System.out.println("read object " + o);
}
}
1.3 序列化对类的处理原则
并不是一个实现了序列化接口的类的所有字段及属性都是可以序列化的。我们分为以下
几个部分来说明:
u 如果该类有父类,则分两种情况来考虑,如果该父类已经实现了可序列化接口。则
其父类的相应字段及属性的处理和该类相同;如果该类的父类没有实现可序列化接
口,则该类的父类所有的字段属性将不会序列化。
u 如果该类的某个属性标识为static类型的,则该属性不能序列化;
u 如果该类的某个属性采用transient关键字标识,则该属性不能序列化;
需要注意的是,在我们标注一个类可以序列化的时候,其以下属性应该设置为transient
来避免序列化:
u 线程相关的属性;
u 需要访问IO、本地资源、网络资源等的属性;
u 没有实现可序列化接口的属性;(注:如果一个属性没有实现可序列化,而我们又
没有将其用transient 标识, 则在对象序列化的时候, 会抛出
java.io.NotSerializableException 异常)。
1.4 构造函数和序列化
对于父类的处理,如果父类没有实现序列化接口,则其必须有默认的构造函数(即没有
参数的构造函数)。为什么要这样规定呢?我们来看实际的例子。仍然采用上面的Humanoid
和Person 类。我们在其构造函数里分别加上输出语句:
/**
* 抽象基本类,完成一些基本的定义
*/
public abstract class Humanoid
{
protected int noOfHeads;
private static int totalHeads;
public Humanoid()
{
this(1);
System.out.println("Human's default constructor is invoked");
}
public Humanoid(int noOfHeads)
{
if (noOfHeads > 10)
throw new Error("Be serious. More than 10 heads?!");
如何正确的使用Java序列化技术 技术研究系列
this.noOfHeads = noOfHeads;
synchronized (Humanoid.class)
{
totalHeads += noOfHeads;
}
}
public int getHeadCount()
{
return totalHeads;
}
}
/**
* Humanoid的实现类,实现了序列化接口
*/
import java.io.*;
public class Person extends Humanoid
implements java.io.Serializable
{
private String lastName;
private String firstName;
private transient Thread workerThread;
private static int population;
public Person(String lastName, String firstName)
{
this.lastName = lastName;
this.firstName = firstName;
synchronized (Person.class)
{
population++;
}
System.out.println("Person's constructor is invoked");
}
public String toString()
{
return "Person " + firstName + " " + lastName;
}
static synchronized public int getPopulation()
{
return population;
}
}
在命令行运行其序列化程序和反序列化程序的结果为:
如何正确的使用Java序列化技术 技术研究系列
可以看到,在从流中读出数据构造Person对象的时候,Person 的父类Humanoid的默认
构造函数被调用了。当然,这点完全不用担心,如果你没有给父类一个默认构造函数,则编
译的时候就会报错。
这里,我们把父类Humanoid做如下的修改:
/**
* 抽象基本类,完成一些基本的定义
*/
public class Humanoid implements java.io.Serializable
{
protected int noOfHeads;
private static int totalHeads;
public Humanoid()
{
this(1);
System.out.println("Human's default constructor is invoked");
}
public Humanoid(int noOfHeads)
{
if (noOfHeads > 10)
throw new Error("Be serious. More than 10 heads?!");
this.noOfHeads = noOfHeads;
synchronized (Humanoid.class)
{
totalHeads += noOfHeads;
}
}
public int getHeadCount()
{
return totalHeads;
}
}
我们把父类标记为可以序列化, 再来看运行的结果:
如何正确的使用Java序列化技术 技术研究系列
可以看到,在反序列化的时候,如果父类也是可序列化的话,则其默认构造函数也不会
调用。这是为什么呢?
这是因为Java 对序列化的对象进行反序列化的时候,直接从流里获取其对象数据来生
成一个对象实例,而不是通过其构造函数来完成,毕竟我们的可序列化的类可能有多个构造
函数,如果我们的可序列化的类没有默认的构造函数,反序列化机制并不知道要调用哪个构
造函数才是正确的。
1.5 序列化带来的问题
我们可以看到上面的例子,在Person 类里,其字段population 很明显是想跟踪在一个
JVM里Person类有多少实例,这个字段在其构造函数里完成赋值,当我们在同一个JVM 里
序列化Person 并反序列化时,因为反序列化的时候Person 的构造函数并没有被调用,所以
这种机制并不能保证正确获取Person在一个JVM的实例个数,在后面的部分我们将要详细
探讨这个问题及给出比较好的解
分享到:
相关推荐
Java 序列化和反序列化是 Java 语言中的一种机制,用于将对象转换为字节流,以便在网络上传输或存储。序列化是将对象转换为字节流的过程,而反序列化是将字节流转换回对象的过程。 在 Java 中,序列化和反序列化是...
Java序列化是Java平台中的一种持久化机制,它允许对象的状态被转换成字节流,以便存储、网络传输或在不同时间点恢复。这个过程被称为序列化,而反向操作称为反序列化。序列化在许多场景下都非常有用,比如在分布式...
Java序列化是Java平台中的一种标准机制,允许将对象的状态转换为字节流,以便存储在磁盘上、通过网络进行传输或者在某些时候恢复原来的对象状态。这一过程包括两个主要步骤:对象的序列化(将对象转换为字节流)和反...
Protocol Buffer(简称PB)是Google开发的一种高效的数据序列化协议,而Java序列化是Java平台内置的一种序列化机制。两者的主要目标都是将对象转化为字节数组,便于在网络传输、持久化存储等场景中使用。然而,它们...
Java反序列化是一种将已序列化的对象状态转换回对象的过程,它是Java平台中持久化数据的一种常见方式。在Java应用程序中,序列化用于保存对象的状态以便稍后恢复,或者在网络间传输对象。然而,这个过程也可能引入...
Java序列化是Java平台提供的一种持久化机制,它允许我们将一个Java对象转换为字节流,以便存储到磁盘上,或者通过网络进行传输。这使得我们可以保存和恢复对象的状态。实现序列化的类需要实现`Serializable`接口,...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化的概念 序列化是指将程序中的对象转换为一系列字节流的过程,主要用于保存对象的状态或在网络之间传输对象。序列化的主要目的是为了能够持久化...
Java序列化是Java平台中的一种核心机制,它允许对象的状态被转换成字节流,以便存储到磁盘、数据库,或者在网络中进行传输。这对于实现持久化、远程方法调用(RMI)以及Enterprise JavaBeans(EJB)等高级功能至关...
Java序列化是Java平台中的一种标准机制,它允许将对象的状态转换为字节流,以便存储、传输或恢复。在Java中,一个类如果要实现序列化,需要实现`Serializable`接口,这是一个标记接口,不包含任何方法。下面我们将...
Java序列化是Java平台中的一种标准机制,允许对象的状态被保存到磁盘或者在网络中进行传输,以便在后续的时间或地点恢复这些对象。这个过程包括两个主要操作:序列化(将对象转换为字节流)和反序列化(将字节流恢复...
Java序列化是Java平台中的一项重要技术,它允许对象的状态被转换为字节流,以便存储或通过网络进行传输。这种技术在分布式系统、持久化存储以及数据交换等场景中非常常见。本资源包含了三个流行的Java序列化框架:...
Java序列化机制是Java语言中一项非常实用的功能,它极大地简化了对象在网络传输和持久化过程中的处理。通过深入了解序列化的原理和算法流程,开发者可以更好地利用这项技术解决实际问题。在未来的学习和工作中,掌握...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化是什么? 序列化是指将程序中的对象转换为字节流的过程,从而方便存储或传输这些对象。通常,序列化用于将对象的状态(即其实例变量的值,而非...
Java对象的序列化和反序列化是Java编程中一项重要的技术,主要用于将对象的状态转换为字节流,以便存储或在网络上传输。这一过程对于理解Java的IO操作、持久化数据以及实现分布式通信等场景非常关键。 首先,我们来...
Java序列化是Java平台提供的一种将对象转换为字节流,以便存储、在网络上传输或者在后续时间重新创建相同对象的机制。这是Java编程中一个非常重要的概念,尤其是在分布式环境和持久化存储中。让我们深入探讨一下Java...
Java序列化流协议定义了一组规则,描述了如何将Java对象转换为字节流。这些规则确保了对象可以在不同的环境中被正确序列化和反序列化。 **6.2 流元素** 序列化流由一系列元素组成,包括对象类型、对象状态等信息。...
总结来说,C#和Java的序列化和反序列化机制都是各自语言中不可或缺的一部分,它们使得数据能够在不同环境之间自由流动。理解和掌握这些技术对于任何软件开发者来说都是非常重要的,特别是涉及到数据持久化、网络通信...
**一、Java序列化** 1. **什么是序列化**:序列化是将对象的状态(属性和成员变量)转换为可以存储或传输的数据格式的过程。在Java中,通常是将对象转换为字节数组,以便写入磁盘或通过网络发送。 2. **为什么需要...
要序列化一个对象,可以使用`ObjectOutputStream`,反序列化则使用`ObjectInputStream`。虽然简单易用,但效率较低,且序列化的元数据(如类名、字段名)会被包含在字节流中,存在安全风险(如反序列化攻击)。 2. ...
总的来说,protobuf是Java序列化的一个强大工具,尤其在处理大量数据交换和跨平台通信时,它的效率和灵活性使它成为首选。学习和掌握protobuf不仅可以提升项目性能,还能提高代码的可维护性和扩展性。