您的位置:首页 > 汽车 > 时评 > 武汉公司制作网站的_常用的网络推广方法_宁波seo网站_百度云网盘资源分享网站

武汉公司制作网站的_常用的网络推广方法_宁波seo网站_百度云网盘资源分享网站

2025/5/30 4:21:06 来源:https://blog.csdn.net/weixin_74417835/article/details/147169030  浏览:    关键词:武汉公司制作网站的_常用的网络推广方法_宁波seo网站_百度云网盘资源分享网站
武汉公司制作网站的_常用的网络推广方法_宁波seo网站_百度云网盘资源分享网站

Java序列化与反序列化

目录

  • 一、基本概念
    • 1.1 什么是序列化与反序列化
    • 1.2 为什么需要序列化
    • 1.3 序列化的应用场景
  • 二、Java序列化机制
    • 2.1 Serializable接口
    • 2.2 Externalizable接口
    • 2.3 序列化ID
    • 2.4 序列化与继承
  • 三、序列化实现
    • 3.1 基本序列化
    • 3.2 自定义序列化
    • 3.3 序列化字段控制
    • 3.4 序列化与静态字段
  • 四、反序列化实现
    • 4.1 基本反序列化
    • 4.2 自定义反序列化
    • 4.3 反序列化与构造函数
    • 4.4 反序列化与单例模式
  • 五、序列化格式
    • 5.1 Java原生序列化
    • 5.2 JSON序列化
    • 5.3 XML序列化
    • 5.4 其他序列化格式
  • 六、性能考虑
    • 6.1 序列化性能
    • 6.2 序列化大小
    • 6.3 序列化与内存
    • 6.4 序列化与垃圾回收
  • 七、安全考虑
    • 7.1 序列化安全风险
    • 7.2 反序列化漏洞
    • 7.3 安全最佳实践
    • 7.4 白名单过滤
  • 八、常见问题与解决方案
    • 8.1 序列化兼容性问题
    • 8.2 循环引用问题
    • 8.3 版本升级问题
    • 8.4 性能优化问题
  • 九、最佳实践
    • 9.1 序列化设计原则
    • 9.2 序列化与不可变性
    • 9.3 序列化与设计模式
    • 9.4 序列化与框架集成

一、基本概念

1.1 什么是序列化与反序列化

**序列化(Serialization)**是将对象的状态信息转换为可以存储或传输的形式的过程。在Java中,序列化是将对象转换为字节序列的过程。

**反序列化(Deserialization)**是将序列化的字节序列恢复为对象的过程。

简单来说:

  • 序列化:对象 → 字节流
  • 反序列化:字节流 → 对象

1.2 为什么需要序列化

序列化在以下场景中非常有用:

  1. 持久化存储:将对象保存到文件或数据库中
  2. 网络传输:在网络上传输对象(如RPC调用)
  3. 缓存:将对象缓存到内存或分布式缓存中
  4. 深拷贝:通过序列化和反序列化实现对象的深拷贝
  5. 会话复制:在分布式系统中复制会话状态

1.3 序列化的应用场景

  • 分布式系统:微服务架构中的服务间通信
  • 缓存系统:Redis、Memcached等缓存系统
  • 消息队列:Kafka、RabbitMQ等消息队列系统
  • Web应用:会话管理、Cookie存储
  • 大数据处理:Hadoop、Spark等大数据框架
  • 游戏开发:游戏状态保存和加载

二、Java序列化机制

2.1 Serializable接口

Java中最基本的序列化机制是通过实现Serializable接口来实现的:

import java.io.Serializable;public class Person implements Serializable {private String name;private int age;// 构造函数、getter和setter方法
}

Serializable是一个标记接口,没有定义任何方法。实现这个接口的类可以被序列化。

2.2 Externalizable接口

Externalizable接口提供了更细粒度的序列化控制:

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;public class Person implements Externalizable {private String name;private int age;// 必须有无参构造函数public Person() {// 默认构造函数}// 自定义序列化@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(name);out.writeInt(age);}// 自定义反序列化@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {name = (String) in.readObject();age = in.readInt();}// 构造函数、getter和setter方法
}

Serializable相比,Externalizable提供了完全自定义序列化和反序列化过程的能力。

