XMLEncoder 类是 ObjectOutputStream 的互补替换,可用于生成 JavaBean 的文本表示形式,所使用方式与用 ObjectOutputStream 创建 Serializable 对象的二进制表示形式的方式相同。

尽管两者的 API 类似,但 XMLEncoder 类仅设计用于将 JavaBean 的图形归档为其公共属性的文本表示形式。与 Java 源文件类似,以这种方式写入的文档在所涉及类的实现中可自然免除更改。在进程间通信和通用序列化中继续推荐使用 ObjectOutputStream
XMLEncoder 类提供 JavaBean 的默认指示,其中它们被表示为符合 1.0 版的 XML 规范和 Unicode/ISO 10646 字符集 UTF-8 字符编码的 XML 文档。由 XMLEncoder 类生成的 XML 文档如下:
  • 轻便且版本灵活:它们不依赖于任何类的私有实现,因此,与 Java 源文件类似,可以在某些不同版本的类之间或不同的供应商的 VM 之间交换它们。
  • 结构紧凑XMLEncoder 类在内部使用删减冗余 (redundancy elimination) 算法,因此 Bean 属性的默认值不会被写入流中。
  • 容错性:文件中的非结构性错误(由于文件的破坏或在归档文件中对类进行的 API 更改导致)仍然保持本地化,因此 reader 可以报告错误,并继续加载不受错误影响的那部分文档。
如下面的例子:

package com.kkoolerter;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;

public class Main {

    public static void main(String[] args) throws Exception {
        Person p = new Person();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        p.setAge(20);
        p.setBirthday(sdf.parse("1999-12-21"));
        p.setName("Hello");
        p.setId("HJ0x000");
        OutputStream out = new FileOutputStream(new File(p.getId()));
        XMLEncoder encoder = new XMLEncoder(out);
       // Statement stmt = new Statement(p,"setAge",new Object[]{19});
        encoder.writeObject(p);
        //
        encoder.close();
        out.close();
        InputStream is = new FileInputStream(new File(p.getId()));
        XMLDecoder decoder = new XMLDecoder(is);
        Person p1 = (Person) decoder.readObject();
       
        System.out.println(p1.getId()+","+p1.getName()+sdf.format(p1.getBirthday())+","+p1.getAge());
       
        decoder.close();
        is.close();
    }
}
生成的XML文档如下:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0-ea" class="java.beans.XMLDecoder">
 <object class="com.kkoolerter.Person">
  <void property="age">
   <int>20</int>
  </void>
  <void property="birthday">
   <object class="java.util.Date">
    <long>945705600000</long>
   </object>
  </void>
  <void property="id">
   <string>HJ0x000</string>
  </void>
  <void property="name">
   <string>Hello</string>
  </void>
 </object>
</java>

XML 语法使用以下约定:
  • 每个元素表示一个方法调用。
  • "object" 标记表示一个表达式,其值被用作参数来封闭元素。
  • "void" 标记表示将要执行的语句,但其结果不会被用作参数来封闭方法。
  • 包含元素的元素使用这些元素作为参数,除非它们有以下标记:"void"。
  • 方法的名称由 "method" 属性表示。
  • XML 的标准 "id" 和 "idref" 属性用于引用以前的表达式,以便处理对象图形中的环形。
  • "class" 属性用于显式指定静态方法的目标或构造方法;其值是类的完全限定名。
  • 如果没有通过 "class" 属性定义目标,则使用外部上下文将带有 "void" 标记的元素作为目标执行。
  • Java 的 String 类被特殊对待并被写入 <string>Hello, world</string>,其中使用 UTF-8 字符编码将字符串的字符转换成字节。
尽管只使用这三个标记就可以写入所有对象图形,但以下定义也包括在内,以便能够更具体地表示普通数据结构:
  • 默认方法名是 "new"。
  • java 类的引用是以 <class>javax.swing.JButton</class> 形式写入的。
  • 用于 Java 基本类型的包装器类的实例是通过将基本类型的名称用做标记来写入的。例如,Integer 类的实例可以写为:<int>123</int>。注意,XMLEncoder 类使用了 Java 的反射包,在该包中,Java 的基本类型与其相关“包装器类”之间的转换是内部处理的。XMLEncoder 类自身的 API 只处理 Object
  • 在表示 null 方法(其名称以 "get" 开头)的元素中,"method" 属性被 "property" 属性替代,后者的值是通过移除 "get" 前缀并取消所得结果的大写化得到的。
  • 在表示一元方法(其名称以 "set" 开头)的元素中,"method" 属性被 "property" 属性替代,后者的值是通过移除 "set" 前缀并取消所得结果的大写化得到的。
  • 在表示名为 "get" 且使用一个整数参数的方法的元素中,"method" 属性由 "index" 属性替换,后者的值是第一个参数的值。
  • 在表示名为 "set" 且使用两个参数(第一个参数为整数)的方法的元素中,"method" 属性由 "index" 属性替换,后者的值是第一个参数的值。
  • 数组的引用是使用 "array" 标记来编写的。"class" 和 "length" 属性分别指定数组的子类型和它的长度。
参考文献:JDK文档