为了账号安全,请及时绑定邮箱和手机立即绑定

在 Java 中由接口引用的对象的新实例

在 Java 中由接口引用的对象的新实例

互换的青春 2022-09-07 17:03:46
我正在做一个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 中传递的参数的副本,但我不想通过将引用声明为 List 接口的特定实现来将其专用化为方法签名:取决于 pojo 的使用位置,可以是 LinkedList 或 ArrayList 等。idssetIdids我想保持参数的相同实现。ids我该如何复制?我想到的第一件事是:,但它需要被InstantiationException和TrastralleAccessException的try/catch块包围,特别是因为我不确定的实际实现是否有一个空的构造函数。有没有更直接的东西?ids.getClass().newInstance()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();}强制使用一个类来实现也可以克隆,但可克隆接口的javadoc很好地解释了为什么这不起作用(以及为什么对克隆的反射也不会起作用):类实现接口以向该方法指示该方法对该类的实例进行字段对字段复制是合法的。Cloneable在未实现接口的实例上调用 Object 的 clone 方法会导致引发异常。CloneableCloneNotSupportedException按照约定,实现此接口的类应使用公共方法重写 Object.clone(受保护)。有关重写此方法的详细信息,请参阅。请注意,此接口不包含克隆方法。因此,仅凭它实现此接口这一事实就不可能克隆对象。即使以反射方式调用了 clone 方法,也不能保证它会成功。最后,无论上下文如何,我问题的答案有没有更直接的东西?是“不”,很可能是因为不应该有做这件事的需要......即使。。https://rules.sonarsource.com/java/type/Vulnerability/RSPEC-2384
查看完整描述

3 回答

?
慕村9548890

TA贡献1884条经验 获得超4个赞

正如你自己所说:

我想到的第一件事是:ids.getClass().newInstance(),但它需要被InstantiationException和TrastralyAccessException的try/catch块包围,特别是因为我不确定ids的实际实现是否有一个空的构造函数。有没有更直接的东西?

当您甚至不知道构造函数的样子时,如何构造基础类的实例?通过反射,你知道一个(可能有多个)构造函数是什么样子的,你仍然需要担心这样的事情:

  • 私有 vs 内部/包私有 vs 公共 - 您如何处理每个案例?一些实现,例如在番石榴库中找到的那些,使用构建器模式来构造集合,从而使构造函数私有。List

  • 构造函数参数的数量 - 如果有多个,如何构造其余参数?

  • 构造函数引发的异常 - 如何捕获所有异常?不要说“抓住”,因为你可能会错过。ExceptionThrowable

  • 多个构造函数 - 如何决定调用哪个构造函数?

  • 还有更多的角落案例需要处理...


您应该采用 KISS (Keep ISimple Soldier) 原则以及 SoC (Separation oConcerns) 原则。保持简单,你会得到回报。让使用 Pojo 的人决定如何检索列表。只要您(通过文档)明确说明该方法的作用,就由用户决定如何使用该方法做出理性的决定。

如果他们做这样的事情:

LinkedList<Integer> myIds = ...;
myPojo.setIds(myIds);

然后让他们决定如何检索 ;他们可以强制转换返回的类型或制作副本。ids

如果您在文档中明确指出该列表已复制,则使用此 POJO 的人在检索它时应该知道要将其作为副本进行复制,否则他们应该安全地将列表转换为 .LinkedListLinkedList


我仍然认为,即使是上述内容也不够简单。最简单的方法(这是被广泛接受的)是使用最通用的类型来完成所需的工作。如果需要映射类型,请使用 、而不是 元组 或 元组;如果您需要一个唯一的集合,请使用 ,如果您需要一个通用的集合,请使用 等。MapHashMapList/SetSetList


查看完整回答
反对 回复 2022-09-07
?
慕神8447489

TA贡献1780条经验 获得超1个赞

有没有更直接的东西?

有两种可能的方法可以做到这一点:

  • 您建议的方法:使用反射调用 no-args 构造函数,创建一个新的空列表,然后用于将元素复制到新列表。List::addAll

  • 使用该方法创建副本。Object::clone

任何一种方法(如果有效!)都将创建与原始类型相同的列表对象。但是,这两种方法都不能保证适用于所有可能的类。List

  • 如果列表实现类没有可用/可访问的无参数构造函数,则反射方法将失败。

  • 如果列表实现类未正确重写,则此方法将失败。cloneObject::clone

请注意,这些不是假设的问题。列表实现类可能被特意设计为防止程序克隆列表。例如,列表和(比如)数据库查询结果集之间可能存在某种关系,因此克隆毫无意义。

但另一方面,如果库设计人员没有提供无参数构造函数或重写,他们这样做可能是有充分理由的。clone


最后,您应该尝试这样做是值得怀疑的。类属性没有明显的理由使用与原始参数相同的类。这实际上使行为类依赖于所提供列表的行为。我认为这是一件坏事,因为你正在削弱你的类的抽象边界。MyPojoidsListMyPojoMyPojo


查看完整回答
反对 回复 2022-09-07
?
月关宝盒

TA贡献1772条经验 获得超5个赞

例如,您可以使用Arrays.asList


public void setIds(List<Integer> ids) {

    this.ids = Arrays.asList(ids.toArray(new Integer[ids.size()]));

}

这应该适用于Java 1.6


查看完整回答
反对 回复 2022-09-07
  • 3 回答
  • 0 关注
  • 151 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号