JAXB可以生成ArrayList而不是List吗?
JAXB以List<JAXBElement>
生成属性。 有没有什么方法可以生成ArrayList?
为什么,那对你有什么好处?
-
ArrayList
没有不在List
接口中的公共方法,因此您无法使用ArrayList
执行任何其他List
(实际上只有一个) :ArrayList.trimToSize()
,谢谢@Joachim Sauer,但几乎不需要)。 - API接受或返回实现类型而不是底层接口是非常糟糕的做法。 我建议你按照Sun Java Tutorial的Collections Trail和/或阅读Joshua Bloch的Effective Java (你会从这个简短的预览中了解他正在谈论的内容,这是下面引用的来源)了解有关Collections框架和界面用法的更多信息。
- 谁说底层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);
但是,一般情况下,您不需要执行任何操作:只要可以,就可以更好地对接口抽象进行编码而不是基础具体类。