java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java序列化与反序列化方式

Java中对象的转移之序列化与反序列化方式

作者:ktkiko11

文章介绍了序列化与反序列化的定义和实现流程,重点阐述了Java中的序列化与反序列化实现,包括Serializable接口、Externalizable接口、transient关键字等,并指出了Java原生序列化的缺点及替代方案FastJson和Protobuf,最终总结了选择不同序列化工具的场景和优势

1. 序列化与反序列化的定义与实现流程

序列化(Serialization)反序列化(Deserialization)是处理对象持久化和网络传输的关键技术。它们在分布式系统、缓存系统和跨应用传输数据中应用广泛。

序列化是什么?

序列化是将一个对象转换成字节流的过程,这样的数据形式便于存储到文件、数据库,或通过网络传输到其他系统。简单来说,序列化就是把数据打包成一个可转移、存储的“快递包裹”。

反序列化是什么?

反序列化是序列化的逆过程,即将字节流还原为对象的过程。通过反序列化,系统可以读取存储的对象数据,或通过网络传输接收到的数据重构出对象。

序列化的实现流程

序列化和反序列化的基本流程可以分为以下几步:

对象状态转换为字节流

传输或存储字节流

将字节流转为对象(反序列化)

这种流程实现了对象在不同系统、不同时刻的持久化保存和跨网络、跨进程的数据传输。序列化的技术不仅限于Java,在很多语言和框架中都有类似实现,适用于不同的应用需求。

2. Java中的序列化与反序列化实现

Java 提供了内置的序列化工具,使对象能方便地转换为字节流。主要工具包括ObjectOutputStreamObjectInputStream,以及SerializableExternalizable接口。

1.Serializable接口:标识对象可序列化

要实现序列化的对象类需要实现Serializable接口。这是一个标记接口,也就是不包含方法,只是标记该类可以序列化。

示例

import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 省略getters和setters
}

解释: 在这个例子中,Person类实现了Serializable接口,说明可以把Person对象转成字节流。类中包含的所有字段都会在序列化过程中转换成字节流。

2.ObjectOutputStream和ObjectInputStream:读写字节流的对象

