JAXB可以生成ArrayList而不是List吗?

        

JAXB以List<JAXBElement>生成属性。 有没有什么方法可以生成ArrayList?

为什么,那对你有什么好处?

  1. ArrayList没有不在List接口中的公共方法,因此您无法使用ArrayList执行任何其他List (实际上只有一个) : ArrayList.trimToSize() ,谢谢@Joachim Sauer,但几乎不需要)。
  2. API接受或返回实现类型而不是底层接口是非常糟糕的做法。 我建议你按照Sun Java Tutorial的Collections Trail和/或阅读Joshua Bloch的Effective Java (你会从这个简短的预览中了解他正在谈论的内容,这是下面引用的来源)了解有关Collections框架和界面用法的更多信息。
  3. 谁说底层List实现不是ArrayList ? 无论如何, ArrayList是最常用的List实现,因此JAXB实际返回ArrayList可能性很高,它不会告诉你(因为你不需要知道)。

第52项:通过接口引用对象(摘录)

第40项包含您应该使用接口而不是类作为参数类型的建议。 更一般地说,您应该倾向于使用接口而不是类来引用对象。 如果存在适当的接口类型,则应使用接口类型声明参数,返回值,变量和字段。 您真正需要引用对象类的唯一时间是使用构造函数创建它。 为了使这个具体,请考虑Vector的情况,它是List接口的一个实现。 养成打字的习惯:

 // Good - uses interface as type List subscribers = new Vector(); 

而不是这个:

 // Bad - uses class as type! Vector subscribers = new Vector(); 

[…]

来源:有效的Java, SafariBooksOnline上的预览 。

默认情况下,该属性将是List,底层实现将是ArrayList。 当然,您可以使用JAXB自定义来更改底层实现,或者使用自己的类具有ArrayList类型的属性(尽管出于其他答案中提到的原因,这很少是一个好主意)。

默认的JAXB生成

给出您的XML Schema:

           

使用以下命令行:

 xjc -d out your-schema.xsd 

JAXB将生成以下类:

 package generated; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementRefs; import javax.xml.bind.annotation.XmlType; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "BookShelf", propOrder = { "newBookOrOldBook" }) public class BookShelf { @XmlElementRefs({ @XmlElementRef(name = "newBook", type = JAXBElement.class), @XmlElementRef(name = "oldBook", type = JAXBElement.class) }) protected List> newBookOrOldBook; public List> getNewBookOrOldBook() { if (newBookOrOldBook == null) { newBookOrOldBook = new ArrayList>(); } return this.newBookOrOldBook; } } 

定制一代

默认情况下,JAXB的属性类型为List,底层实现为ArrayList。 如果您希望控制底层实现,可以使用外部绑定文件,如:

        

以下是XJC电话:

 xjc -d out -b binding.xml your-schema.xsd 

改为获得以下课程:

 package generated; import java.util.LinkedList; import java.util.List; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementRefs; import javax.xml.bind.annotation.XmlType; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "BookShelf", propOrder = { "newBookOrOldBook" }) public class BookShelf { @XmlElementRefs({ @XmlElementRef(name = "oldBook", type = JAXBElement.class), @XmlElementRef(name = "newBook", type = JAXBElement.class) }) protected List> newBookOrOldBook = new LinkedList>(); public List> getNewBookOrOldBook() { if (newBookOrOldBook == null) { newBookOrOldBook = new LinkedList>(); } return this.newBookOrOldBook; } } 

使用自己的课程:

您也可以使用自己的类与ArrayList类型的属性(虽然由于其他答案中提到的原因,这很少是一个好主意)。

 package com.example; import java.util.ArrayList; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementRefs; import javax.xml.bind.annotation.XmlType; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "BookShelf", propOrder = { "newBookOrOldBook" }) public class BookShelf { @XmlElementRefs({ @XmlElementRef(name = "oldBook", type = JAXBElement.class), @XmlElementRef(name = "newBook", type = JAXBElement.class) }) protected ArrayList> newBookOrOldBook ; public ArrayList> getNewBookOrOldBook() { if (newBookOrOldBook == null) { newBookOrOldBook = new ArrayList>(); } return this.newBookOrOldBook; } } 

了解更多信息:

您无法更改API生成List的事实。

但是,假设底层实现实际上生成了一个ArrayList,您始终可以将其强制转换为ArrayList:

 ArrayList> arrayList = (ArrayList>) list; 

或者如果它不是一个arraylist(即你尝试上面的例外…),你可以生成一个包含列表相同元素的新ArrayList。

 ArrayList> arrayList = new ArrayList>(list); 

但是,一般情况下,您不需要执行任何操作:只要可以,就可以更好地对接口抽象进行编码而不是基础具体类。