简单来说序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化,流的概念这里不用多说(就是I/O),我们可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间(注:要想将对象传输于网络必须进行流化)!在对对象流进行读写操作时会引发一些问题,而序列化机制正是用来解决这些问题的!
问题的引出:
如上所述,读写对象会有什么问题呢?比如:我要将对象写入一个磁盘文件而后再将其读出来会有什么问题吗?别急,其中一个最大的问题就是对象引用!举个例子来说:假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); },这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b,接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个空间,而对象a同时在内存中存在两份,想一想后果吧,如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,这不是我们所希望的!
以下序列化机制的解决方案:
1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)
2.当要保存一个对象时,先检查该对象是否被保存了。
3.如果以前保存过,只需写入"与已经保存的具有序列号x的对象相同"的标记,否则,保存该对象
通过以上的步骤序列化机制解决了对象引用的问题!
序列化的实现
将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
例子:
import java.io.*;
public class Test {
public static void main(String[] args) {
Employee harry = new Employee("Harry Hacker", 50000);
Manager manager1 = new Manager("Tony Tester", 80000);
manager1.setSecretary(harry);
Employee[] staff = new Employee[2];
staff[0] = harry;
staff[1] = manager1;
try {
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("employee.dat"));
out.writeObject(staff);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
"employee.dat"));
Employee[] newStaff = (Employee[]) in.readObject();
in.close();
/**
* 通过harry对象来加薪 将在secretary上反映出来
*/
newStaff[0].raiseSalary(10);
for (int i = 0; i < newStaff.length; i++)
System.out.println(newStaff[i]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Employee implements Serializable {
public Employee(String n, double s) {
name = n;
salary = s;
}
/**
*
* 加薪水
*
*/
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString() {
return getClass().getName() + "[name = " + name+ ",salary = " + salary+ "]";
}
private String name;
private double salary;
}
class Manager extends Employee
{
public Manager(String n, double s)
{
super(n, s);
secretary = null;
}
/**
*
* 设置秘书
*
*/
public void setSecretary(Employee s)
{
secretary = s;
}
public String toString()
{
return super.toString()+ "[secretary = " + secretary+ "]";
}
// secretary代表秘书
private Employee secretary;
}
修改默认的序列化机制
在序列化的过程中,有些数据字段我们不想将其序列化,对于此类字段我们只需要在定义时给它加上transient关键字即可,对于transient字段序列化机制会跳过不会将其写入文件,当然也不可被恢复。但有时我们想将某一字段序列化,但它在SDK中的定义却是不可序列化的类型,这样的话我们也必须把他标注为transient,可是不能写入又怎么恢复呢?好在序列化机制为包含这种特殊问题的类提供了如下的方法定义:
private void readObject(ObjectInputStream in) throws
IOException, ClassNotFoundException;
private void writeObject(ObjectOutputStream out) throws
IOException;
(注:这些方法定义时必须是私有的,因为不需要你显示调用,序列化机制会自动调用的)
使用以上方法我们可以手动对那些你又想序列化又不可以被序列化的数据字段进行写出和读入操作。
下面是一个典型的例子,java.awt.geom包中的Point2D.Double类就是不可序列化的,因为该类没有实现Serializable接口,在我的例子中将把它当作LabeledPoint类中的一个数据字段,并演示如何将其序列化!
import java.io.*;
import java.awt.geom.*;
public class TransientTest
{
public static void main(String[] args)
{
LabeledPoint label = new LabeledPoint("Book", 5.00, 5.00);
try
{
System.out.println(label);// 写入前
ObjectOutputStream out = new ObjectOutputStream(new
FileOutputStream("Label.txt"));
out.writeObject(label);
out.close();
System.out.println(label);// 写入后
ObjectInputStream in = new ObjectInputStream(new
FileInputStream("Label.txt"));
LabeledPoint label1 = (LabeledPoint) in.readObject();
in.close();
System.out.println(label1);// 读出并加1.0后
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class LabeledPoint implements Serializable
{
public LabeledPoint(String str, double x, double y)
{
label = str;
point = new Point2D.Double(x, y);
}
private void writeObject(ObjectOutputStream out) throws IOException
{
/**
*
* 必须通过调用defaultWriteObject()方法来写入
*
* 对象的描述以及那些可以被序列化的字段
*
*/
out.defaultWriteObject();
out.writeDouble(point.getX());
out.writeDouble(point.getY());
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
/**
*
* 必须调用defaultReadObject()方法
*
*/
in.defaultReadObject();
double x = in.readDouble() + 1.0;
double y = in.readDouble() + 1.0;
point = new Point2D.Double(x, y);
}
public String toString()
{
return getClass().getName()+ "[label = " + label+ ", point.getX() = " + point.getX()+ ", point.getY() = " + point.getY()+ "]";
}
private String label;
transient private Point2D.Double point;
}
分享到:
相关推荐
首先,让我们深入理解什么是C#中的类序列化。在C#中,序列化允许我们将对象实例转换为字节流,这可以是XML、JSON或其他二进制格式。这样做是为了持久化对象的状态,也就是将对象的所有属性和字段保存下来,即使程序...
boost类序列化
在C#编程中,类序列化是一个非常重要的概念,它涉及到将对象的状态转换为可以存储或传输的数据格式,如XML、JSON或者二进制。这个过程对于数据持久化、网络通信以及跨进程通信等场景非常有用。在这个"仅供学习"的...
Java SE程序 类序列化ObjectInputStreamsJava SE程序 类序列化ObjectInputStreamsJava SE程序 类序列化ObjectInputStreamsJava SE程序 类序列化ObjectInputStreamsJava SE程序 类序列化ObjectInputStreamsJava SE...
在本文中,我们将探讨PHP中的类序列化,以及如何自定义序列化过程。 ### PHP序列化基础 PHP内置的`serialize()`函数是进行对象序列化的工具。当你调用`serialize()`时,它会返回一个表示对象状态的字符串。例如: ...
这是一个标记接口,没有定义任何方法,只是告诉Java虚拟机(JVM)这个类的对象是可以序列化的。例如: ```java public class MyEntity implements Serializable { private String name; private int age; // ...
本工程源码,基于rapidjson实现二次封装,使C++序列化一个类的变得代码非常小,耦合性非常低,且不损失原有序列化性能。详细使用可关联本人博客:http://blog.csdn.net/lightspear/article/details/54836656
本文将详细讲解如何在Objective-C或Swift环境下,针对ARC(Automatic Reference Counting)内存管理机制,实现JSON实体类的序列化与反序列化。 ### 一、序列化(Serialization) 序列化是指将对象转换为可以传输或...
本资源提供了C#实现的序列化与反序列化类的源代码,支持对类和任意C#对象进行操作。 首先,我们要理解序列化的概念。序列化是将对象转换为可以持久存储或在网络上传输的格式的过程。在C#中,我们可以使用.NET框架...
总结来说,序列化和反序列化是将对象转换为可存储或传输的格式的过程,而封装类的使用则可以简化这些操作,使得开发者可以更加专注于业务逻辑而不是底层的序列化细节。在C#中,我们可以利用.NET框架提供的工具来实现...
需要注意的是,实现序列化的类应该谨慎处理其内部状态,因为序列化会保存对象的所有字段,包括私有(private)和受保护的(protected)成员。如果某个类的父类没有实现`Serializable`接口,那么子类仍然可以序列化,...
在本主题中,我们将深入探讨如何利用MyBatis Generator进行反向工程操作,以及如何在生成的POJO类中集成序列化功能。 首先,反向工程(Reverse Engineering)是根据已有的数据库模型生成相应的Java代码的过程。在...
5. **序列化安全**:FST可以防止恶意的反序列化攻击,通过配置可以禁止不安全的类序列化,增强系统的安全性。 6. **跨平台兼容**:与其他序列化库一样,FST序列化的数据可以在不同的Java环境中无缝传输,保证了平台...
这是一个用于标识类序列化版本的特殊字段。如果不显式声明,JVM会自动生成一个默认值。但是,当类结构改变时,应该手动更新此ID,以避免因版本不匹配导致的异常。 ```java private static final long ...
详细解释了C++对类的序列化的原理,通过这个,可以自己编译出可以序列化和反序列化的代码来,而不再用MFC的宏,本想0积分的,但确实是自己慢慢测试编译的,好歹也有辛苦分,高手勿喷,新手共勉。
在C#编程环境中,我们有时需要将自定义的结构体或类序列化成Excel格式,以便进行快速的数据输出、报表生成或进一步的数据分析。本知识点主要围绕“Excel序列化代码”这一主题,探讨如何利用C#实现这一功能。 首先,...
1. 复杂类型的处理:除了基本类型外,还可以序列化和反序列化自定义类、结构体以及容器(如vector、map等)。对于自定义类型,通常需要重载`operator和`operator>>`,或者使用nlohmann/json库中的`to_json`和`from_...
这意味着较新的类版本可以读取由较旧版本的类序列化的流,反之亦然。这种兼容性允许应用程序在不同的Java虚拟机(JVM)版本之间传输对象,而不必担心类版本不匹配的问题。 序列化过程通常需要对象实现java.io....
在IT行业中,三层架构、抽象工厂模式以及序列化与反序列化是软件开发中的关键概念。下面将详细解析这些知识点。 首先,三层架构是一种常见的软件设计模式,它将应用程序分为三个逻辑层:表现层(Presentation Layer...