XML 序列化是将 Java 对象转换为 XML 格式字符串的过程,而反序列化则是将 XML 字符串转换回 Java 对象的过程,这在配置文件、数据交换、Web 服务等领域有广泛应用。

(图片来源网络,侵删)
Java 提供了多种方式来处理 XML,我将介绍三种最主流的方法:
- JAXB (Java Architecture for XML Binding) - (推荐,最常用)
- DOM (Document Object Model) - (适用于需要频繁操作 XML 结构的场景)
- SAX (Simple API for XML) - (适用于解析大型 XML 文件,内存效率高)
JAXB (Java Architecture for XML Binding)
JAXB 是 Java 标准库的一部分(从 Java 6 开始),它通过注解将 Java 类和 XML 表示绑定在一起,极大地简化了 XML 的处理,它非常适合将整个对象树直接转换为 XML。
核心概念
@XmlRootElement: 将一个类映射为 XML 的根元素。@XmlElement: 将一个字段或属性映射为 XML 的一个元素。@XmlAttribute: 将一个字段或属性映射为 XML 元素的属性。@XmlTransient: 标记一个字段或属性,使其不参与 XML 序列化/反序列化。JAXBContext: 入口点,用于管理 XML 绑定信息。Marshaller: 负责将 Java 对象序列化为 XML。Unmarshaller: 负责将 XML 反序列化为 Java 对象。
示例
准备 Java 类
我们创建一个 Java POJO (Plain Old Java Object),并用 JAXB 注解来标记它。

