为什么要在内部使用MyObject [],但是公开List <myobject>?</myobject>

时间:2010-04-08 12:21:10

标签: java arrays collections

我遇到过一个具有不可变属性的类:

MyObject[] allObjs

该属性初始化如下:

List<MyObject> objs = createAllMyObjects();
allObjs = objs.toArray(new MyObject[objs.size()]);

当它通过访问者公开时,它以列表形式完成:

public List<MyObject> getAllMyObjects() {
    return Collections.unmodifiableList(Arrays.asList(allObjs));
}

为什么程序员会这样做?有什么好处我不知道吗?

性能不是一个问题,因为objs数组只会在几十个元素中出现。

似乎我们正在四处转圈。

这个类是一种工厂,所以它有一个私有的构造函数,只暴露静态方法(不确定这是否是疯狂的原因)。

修改

我想我的问题确实是,“为什么不使用内部List<MyObject> allObjs代替MyObject[] allObjs,并返回Collections.unmodifiableList(allObjs)?”因为这会完成同样的事情。

9 个答案:

答案 0 :(得分:6)

我看到的唯一原因是“在误用的情况下提前失败”(如果这种设计选择不是随机的并且有意义,那么他的信任很少就是他的特定客户)。

MyObject[] 具体化在运行时检查,而List<MyObject>则不然。可以在后者中隐藏非MyObject引用(当然,他会在编译时得到未经检查的警告),这将在ClassCastException的某个未定义的未来点失败,但他不能对{{1}做同样的事情。 - 在滥用时会立即失败。

请注意,如果客户端是在生成之前使用此API的预构建二进制文件,那么没有人会收到未经检查的警告,因此如果此代码尝试迁移前泛型客户端使用的代码,则这是有意义的。

(实现相同结果的另一种方法是使用MyObject[]并且还需要List<T>,以便后者可以提供运行时类型检查。但这需要例如另一个构造函数参数 - 现有的客户端不会自动利用它。**更新:**这基本上描述了Sauer在第一条评论中提到的API调用,因此不需要重新发明这个,只需使用那个:))。

答案 1 :(得分:2)

可能有几个原因:

  • 他们不知道他们在做什么。我现在正在编写代码,似乎是由Java新手和编程新手编写的。不幸的是,遇到设计不良的代码比找到一个对平台有深入了解的人编写的好的,干净的,维护良好的代码更为常见。部分原因在于下一点。
  • List更改已修补,无需进行批量更改。如果代码的其余部分使用该数组,则可能没有人想要进行所有其他更改。
  • 虽然集合是更多的OO / Java方式,但如果列表是静态的,则数组实际上“更容易”使用,因为它们仍然可以像for(:)一样迭代,但是可以通过[]代替get()。就个人而言,使用阵列的理由还不够,但也许只是我。
  • 也许他们希望明确数据的长度为 final 。如果他们刚刚使用了不可修改的列表,那么List仍然是引用数据的手段,任何不注意其余(希望注释的)代码的人都可能会尝试添加到{{1}这将导致运行时UnsupportedOperationException。使它成为一个数组使它的用法清晰。

答案 2 :(得分:1)

似乎作者想要返回一个不可变的副本并且已经冗余地完成了。我假设选择了List作为返回类型,因此可以使用MyObject类型轻松创建克隆。

答案 3 :(得分:1)

有充分的理由不返回对内部MyObject[]属性的引用。通过引用,调用者可以对数组进行更改。

如果没有理由为什么结果必须是List,您还可以返回数组的副本:

public MyObject[] getAllMyObjects() {
    MyObject[] result = new MyObject[allObjs.length];
    system.ArrayCopy(allObjs, 0, result, 0, result.length);
    return result;
}
在添加问题后,

更新: 你是正确的,如果将内部属性更改为List,则将其包装为不可修改更容易。

类使用数组而不是List的原因可能是性能。如果数组在对象的生命周期内没有发生太多变化并且经过多次迭代,那么数组的开销就比List少。

如果性能是使用数组的原因,你可以通过存储List来防止在getter中创建额外的对象,仅用于返回,即:

allObjsList = Collections.unmodifiableList(createAllMyObjects());
allObjs = allObjsList.toArray(new MyObject[allObjsList.size()]);

像以前一样使用allObjs数组,并在getter中返回存储的列表:

public List<MyObject> getAllMyObjects() {
    return allObjsList ;
}

答案 4 :(得分:1)

让我回答一个笑话:

  

这位新犹太新娘正在为她的丈夫做第一次大餐,并尝试用她母亲的牛腩配方,以她母亲的方式切断烤肉。 Hubby认为肉是美味的,但是,“你为什么要切断两端 - 这是最好的部分!”她回答说,“这就是我母亲总是这样做的。

     

下周他们去了老布比的房子,她准备了着名的胸肉配方,再次切断了两端。年轻的新娘确信她一定会遗漏一些重要的信息,所以她问奶奶为什么要切断两端。奶奶说,“Dahlink,这是它适合平底锅的唯一方式!”

虽然我们当然可以找到一些论证来证明某一特定决定的合理性,但在实践中,这很少会产生任何影响,并且通常没有这样的决定背后的意图。

使用最简单易读的选项。可读性通常比聪明更重要。

答案 5 :(得分:0)

我认为使用数组而不是列表没有任何优势。列表更舒适。也许那个人喜欢使用数组:)

答案 6 :(得分:0)

我认为这背后的原因可能是数组不可修改。但是,您可以将内部列表保留为List,并在getter中返回它的副本,这样内部列表仍然无法从外部修改。

或使用Collections.unmodifiableList()返回的“不可修改”列表......

在这种情况下,我也没有看到任何性能优势,因为无论如何来回转换需要一些周期。

答案 7 :(得分:0)

这种方式集合是不可修改的,即调用者不能修改成员数组。 无法使用数组执行此操作,因此编码器会将其复制到列表中。

答案 8 :(得分:0)

Java Generics书中,作者实际上说,由于我们有泛型,我们应该专门使用集合,不应该再使用数组。我个人现在倾向于远离数组,因为集合帮助我记住了使用一系列事物的意图,例如。将vs vs list作为对阵数组的对象,它并没有真正告诉我有关数据的任何信息。

除了可能是快速复制(System.arraycopy())

之外,对于我不能用数组做的集合没有任何我无法做的事情。