2.3 序列化ID

序列化ID(serialVersionUID)用于版本控制,确保序列化和反序列化的类版本兼容:

import java.io.Serializable;public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;// 构造函数、getter和setter方法
}

如果不显式定义serialVersionUID,JVM会根据类的结构自动生成一个。但是,当类的结构发生变化时,自动生成的ID也会变化,这可能导致反序列化失败。因此,建议显式定义serialVersionUID

2.4 序列化与继承

序列化与继承的关系:

  1. 父类可序列化,子类自动可序列化
  2. 父类不可序列化,子类可序列化:子类需要负责序列化父类的状态
  3. 子类可序列化,父类构造函数有参数:父类必须有无参构造函数

示例:

// 父类不可序列化
public class Animal {protected String species;public Animal(String species) {this.species = species;}// 必须有无参构造函数public Animal() {this.species = "Unknown";}
}// 子类可序列化
public class Dog extends Animal implements Serializable {private static final long serialVersionUID = 1L;private String name;public Dog(String species, String name) {super(species);this.name = name;}// 自定义序列化private void writeObject(java.io.ObjectOutputStream out) throws IOException {out.defaultWriteObject();out.writeObject(species); // 序列化父类字段}// 自定义反序列化private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();species = (String) in.readObject(); // 反序列化父类字段}
}

三、序列化实现

3.1 基本序列化

使用ObjectOutputStream进行基本序列化:

import java.io.*;public class SerializationExample {public static void main(String[] args) {Person person = new Person("张三", 30);// 序列化try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {oos.writeObject(person);System.out.println("对象已序列化");} catch (IOException e) {e.printStackTrace();}}
}

3.2 自定义序列化

通过实现writeObjectreadObject方法来自定义序列化过程:

import java.io.*;public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;private transient String password; // 不序列化密码public Person(String name, int age, String password) {this.name = name;this.age = age;this.password = password;}// 自定义序列化private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject(); // 调用默认序列化// 对密码进行加密后再序列化String encryptedPassword = encryptPassword(password);out.writeObject(encryptedPassword);}// 自定义反序列化private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject(); // 调用默认反序列化// 解密密码String encryptedPassword = (String) in.readObject();this.password = decryptPassword(encryptedPassword);}// 加密和解密方法(示例)private String encryptPassword(String password) {// 实际应用中应使用安全的加密算法return "encrypted_" + password;}private String decryptPassword(String encryptedPassword) {// 实际应用中应使用安全的解密算法return encryptedPassword.substring("encrypted_".length());}// getter和setter方法
}

3.3 序列化字段控制

使用transient关键字控制字段是否序列化:

import java.io.Serializable;public class User implements Serializable {private static final long serialVersionUID = 1L;private String username;private transient String password; // 不序列化private transient int loginCount; // 不序列化,可以在反序列化后重新计算public User(String username, String password) {this.username = username;this.password = password;this.loginCount = 0;}// 自定义反序列化,重新计算loginCountprivate void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();this.loginCount = 0; // 重置登录次数}// getter和setter方法
}

3.4 序列化与静态字段

静态字段不会被序列化,因为静态字段属于类而不是对象:

import java.io.Serializable;public class Counter implements Serializable {private static final long serialVersionUID = 1L;private int count;private static int totalCount = 0; // 静态字段不会被序列化public Counter() {count = 0;totalCount++;}public void increment() {count++;totalCount++;}public int getCount() {return count;}public static int getTotalCount() {return totalCount;}
}

四、反序列化实现

4.1 基本反序列化

使用ObjectInputStream进行基本反序列化:

import java.io.*;public class DeserializationExample {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 (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}

4.2 自定义反序列化

通过实现readObject方法来自定义反序列化过程:

import java.io.*;public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;private String email;public Person(String name, int age) {this.name = name;this.age = age;}// 自定义反序列化private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();// 如果email为null,设置默认值if (email == null) {email = name.toLowerCase().replace(" ", ".") + "@example.com";}}// getter和setter方法
}

4.3 反序列化与构造函数

反序列化过程中不会调用类的构造函数,而是使用默认的无参构造函数:

import java.io.*;public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;public Person(String name, int age) {System.out.println("构造函数被调用");this.name = name;this.age = age;}// 必须有无参构造函数public Person() {System.out.println("无参构造函数被调用");}// getter和setter方法
}

4.4 反序列化与单例模式

反序列化可能会破坏单例模式,因为反序列化会创建新的实例:

import java.io.*;public class Singleton implements Serializable {private static final long serialVersionUID = 1L;private static Singleton instance;private Singleton() {// 私有构造函数}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}// 防止反序列化创建新实例private Object readResolve() {return getInstance();}
}

readResolve方法会在反序列化后被调用,可以用来返回单例实例,从而防止反序列化创建新实例。

五、序列化格式

5.1 Java原生序列化

Java原生序列化使用ObjectOutputStreamObjectInputStream

// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.ser"));
oos.writeObject(object);
oos.close();// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.ser"));
Object object = ois.readObject();
ois.close();

优点:

  • 简单易用
  • 自动处理对象图
  • 支持循环引用

缺点:

  • 序列化后的数据较大
  • 序列化和反序列化速度较慢
  • 与Java语言强耦合

5.2 JSON序列化

使用Jackson、Gson等库进行JSON序列化:

// 使用Jackson
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(object);
Object obj = mapper.readValue(json, Object.class);// 使用Gson
Gson gson = new Gson();
String json = gson.toJson(object);
Object obj = gson.fromJson(json, Object.class);

优点:

  • 人类可读
  • 语言无关
  • 广泛支持
  • 序列化后的数据较小

缺点:

  • 不支持复杂对象图
  • 不支持循环引用
  • 性能不如二进制格式

5.3 XML序列化

使用JAXB、XStream等库进行XML序列化:

// 使用JAXB
JAXBContext context = JAXBContext.newInstance(Person.class);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(person, new File("person.xml"));Unmarshaller unmarshaller = context.createUnmarshaller();
Person person = (Person) unmarshaller.unmarshal(new File("person.xml"));

优点:

  • 人类可读
  • 语言无关
  • 支持复杂结构
  • 支持验证

缺点:

  • 序列化后的数据较大
  • 序列化和反序列化速度较慢
  • 配置复杂

5.4 其他序列化格式

  1. Protocol Buffers

    // 定义.proto文件
    message Person {required string name = 1;required int32 age = 2;
    }// 使用生成的类
    Person person = Person.newBuilder().setName("张三").setAge(30).build();
    byte[] bytes = person.toByteArray();
    Person parsed = Person.parseFrom(bytes);
    
  2. Apache Avro

    // 定义schema
    String schema = "{\"type\":\"record\",\"name\":\"Person\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"age\",\"type\":\"int\"}]}";// 使用Avro
    DatumWriter<GenericRecord> writer = new GenericDatumWriter<>(new Schema.Parser().parse(schema));
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    JsonEncoder encoder = EncoderFactory.get().jsonEncoder(new Schema.Parser().parse(schema), output);
    writer.write(record, encoder);
    
  3. MessagePack

    // 使用MessagePack
    MessagePack msgpack = new MessagePack();
    byte[] bytes = msgpack.write(object);
    Object obj = msgpack.read(bytes);
    

六、性能考虑

6.1 序列化性能

不同序列化方式的性能比较:

  1. Java原生序列化:中等性能,适合简单对象
  2. JSON序列化:较低性能,但人类可读
  3. Protocol Buffers:高性能,适合大规模数据
  4. MessagePack:高性能,二进制格式
  5. Kryo:极高性能,但仅支持Java

性能优化技巧:

// 使用Kryo进行高性能序列化
Kryo kryo = new Kryo();
kryo.register(Person.class);
ByteArrayOutputStream output = new ByteArrayOutputStream();
Output output = new Output(output);
kryo.writeObject(output, person);
output.close();
byte[] bytes = output.toByteArray();// 反序列化
Kryo kryo = new Kryo();
kryo.register(Person.class);
Input input = new Input(bytes);
Person person = kryo.readObject(input, Person.class);
input.close();

6.2 序列化大小

不同序列化方式的序列化大小比较:

  1. Java原生序列化:较大,包含类信息
  2. JSON序列化:中等,人类可读
  3. Protocol Buffers:较小,二进制格式
  4. MessagePack:较小,二进制格式
  5. Kryo:最小,但仅支持Java

减小序列化大小的技巧:

// 使用transient排除不需要序列化的字段
public class Person implements Serializable {private String name;private transient String password; // 不序列化private transient List<String> temporaryData; // 不序列化临时数据
}// 使用自定义序列化控制序列化内容
private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();// 只序列化必要的数据out.writeObject(essentialData);
}