示例:序列化对象

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializeExample {
    public static void main(String[] args) {
        Person person = new Person("Alice", 30);

        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
            oos.writeObject(person); // 将Person对象写入文件
            System.out.println("对象已序列化");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

解释

  1. 创建ObjectOutputStream,用于将对象写入文件。
  2. 使用writeObject方法将person对象转为字节流写入文件person.ser中。
  3. 文件中保存了person对象的状态数据,以便后续读取。

示例:反序列化对象

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class DeserializeExample {
    public static void main(String[] args) {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
            Person person = (Person) ois.readObject(); // 从文件中读取对象
            System.out.println("对象已反序列化: " + person.getName() + ", " + person.getAge());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

解释

  1. 创建ObjectInputStream,读取存储的字节流。
  2. 使用readObject方法从字节流中还原对象。
  3. 将反序列化的person对象信息打印出来。

3.transient关键字:保护敏感数据

在某些场景中,可能不希望某些字段被序列化,例如密码、敏感信息等。可以用transient关键字声明这些字段,以忽略序列化。

示例

public class User implements Serializable {
    private String username;
    private transient String password; // 不会被序列化

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

在这个例子中,password字段不会被序列化,也不会被写入字节流中,从而保护了敏感数据。

4.Externalizable接口:自定义序列化逻辑

除了Serializable,Java还提供了Externalizable接口,允许完全自定义序列化过程。实现Externalizable接口的类需要覆盖两个方法:

示例

import java.io.Externalizable;
import java.io.ObjectOutput;
import java.io.ObjectInput;

public class Book implements Externalizable {
    private String title;
    private double price;

    public Book() {} // 必须有无参构造方法

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(title);
        out.writeDouble(price);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        title = in.readUTF();
        price = in.readDouble();
    }
}

解释

在Java中,序列化和反序列化的基本实现方式非常直接,Serializable接口和ObjectOutputStream/ObjectInputStream提供了便捷的工具。对于更复杂的需求,Externalizable接口可以让开发者自定义序列化和反序列化的过程。这些方法不仅在Java内使用方便,同时为跨网络传输、存储等应用场景提供了基础支持。

3. Java序列化的缺点和替代方案

Java原生序列化是一种方便的方式,特别适合在同一系统中使用。不过,它在实际应用中存在以下明显的缺点:

Java序列化的缺点

性能较差

不跨语言

存在安全漏洞

缺乏版本控制

这些缺点在很多分布式、跨平台系统中都是阻碍,因此现在很多开发者会考虑使用更高效、安全、灵活的序列化框架。下面介绍两个主流替代方案:FastJsonProtobuf

替代方案一:FastJson

FastJson是阿里巴巴开发的一个高性能JSON库,主要用于Java对象和JSON格式之间的相互转换。JSON格式是一种人类可读的数据格式,可以方便地在不同语言间共享。

FastJson的优势

跨平台

速度快,性能优异

支持灵活的数据结构

安全性更高

FastJson使用示例

import com.alibaba.fastjson.JSON;

public class FastJsonExample {
    public static void main(String[] args) {
        // 序列化
        Person person = new Person("Alice", 25);
        String jsonString = JSON.toJSONString(person);
        System.out.println("序列化为JSON字符串:" + jsonString);

        // 反序列化
        Person deserializedPerson = JSON.parseObject(jsonString, Person.class);
        System.out.println("反序列化对象:" + deserializedPerson.getName());
    }
}

替代方案二:Protobuf

Protobuf(Protocol Buffers)是由Google推出的一种序列化框架,专门用于跨语言、跨平台的高效数据序列化。

Protobuf的优势

高效的二进制格式

跨语言

支持严格的版本控制

安全性强

Protobuf使用示例: Protobuf使用时,需要先定义一个.proto文件,指定数据结构:

// person.proto
syntax = "proto3";

message Person {
    string name = 1;
    int32 age = 2;
}

然后,通过Protobuf编译工具生成对应的Java类,进行序列化和反序列化:

Person person = Person.newBuilder().setName("Alice").setAge(25).build();
byte[] data = person.toByteArray(); // 序列化
Person deserializedPerson = Person.parseFrom(data); // 反序列化

在实际项目中,由于Java原生序列化的性能、安全和跨语言问题,开发者更倾向于选择FastJson或Protobuf。FastJson适合数据格式简单、语言可读性要求高的应用场景;Protobuf则适合大数据传输、分布式和跨平台应用中对效率和兼容性要求高的场景。两者都比Java原生序列化更灵活、安全和高效。

4. 总结

序列化与反序列化是现代软件开发中用于数据传输、存储的基本技术,尤其在分布式系统、缓存系统和跨语言数据交换中应用广泛。通过这些技术,可以将复杂的对象在不同进程、系统甚至平台间传递和共享。

1. Java原生序列化的基础

Java为对象序列化提供了内置支持,使用Serializable接口和ObjectOutputStream/ObjectInputStream流实现简单直接的序列化。Java原生序列化的流程包括:

这种方式在同一Java系统内部传输数据非常便捷,但存在性能、安全和兼容性等问题。

2. Java原生序列化的缺点

Java原生序列化适用于小规模数据传输或非跨平台的Java系统。但在生产级别应用中,它的缺陷较为明显:

因此,Java原生序列化适合临时数据保存,但在涉及敏感数据和跨系统场景时,存在较大风险。

3. 替代方案:FastJson和Protobuf

为了解决Java原生序列化的不足,许多开发者选择更高效的序列化框架,例如FastJson和Protobuf:

使用场景总结

综上所述,序列化和反序列化技术的发展,为现代软件提供了多样化的数据传输和持久化方案。通过合理选择合适的序列化工具,可以优化系统的性能、安全性和兼容性,从而满足不同应用的需求。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文