在Java中将对象转换为二进制流再转为Base64字符串,通常涉及序列化过程。以下是几种实现方式:
1. 使用标准Java序列化
import java.io.*;
import java.util.Base64;
public class ObjectToBase64 {
// 对象必须实现Serializable接口
static class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
/**
* 对象序列化为Base64字符串
*/
public static String objectToBase64(Serializable obj) throws IOException {
// 序列化对象到字节数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(obj);
}
// 将字节数组转为Base64
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
/**
* 从Base64字符串反序列化对象
*/
public static Object base64ToObject(String base64Str)
throws IOException, ClassNotFoundException {
// Base64解码为字节数组
byte[] data = Base64.getDecoder().decode(base64Str);
// 从字节数组反序列化对象
ByteArrayInputStream bais = new ByteArrayInputStream(data);
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
return ois.readObject();
}
}
public static void main(String[] args) {
try {
// 创建测试对象
Person person = new Person("张三", 25);
// 序列化为Base64
String base64 = objectToBase64(person);
System.out.println("Base64字符串: " + base64);
// 反序列化
Person restoredPerson = (Person) base64ToObject(base64);
System.out.println("反序列化对象: " + restoredPerson);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 使用JSON序列化(推荐)
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Base64;
public class JsonToBase64 {
static class Product {
private String id;
private String name;
private double price;
// 无参构造函数
public Product() {}
public Product(String id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
// getters and setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
}
/**
* 对象转Base64(JSON格式)
*/
public static String toBase64(Object obj) throws Exception {
ObjectMapper mapper = new ObjectMapper();
byte[] jsonBytes = mapper.writeValueAsBytes(obj);
return Base64.getEncoder().encodeToString(jsonBytes);
}
/**
* Base64转对象
*/
public static <T> T fromBase64(String base64Str, Class<T> clazz)
throws Exception {
ObjectMapper mapper = new ObjectMapper();
byte[] jsonBytes = Base64.getDecoder().decode(base64Str);
return mapper.readValue(jsonBytes, clazz);
}
public static void main(String[] args) {
try {
Product product = new Product("P001", "笔记本电脑", 5999.99);
// 转为Base64
String base64 = toBase64(product);
System.out.println("Base64字符串: " + base64);
// 从Base64恢复
Product restored = fromBase64(base64, Product.class);
System.out.println("恢复的对象: " +
"id=" + restored.getId() +
", name=" + restored.getName() +
", price=" + restored.getPrice());
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. 使用Apache Commons工具类
import org.apache.commons.codec.binary.Base64;
import java.io.*;
public class CommonsBase64Util {
/**
* 序列化对象到Base64字符串
*/
public static String serializeToBase64(Serializable obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(obj);
}
return Base64.encodeBase64String(baos.toByteArray());
}
/**
* 从Base64字符串反序列化对象
*/
public static Object deserializeFromBase64(String base64Str)
throws IOException, ClassNotFoundException {
byte[] data = Base64.decodeBase64(base64Str);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
return ois.readObject();
}
}
}
4. 封装工具类
import java.io.*;
import java.util.Base64;
public class SerializationUtils {
/**
* 将对象序列化为Base64字符串
*/
public static String serializeToBase64(Serializable object) {
if (object == null) {
return null;
}
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
oos.flush();
return Base64.getEncoder().encodeToString(baos.toByteArray());
} catch (IOException e) {
throw new RuntimeException("序列化失败", e);
}
}
/**
* 从Base64字符串反序列化对象
*/
@SuppressWarnings("unchecked")
public static <T> T deserializeFromBase64(String base64Str) {
if (base64Str == null || base64Str.isEmpty()) {
return null;
}
byte[] data = Base64.getDecoder().decode(base64Str);
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais)) {
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("反序列化失败", e);
}
}
/**
* 安全的反序列化,避免反序列化漏洞
*/
public static <T> T safeDeserializeFromBase64(String base64Str, Class<T> expectedClass) {
if (base64Str == null || base64Str.isEmpty()) {
return null;
}
byte[] data = Base64.getDecoder().decode(base64Str);
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais)) {
Object obj = ois.readObject();
if (expectedClass.isInstance(obj)) {
return expectedClass.cast(obj);
} else {
throw new RuntimeException("反序列化类型不匹配");
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("反序列化失败", e);
}
}
}
5. 使用示例
public class Example {
// 定义可序列化的类
static class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private String email;
private transient String password; // transient字段不会被序列化
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
// getters and setters
}
public static void main(String[] args) {
// 创建对象
User user = new User("john_doe", "john@example.com", "secret123");
// 序列化为Base64
String base64 = SerializationUtils.serializeToBase64(user);
System.out.println("Base64: " + base64);
System.out.println("长度: " + base64.length());
// 反序列化
User restoredUser = SerializationUtils.deserializeFromBase64(base64);
System.out.println("用户名: " + restoredUser.username);
System.out.println("邮箱: " + restoredUser.email);
System.out.println("密码: " + restoredUser.password); // 为null,因为是transient
}
}
注意事项
-
安全性:Java原生序列化存在安全风险,可能被恶意利用
-
版本兼容:序列化对象修改后,旧版本可能无法反序列化
-
性能:JSON序列化通常比Java原生序列化更高效
-
transient字段 :使用
transient关键字标记的字段不会被序列化 -
serialVersionUID:建议显式定义,避免自动生成导致版本兼容问题
推荐方案
-
网络传输或存储:推荐使用JSON + Base64
-
本地持久化:考虑使用protobuf、Avro等二进制格式
-
安全性要求高:避免使用Java原生序列化,使用JSON或自定义序列化
选择哪种方式取决于具体需求,JSON方式更通用、更安全,而Java原生序列化更适合Java系统间的通信。