6.3 序列化与内存

序列化过程中的内存使用:

  1. 对象图遍历:序列化时会遍历整个对象图
  2. 临时对象创建:序列化过程中会创建临时对象
  3. 内存泄漏风险:处理大对象时可能导致内存问题

内存优化技巧:

// 使用流式处理避免一次性加载大对象
public void processLargeObject(InputStream in) throws IOException {try (ObjectInputStream ois = new ObjectInputStream(in)) {while (true) {try {Person person = (Person) ois.readObject();processPerson(person);} catch (EOFException e) {break;}}} catch (ClassNotFoundException e) {throw new IOException(e);}
}// 使用分块序列化
public void serializeLargeObject(Object obj, OutputStream out) throws IOException {try (ObjectOutputStream oos = new ObjectOutputStream(out)) {// 分块序列化for (Chunk chunk : getChunks(obj)) {oos.writeObject(chunk);oos.flush(); // 及时刷新,避免内存累积}}
}

6.4 序列化与垃圾回收

序列化过程中的垃圾回收考虑:

  1. 临时对象:序列化过程中创建的临时对象会增加GC压力
  2. 大对象:序列化大对象可能导致内存压力
  3. 缓存:序列化缓存可能导致内存泄漏

垃圾回收优化技巧:

// 使用对象池减少临时对象创建
public class ObjectPool<T> {private final Queue<T> pool = new ConcurrentLinkedQueue<>();public T borrowObject() {T obj = pool.poll();return obj != null ? obj : createNew();}public void returnObject(T obj) {pool.offer(obj);}private T createNew() {// 创建新对象}
}// 使用软引用或弱引用缓存序列化结果
public class SerializationCache {private final Map<Object, SoftReference<byte[]>> cache = new ConcurrentHashMap<>();public byte[] serialize(Object obj) {SoftReference<byte[]> ref = cache.get(obj);byte[] bytes = ref != null ? ref.get() : null;if (bytes == null) {bytes = doSerialize(obj);cache.put(obj, new SoftReference<>(bytes));}return bytes;}
}

七、安全考虑

7.1 序列化安全风险

序列化过程中的安全风险:

  1. 敏感数据泄露:序列化可能包含敏感信息
  2. 反序列化漏洞:恶意序列化数据可能导致安全问题
  3. 远程代码执行:反序列化可能执行任意代码

安全风险示例:

// 不安全的序列化
public class User implements Serializable {private String username;private String password; // 敏感信息// 构造函数、getter和setter
}// 安全的序列化
public class User implements Serializable {private String username;private transient String password; // 不序列化敏感信息// 构造函数、getter和setter
}

7.2 反序列化漏洞

Java反序列化漏洞(如Apache Commons Collections漏洞):

// 不安全的反序列化
ObjectInputStream ois = new ObjectInputStream(input);
Object obj = ois.readObject(); // 可能执行恶意代码// 安全的反序列化
public class SecureObjectInputStream extends ObjectInputStream {public SecureObjectInputStream(InputStream in) throws IOException {super(in);enableResolveObject(true);}@Overrideprotected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {// 白名单验证String className = desc.getName();if (!isAllowedClass(className)) {throw new InvalidClassException("Unauthorized deserialization attempt", className);}return super.resolveClass(desc);}private boolean isAllowedClass(String className) {// 实现白名单验证return ALLOWED_CLASSES.contains(className);}
}

7.3 安全最佳实践

序列化安全最佳实践:

  1. 避免序列化敏感数据

    public class SecureObject implements Serializable {private String publicData;private transient String sensitiveData; // 不序列化敏感数据
    }
    
  2. 使用自定义序列化控制敏感数据

    private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();// 加密敏感数据String encryptedData = encrypt(sensitiveData);out.writeObject(encryptedData);
    }private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();// 解密敏感数据String encryptedData = (String) in.readObject();sensitiveData = decrypt(encryptedData);
    }
    
  3. 实现白名单过滤

    public class SecureDeserializer {private static final Set<String> ALLOWED_CLASSES = new HashSet<>();static {ALLOWED_CLASSES.add("java.lang.String");ALLOWED_CLASSES.add("java.util.ArrayList");ALLOWED_CLASSES.add("com.example.SafeClass");}public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {try (ObjectInputStream ois = new SecureObjectInputStream(new ByteArrayInputStream(data))) {return ois.readObject();}}
    }
    

7.4 白名单过滤

实现白名单过滤以防止反序列化漏洞:

import java.io.*;
import java.util.*;public class WhitelistDeserializer {private static final Set<String> ALLOWED_CLASSES = new HashSet<>();static {// 添加允许的类ALLOWED_CLASSES.add("java.lang.String");ALLOWED_CLASSES.add("java.lang.Integer");ALLOWED_CLASSES.add("java.util.ArrayList");ALLOWED_CLASSES.add("java.util.HashMap");ALLOWED_CLASSES.add("com.example.SafeClass");}public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {try (ObjectInputStream ois = new WhitelistObjectInputStream(new ByteArrayInputStream(data))) {return ois.readObject();}}private static class WhitelistObjectInputStream extends ObjectInputStream {public WhitelistObjectInputStream(InputStream in) throws IOException {super(in);enableResolveObject(true);}@Overrideprotected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {String className = desc.getName();if (!isAllowedClass(className)) {throw new InvalidClassException("Unauthorized deserialization attempt", className);}return super.resolveClass(desc);}private boolean isAllowedClass(String className) {return ALLOWED_CLASSES.contains(className);}}
}

八、常见问题与解决方案

8.1 序列化兼容性问题

序列化兼容性问题通常发生在类结构变化时:

// 原始类
public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;// 构造函数、getter和setter
}// 修改后的类
public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;private String email; // 新增字段// 构造函数、getter和setter
}

