我正在从事 JDK6项目。
我有一个类似的pojo:
public class MyPojo implements serializable {
private List<Integer> ids;
public List<Integers> getIds() {
return ids;
}
public List<Integers> setIds(List<Integer> ids) {
// idsCopy = copy of ids; // how can I do it?
this.ids = idsCopy;
}
}
我想存储在setter中传递的参数ids
的副本,但是我不想通过将引用声明为特定实现来专门用于setId
方法签名中。 List接口的功能:根据使用pojo的位置,ids
可以是LinkedList或ArrayList等。
我想保留ids
参数的相同实现。
我该怎么做?
我想到的第一件事是:ids.getClass().newInstance()
,但是它必须被InstantiationException和IllegalAccessException的try / catch块包围,尤其是因为我不确定ids
的实际实现有一个空的构造函数。还有更直接的东西吗?
更新 在这种情况下,最常见,直接和合理的做法是避免进行复制,而让使用MyPojo类的人传递要设置的对象的副本,例如:
List<Integer> ls = new Arraylist<>();
MyPojo pj = new MyPojo();
pj.setIds(ls.clone()); // or using copy constructor or anything else..
一开始我就有这样的想法:
public <T extends List<Integer> & Cloneable> void setIds(T ids) {
this.ids = ids.clone();
}
使用也实现了Cloneable的类来强制执行,但Cloneable接口的javadoc很好地解释了为什么它不起作用(以及为什么对克隆的反射也不会如此):
一个类实现了
Cloneable
接口 指示方法 使用该方法制作 该类实例的字段间复制。在未实现该实例的实例上调用Object的clone方法
Cloneable
界面导致异常CloneNotSupportedException
被抛出。按照约定,实现此接口的类应重写 使用公共方法的Object.clone(受保护的)。 请参阅有关覆盖此内容的详细信息 方法。
请注意,此接口不包含clone方法。 因此,不可能仅仅依靠 它实现了此接口的事实。即使调用了clone方法 反思地,并不能保证它会成功。
最后,无论上下文如何,我的问题的答案
还有更直接的东西吗?
是“否”,很可能是因为不需要这样做... ..即使..
答案 0 :(得分:0)
还有更直接的东西吗?
有两种可能的方法:
您建议的方法:使用反射调用no-args构造函数以创建一个新的空列表,然后使用List::addAll
将元素复制到新列表中。
使用Object::clone
方法创建副本。
这两种方法(如果可行)都将创建与原始对象相同类型的列表对象。但是,没有一种方法可以保证对所有可能的List
类都适用。
如果列表实现类没有可用/可访问的无参数构造函数,则反射方法将失败。
如果列表实现类未适当覆盖clone
,则Object::clone
方法将失败。
请注意,这些不是假设的问题。可以故意设计列表实现类,以防止程序克隆列表。例如,列表与数据库查询结果集(例如)之间可能存在某种关系,因此克隆毫无意义。
但是另一方面,如果库设计人员没有提供无参数的构造函数或clone
覆盖,则他们可能这样做是有充分的理由。
最后,值得怀疑的是,您是否应该尝试完全做到这一点。没有明显的理由让您的MyPojo
类ids
属性使用与原始参数相同的List
类。这实际上使行为MyPojo
类取决于所提供列表的行为。我认为这是一件坏事,因为您正在削弱MyPojo
类的抽象边界。
答案 1 :(得分:0)
就像你自己说的那样:
我想到的第一件事是:ids.getClass()。newInstance(),但它 对于InstantiationException,需要用try / catch块包围 和IllegalAccessException,尤其是因为我不确定 id的实际实现具有空的构造函数。在那儿 更直接的事情?
当您甚至不知道构造函数的外观时,将如何构造一个基础类的实例?通过反射说,您知道 a (可能不止一个)构造函数的样子,您仍然需要担心以下问题:
List
的某些实现(例如在guava库中找到的实现)使用构建器模式来构造集合,因此将构造器设为私有。Exception
”,因为您可能会错过Throwable
。您应采用KISS( K 深我 t S 简单 S 较旧)的原则,以及SoC( S 分隔 o f C oncerns)原则。保持简单,您将得到回报。让使用Pojo的人决定如何检索列表。只要您(通过文档)明确说明了该方法的作用,就应该由用户对他们如何使用该方法做出合理的决定。
如果他们做类似的事情:
LinkedList<Integer> myIds = ...;
myPojo.setIds(myIds);
然后让他们决定如何检索ids
;他们可以转换返回的类型或进行复制。
如果您在文档中明确指出已复制列表,则使用此POJO的人员在检索列表时应知道将其复制为LinkedList
,否则应该安全地进行投射到LinkedList
的列表。
我仍然会争辩说,即使以上内容也不够简单。最简单的方法(这是被广泛接受的方法)是使用最通用的类型进行所需的工作。如果需要映射类型,请使用Map
,而不要使用HashMap
或List/Set
元组;如果需要唯一集合,请使用Set
,如果需要常规集合,请使用List
,等等。
答案 2 :(得分:-1)
例如,您可以使用Arrays.asList
public void setIds(List<Integer> ids) {
this.ids = Arrays.asList(ids.toArray(new Integer[ids.size()]));
}
这应该适用于Java 1.6