杰瑞科技汇

Java对象如何高效转换?

概览:对象转换的目标是什么?

我们通常将一个 Java 对象转换为以下几种形式:

  1. JSON 字符串:用于 Web API 前后端交互。
  2. XML 字符串:用于企业级集成、配置文件等。
  3. 字符串:用于日志记录、控制台输出等。
  4. Map:需要灵活地处理对象的属性,特别是当属性名是动态的时候。
  5. 字节数组:用于网络传输、文件存储或序列化。
  6. 其他对象:将一个 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 是一个全能型的工具,强烈建议将其作为项目的基础依赖,它几乎能满足所有对象转换的需求。

分享:
扫描分享到社交APP
上一篇
下一篇