概览:对象转换的目标是什么?
我们通常将一个 Java 对象转换为以下几种形式:
- JSON 字符串:用于 Web API 前后端交互。
- XML 字符串:用于企业级集成、配置文件等。
- 字符串:用于日志记录、控制台输出等。
- Map:需要灵活地处理对象的属性,特别是当属性名是动态的时候。
- 字节数组:用于网络传输、文件存储或序列化。
- 其他对象:将一个 DTO (Data Transfer Object) 转换为 Entity (数据库实体)。
转换为 JSON 字符串
这是目前最主流的转换方式,广泛应用于 RESTful API 开发。
使用 Jackson (最流行、功能强大)
Jackson 是事实上的标准,你需要添加 jackson-databind 依赖。
Maven 依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version> <!-- 使用最新版本 -->
</dependency>
示例代码:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
// 1. 定义一个简单的 Java 对象 (POJO)
class User {
private String name;
private int age;
private String email;
// Jackson 需要一个无参构造函数
public User() {}
// Getters and Setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + ", email='" + email + "'}";
}
}
public class Main {
public static void main(String[] args) {
// 2. 创建 ObjectMapper 实例
ObjectMapper objectMapper = new ObjectMapper();
// 3. 创建 User 对象
User user = new User();
user.setName("张三");
user.setAge(30);
user.setEmail("zhangsan@example.com");
try {
// 4. 将对象转换为 JSON 字符串
String jsonString = objectMapper.writeValueAsString(user);
System.out.println("转换为 JSON 字符串:");
System.out.println(jsonString);
// 输出: {"name":"张三","age":30,"email":"zhangsan@example.com"}
// 5. 将 JSON 字符串转换回对象
User deserializedUser = objectMapper.readValue(jsonString, User.class);
System.out.println("\n从 JSON 字符串转换回对象:");
System.out.println(deserializedUser);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
使用 Gson (Google出品,简单易用)
Gson 是另一个非常流行的库,由 Google 开发。
Maven 依赖:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version> <!-- 使用最新版本 -->
</dependency>
示例代码:
import com.google.gson.Gson;
// 使用上面定义的 User 类
public class Main {
public static void main(String[] args) {
// 1. 创建 Gson 实例
Gson gson = new Gson();
// 2. 创建 User 对象
User user = new User();
user.setName("李四");
user.setAge(25);
user.setEmail("lisi@example.com");
// 3. 转换为 JSON 字符串
String jsonString = gson.toJson(user);
System.out.println("转换为 JSON 字符串:");
System.out.println(jsonString);
// 输出: {"name":"李四","age":25,"email":"lisi@example.com"}
// 4. 从 JSON 字符串转换回对象
User deserializedUser = gson.fromJson(jsonString, User.class);
System.out.println("\n从 JSON 字符串转换回对象:");
System.out.println(deserializedUser);
}
}
转换为 XML 字符串
XML 在企业应用中仍然很常见,JAXB (Java Architecture for XML Binding) 是 Java 标准库中用于 XML 绑定的 API,无需额外依赖(Java 8 及以上内置)。
示例代码:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.StringWriter;
// 1. 使用 @XmlRootElement 注解标记类
@XmlRootElement
class Product {
private String id;
private String name;
private double price;
public Product() {}
// 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; }
}
public class Main {
public static void main(String[] args) {
Product product = new Product();
product.setId("P001");
product.setName("高性能笔记本电脑");
product.setPrice(8999.99);
try {
// 2. 创建 JAXBContext
JAXBContext jaxbContext = JAXBContext.newInstance(Product.class);
// 3. 创建 Marshaller
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 格式化输出
// 4. 转换为 XML 字符串
StringWriter writer = new StringWriter();
marshaller.marshal(product, writer);
String xmlString = writer.toString();
System.out.println("转换为 XML 字符串:");
System.out.println(xmlString);
/*
输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<product>
<id>P001</id>
<name>高性能笔记本电脑</name>
<price>8999.99</price>
</product>
*/
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
转换为字符串
通常我们指的是有意义的字符串表示,而不是默认的 com.example.User@1a2b3c4d 这种哈希码。
重写 toString() 方法 (最基本、最推荐)
这是 Java 的标准做法,用于对象的日志记录和调试。
class User {
private String name;
private int age;
// ... constructor, getters, setters ...
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
User user = new User();
user.setName("王五");
user.setAge(28);
// 直接打印对象,会自动调用 toString() 方法
System.out.println(user); // 输出: User{name='王五', age=28}
}
}
使用字符串拼接或 StringBuilder
在 toString() 方法内部或需要手动拼接时使用。
String userString = "User{name='" + user.getName() + "', age=" + user.getAge() + "}";
使用 Apache Commons Lang (功能更丰富)
ToStringBuilder 可以简化 toString() 方法的编写。
Maven 依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
import org.apache.commons.lang3.builder.ToStringBuilder;
class User {
private String name;
private int age;
// ... constructor, getters, setters ...
@Override
public String toString() {
// reflectionToString 会自动遍历所有字段
return ToStringBuilder.reflectionToString(this);
}
}
转换为 Map
当对象的属性名是动态的,或者你想要一个更灵活的键值对结构时,将对象转为 Map 会很有用。
手动转换 (简单直接)
class User {
private String name;
private int age;
// ... getters and setters ...
}
public class Main {
public static void main(String[] args) {
User user = new User();
user.setName("赵六");
user.setAge(35);
Map<String, Object> userMap = new HashMap<>();
userMap.put("name", user.getName());
userMap.put("age", user.getAge());
System.out.println(userMap); // 输出: {name=赵六, age=35}
}
}
使用反射 (通用但性能较低)
可以写一个通用工具方法来转换任何对象。
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class ObjectToMapUtil {
public static Map<String, Object> convertToMap(Object obj) {
Map<String, Object> map = new HashMap<>();
if (obj == null) {
return map;
}
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true); // 允许访问私有字段
try {
map.put(field.getName(), field.get(obj));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return map;
}
}
// 使用方式
User user = new User();
// ... set properties ...
Map<String, Object> userMap = ObjectToMapUtil.convertToMap(user);
使用 Jackson (推荐,性能好且功能全)
Jackson 可以非常方便地将对象转为 Map。
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
// ... 使用上面的 User 类和 ObjectMapper ...
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User();
user.setName("钱七");
user.setAge(40);
// 使用 TypeReference 来指定泛型类型
Map<String, Object> map = objectMapper.convertValue(user, new TypeReference<Map<String, Object>>() {});
System.out.println(map); // 输出: {name=钱七, age=40}
}
}
转换为字节数组
这通常被称为序列化 (Serialization),主要用于将对象的状态保存到文件或通过网络传输。
Java 提供了内置的序列化机制,但更推荐使用 JSON 或 Protocol Buffers 等更高效、跨语言的格式。
使用 Java 内置序列化 (不推荐用于生产)
对象必须实现 Serializable 接口。
import java.io.*;
import java.util.Arrays;
class User implements Serializable {
private static final long serialVersionUID = 1L; // 推荐添加,用于版本控制
private String name;
private int age;
// ... constructor, getters, setters ...
}
public class Main {
public static void main(String[] args) {
User user = new User();
user.setName("孙八");
user.setAge(45);
// 1. 对象 -> 字节数组 (序列化)
byte[] serializedBytes;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(user);
serializedBytes = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return;
}
System.out.println("对象已序列化为字节数组,长度: " + serializedBytes.length);
System.out.println("字节数组内容: " + Arrays.toString(serializedBytes));
// 2. 字节数组 -> 对象 (反序列化)
try (ByteArrayInputStream bis = new ByteArrayInputStream(serializedBytes);
ObjectInputStream ois = new ObjectInputStream(bis)) {
User deserializedUser = (User) ois.readObject();
System.out.println("\n从字节数组反序列化回对象:");
System.out.println(deserializedUser);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
使用 Jackson (推荐)
将对象转为 JSON 字符串,再将字符串转为字节数组。
ObjectMapper objectMapper = new ObjectMapper(); User user = new User(); // ... set properties ... // 1. 对象 -> JSON 字符串 -> 字节数组 byte[] jsonBytes = objectMapper.writeValueAsString(user).getBytes(StandardCharsets.UTF_8); // 2. 字节数组 -> JSON 字符串 -> 对象 User deserializedUser = objectMapper.readValue(new String(jsonBytes, StandardCharsets.UTF_8), User.class);
总结与选择建议
| 目标形式 | 推荐方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| JSON 字符串 | Jackson / Gson | 行业标准,性能好,功能强大,生态成熟 | 需要引入第三方库 | Web API 开发、前后端数据交互、配置文件 |
| XML 字符串 | JAXB | Java 标准,无需额外依赖,绑定方便 | 语法冗余,解析性能不如 JSON | 企业级应用集成、SOAP Web Service、旧系统 |
| 字符串 | 重写 toString() |
Java 内置,简单直接,用于调试和日志 | 非结构化,不适合数据交换 | 日志记录、调试、打印信息 |
| Map | Jackson / 手动转换 | 灵活,适合动态属性名 | 失去类型安全,手动转换麻烦 | 需要动态处理对象属性、与某些特定 API 交互 |
| 字节数组 | Jackson (推荐) | 跨语言,可读性好,压缩率高 | Java 内置序列化是二进制,不可读 | 网络传输、文件存储、分布式系统 |
对于现代 Java 开发,Jackson 是一个全能型的工具,强烈建议将其作为项目的基础依赖,它几乎能满足所有对象转换的需求。