解决方案:

  1. 保持serialVersionUID不变

    private static final long serialVersionUID = 1L; // 保持不变
    
  2. 使用自定义序列化处理兼容性

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();// 处理新增字段if (email == null) {email = "default@example.com";}
    }
    
  3. 使用版本控制

    public class Person implements Serializable {private static final long serialVersionUID = 1L;private int version = 1; // 版本字段private String name;private int age;private String email;private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();if (version < 2) {email = "default@example.com";version = 2;}}
    }
    

8.2 循环引用问题

序列化循环引用可能导致栈溢出:

public class Node implements Serializable {private String data;private Node next;public Node(String data) {this.data = data;}public void setNext(Node next) {this.next = next;}
}// 创建循环引用
Node node1 = new Node("A");
Node node2 = new Node("B");
node1.setNext(node2);
node2.setNext(node1); // 循环引用

解决方案:

  1. 使用transient排除循环引用

    public class Node implements Serializable {private String data;private transient Node next; // 不序列化next字段// 其他代码
    }
    
  2. 使用自定义序列化处理循环引用

    private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();// 使用ID引用代替直接引用if (next != null) {out.writeBoolean(true);out.writeObject(next.data);} else {out.writeBoolean(false);}
    }private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();// 重建引用关系if (in.readBoolean()) {String nextData = (String) in.readObject();next = new Node(nextData);}
    }
    

8.3 版本升级问题

版本升级时的序列化兼容性问题:

// 原始版本
public class Product implements Serializable {private static final long serialVersionUID = 1L;private String name;private double price;// 构造函数、getter和setter
}// 升级版本
public class Product implements Serializable {private static final long serialVersionUID = 1L;private String name;private double price;private String category; // 新增字段private int stock; // 新增字段// 构造函数、getter和setter
}