(图片来源网络,侵删)
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "student") // 映射为XML根元素 <student>
@XmlAccessorType(XmlAccessType.FIELD) // 指定使用字段进行绑定,而不是getter/setter
public class Student {
@XmlAttribute(name = "id") // 映射为XML元素的属性
private int id;
@XmlElement(name = "name") // 映射为XML元素 <name>
private String name;
@XmlElement(name = "age")
private int age;
@XmlElement(name = "course")
private String course;
// 必须提供一个无参构造函数,用于反序列化
public Student() {
}
public Student(int id, String name, int age, String course) {
this.id = id;
this.name = name;
this.age = age;
this.course = course;
}
// Getters and Setters (标准做法)
public int getId() { return id; }
public void setId(int id) { this.id = id; }
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 getCourse() { return course; }
public void setCourse(String course) { this.course = course; }
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", course='" + course + '\'' +
'}';
}
}
序列化:将 Student 对象转为 XML 字符串
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
public class JaxbSerializationExample {
public static void main(String[] args) {
try {
// 1. 创建一个Student对象
Student student = new Student(1, "张三", 20, "计算机科学");
// 2. 创建JAXBContext实例,需要传入要序列化的类的Class对象
JAXBContext jaxbContext = JAXBContext(Student.class);
// 3. 创建Marshaller实例
Marshaller marshaller = jaxbContext.createMarshaller();
// 4. 设置格式化输出(美化XML)
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// 5. 将对象序列化到StringWriter中
StringWriter writer = new StringWriter();
marshaller.marshal(student, writer);
// 6. 输出结果
String xml = writer.toString();
System.out.println("序列化后的XML:");
System.out.println(xml);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
输出结果:
序列化后的XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student id="1">
<name>张三</name>
<age>20</age>
<course>计算机科学</course>
</student>
反序列化:将 XML 字符串转为 Student 对象
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class JaxbDeserializationExample {
public static void main(String[] args) {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<student id=\"1\">\n" +
" <name>张三</name>\n" +
" <age>20</age>\n" +
" <course>计算机科学</course>\n" +
"</student>";
try {
// 1. 创建JAXBContext实例
JAXBContext jaxbContext = JAXBContext(Student.class);
// 2. 创建Unmarshaller实例
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
// 3. 从XML字符串反序列化对象
// 注意:需要将String转换为InputStream或Reader
Student student = (Student) unmarshaller.unmarshal(new java.io.StringReader(xml));
// 4. 输出结果
System.out.println("反序列化后的对象:");
System.out.println(student); // 调用对象的toString()方法
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
输出结果:

(图片来源网络,侵删)
反序列化后的对象:
Student{id=1, name='张三', age=20, course='计算机科学'}
DOM (Document Object Model)
DOM 是一种将整个 XML 文档加载到内存中,形成一个树状结构模型的方式,你可以像操作 Java 对象一样自由地遍历、修改、添加或删除这个树中的节点。
特点
- 易于操作:提供了完整的 API 来访问和修改 XML 数据。
- 内存消耗大:因为需要将整个文档加载到内存,所以不适合处理非常大的 XML 文件。
- 随机访问:可以随时访问文档中的任何节点。
示例:解析 XML 并获取数据
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.IOException;
import org.xml.sax.SAXException;
public class DomParserExample {
public static void main(String[] args) {
try {
// 1. 创建 DocumentBuilderFactory 和 DocumentBuilder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// 2. 解析 XML 文件(这里我们用StringReader模拟)
String xml = "<student id=\"1\"><name>张三</name><age>20</age><course>计算机科学</course></student>";
Document document = builder.parse(new java.io.ByteArrayInputStream(xml.getBytes()));
// 3. 获取根元素
Element rootElement = document.getDocumentElement();
System.out.println("根元素: " + rootElement.getNodeName());
// 4. 获取属性
String id = rootElement.getAttribute("id");
System.out.println("学生ID: " + id);
// 5. 获取子元素
NodeList nameNodes = rootElement.getElementsByTagName("name");
if (nameNodes.getLength() > 0) {
Element nameElement = (Element) nameNodes.item(0);
System.out.println("学生姓名: " + nameElement.getTextContent());
}
NodeList ageNodes = rootElement.getElementsByTagName("age");
if (ageNodes.getLength() > 0) {
Element ageElement = (Element) ageNodes.item(0);
System.out.println("学生年龄: " + ageElement.getTextContent());
}
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
SAX (Simple API for XML)
SAX 是一种事件驱动的 XML 解析器,它不会将整个 XML 文档加载到内存中,而是当解析器读取到文档的开始、结束、元素的开始、结束等事件时,会调用相应的方法(回调)。
特点
- 内存效率高:因为不需要在内存中保存整个文档,所以非常适合处理大型或超大型 XML 文件。
- 顺序访问:只能从头到尾顺序解析,不能随机访问。
- 编程复杂:需要实现
ContentHandler接口,处理各种回调事件。
示例:使用 SAX 解析 XML
创建一个 DefaultHandler 来处理事件
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.ByteArrayInputStream;
public class SaxParserExample {
public static void main(String[] args) {
String xml = "<student id=\"1\"><name>张三</name><age>20</age><course>计算机科学</course></student>";
try {
// 1. 创建 SAXParserFactory 和 SAXParser
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
// 2. 创建自定义的 Handler
DefaultHandler handler = new DefaultHandler() {
boolean bName = false;
boolean bAge = false;
boolean bCourse = false;
// 当遇到开始标签时触发
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("name")) {
bName = true;
}
if (qName.equalsIgnoreCase("age")) {
bAge = true;
}
if (qName.equalsIgnoreCase("course")) {
bCourse = true;
}
// 获取属性
if (qName.equalsIgnoreCase("student")) {
System.out.println("学生ID: " + attributes.getValue("id"));
}
}
// 当遇到标签内的文本内容时触发
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (bName) {
System.out.println("学生姓名: " + new String(ch, start, length));
bName = false;
}
if (bAge) {
System.out.println("学生年龄: " + new String(ch, start, length));
bAge = false;
}
if (bCourse) {
System.out.println("学生课程: " + new String(ch, start, length));
bCourse = false;
}
}
// 当遇到结束标签时触发
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// System.out.println("结束标签: " + qName);
}
};
// 3. 开始解析
saxParser.parse(new ByteArrayInputStream(xml.getBytes()), handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
总结与对比
| 特性 | JAXB | DOM | SAX |
|---|---|---|---|
| 核心思想 | 数据绑定:将 XML 直接映射成 Java 对象。 | 树模型:将 XML 文档在内存中构建成一棵树。 | 事件驱动:解析器触发事件,由程序处理。 |
| 易用性 | 非常高,几行代码即可完成序列化和反序列化。 | 中等,需要理解树结构,节点操作较多。 | 较低,需要处理各种回调事件,代码量较大。 |
| 内存消耗 | 中等,取决于对象的大小和结构。 | 高,整个文档都加载到内存中。 | 非常低,不一次性加载文档,逐行处理。 |
| 性能 | 较快,但不如 SAX。 | 较慢,尤其是大文件时。 | 非常高,特别是对于大文件。 |
| 适用场景 | 对象与 XML 的转换,如配置文件、Web Service (SOAP)、数据持久化。 | 需要频繁修改或随机访问 XML 结构的场景。 | 解析大型或超大型 XML 文件,或内存受限的环境。 |
| Java 版本 | Java 6+ (内置) | Java 标准库 | Java 标准库 |
如何选择?
- 如果你的任务是让一个 Java 对象(或一组对象)持久化为 XML,或者从 XML 文件中恢复一个对象,JAXB 是你的不二之选,它最简单、最直接,也最符合面向对象的思想。
- 如果你的程序需要对一个 XML 文件进行复杂的查询、修改或重组,并且文件不是特别大,DOM 是一个不错的选择,因为它提供了灵活的树形操作。
- 如果你需要处理一个几百MB甚至上GB的日志文件或数据文件,使用 DOM 会导致内存溢出,这时必须使用 SAX 来保证程序的稳定性和低内存占用。