解决方案:

  1. 使用版本控制

    public class Product implements Serializable {private static final long serialVersionUID = 1L;private int version = 1;private String name;private double price;private String category;private int stock;private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();if (version < 2) {category = "Uncategorized";stock = 0;version = 2;}}
    }
    
  2. 使用迁移工具

    public class ProductMigration {public static Product migrate(Product oldProduct) {Product newProduct = new Product();newProduct.setName(oldProduct.getName());newProduct.setPrice(oldProduct.getPrice());newProduct.setCategory("Uncategorized");newProduct.setStock(0);return newProduct;}
    }
    

8.4 性能优化问题

序列化性能优化:

  1. 使用更高效的序列化库

    // 使用Kryo
    Kryo kryo = new Kryo();
    kryo.register(Person.class);
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    Output output = new Output(output);
    kryo.writeObject(output, person);
    output.close();
    
  2. 减少序列化数据量

    public class OptimizedPerson implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;private transient List<String> temporaryData; // 不序列化临时数据// 只序列化必要的数据private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();// 只序列化必要的数据}
    }
    
  3. 使用流式处理

    public void processLargeData(InputStream in) throws IOException {try (ObjectInputStream ois = new ObjectInputStream(in)) {while (true) {try {Person person = (Person) ois.readObject();processPerson(person);} catch (EOFException e) {break;}}} catch (ClassNotFoundException e) {throw new IOException(e);}
    }
    

九、最佳实践

9.1 序列化设计原则

序列化设计的最佳原则:

  1. 最小化序列化数据

    public class MinimalPerson implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;private transient String password; // 不序列化敏感数据private transient List<String> temporaryData; // 不序列化临时数据
    }
    
  2. 使用不可变对象

    public final class ImmutablePerson implements Serializable {private static final long serialVersionUID = 1L;private final String name;private final int age;public ImmutablePerson(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}
    }
    
  3. 实现自定义序列化

    private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();// 自定义序列化逻辑
    }private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();// 自定义反序列化逻辑
    }
    

9.2 序列化与不可变性

不可变对象与序列化的关系:

public final class ImmutablePerson implements Serializable {private static final long serialVersionUID = 1L;private final String name;private final int age;public ImmutablePerson(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}// 不需要自定义序列化,因为对象是不可变的
}

不可变对象的优点:

  • 线程安全
  • 简化序列化
  • 避免状态变化导致的序列化问题

9.3 序列化与设计模式

序列化与常用设计模式的结合:

  1. 单例模式

    public class Singleton implements Serializable {private static final long serialVersionUID = 1L;private static Singleton instance;private Singleton() {// 私有构造函数}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}// 防止反序列化创建新实例private Object readResolve() {return getInstance();}
    }
    
  2. 工厂模式

    public class PersonFactory implements Serializable {private static final long serialVersionUID = 1L;public static Person createPerson(String name, int age) {return new Person(name, age);}
    }
    
  3. 代理模式

    public class PersonProxy implements Serializable {private static final long serialVersionUID = 1L;private Person person;public PersonProxy(Person person) {this.person = person;}// 代理方法public String getName() {return person.getName();}// 自定义序列化,只序列化必要的数据private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();out.writeObject(person.getName());out.writeInt(person.getAge());}// 自定义反序列化,重建代理对象private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();String name = (String) in.readObject();int age = in.readInt();person = new Person(name, age);}
    }
    

9.4 序列化与框架集成

序列化在常用框架中的应用:

  1. Spring框架

    @Component
    public class SerializableBean implements Serializable {private static final long serialVersionUID = 1L;private String data;// getter和setter
    }
    
  2. Hibernate/JPA

    @Entity
    public class Person implements Serializable {private static final long serialVersionUID = 1L;@Id@GeneratedValueprivate Long id;private String name;private int age;// getter和setter
    }
    
  3. RESTful API

    @RestController
    @RequestMapping("/api")
    public class PersonController {@GetMapping("/person/{id}")public Person getPerson(@PathVariable Long id) {// 返回可序列化的Person对象return personService.getPerson(id);}
    }
    
  4. 消息队列

    public class MessageProducer {public void sendMessage(Person person) {// 序列化Person对象并发送到消息队列byte[] serialized = serialize(person);queue.send(serialized);}private byte[] serialize(Person person) {try (ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos)) {oos.writeObject(person);return baos.toByteArray();} catch (IOException e) {throw new RuntimeException("序列化失败", e);}}
    }

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com