为什么要在内部使用 MyObject[],但公开 List?
我遇到过一个具有不可变属性的类:
MyObject[] allObjs
该属性的初始化如下:
List<MyObject> objs = createAllMyObjects();
allObjs = objs.toArray(new MyObject[objs.size()]);
当它通过访问器公开时,它以列表形式完成:
public List<MyObject> getAllMyObjects() {
return Collections.unmodifiableList(Arrays.asList(allObjs));
}
程序员为什么要这样做?难道还有什么我不知道的好处吗?
性能不是问题,因为 obj 数组只会包含几十个元素。
看来我们一直在兜圈子。
该类是一种工厂,因此它有一个私有构造函数,并且仅公开静态方法(不确定这是否是疯狂的原因)。
编辑
我想我的问题确实是,“为什么不只使用内部 List
而不是 MyObject[] allObjs
,并且返回 Collections.unmodifyingList(allObjs)?”因为这会完成同样的事情。
I have come across a class that has an immutable property:
MyObject[] allObjs
The property is initialized like this:
List<MyObject> objs = createAllMyObjects();
allObjs = objs.toArray(new MyObject[objs.size()]);
When it is exposed through the accessor, it's done as a List:
public List<MyObject> getAllMyObjects() {
return Collections.unmodifiableList(Arrays.asList(allObjs));
}
Why would a programmer do this? Is there a benefit that I don't know about?
Performance is not a concern, as the array of objs will only ever number in a few dozen elements.
It seems that we are going round and round in circles.
The class is a sort of factory, so it's got a private constructor and exposes only static methods (not sure if this could be a reason for the madness).
edit
I guess that my question is really, "Why not just use an internal List<MyObject> allObjs
instead of MyObject[] allObjs
, and return the Collections.unmodifiableList(allObjs)?" as this would accomplish the same thing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我看到的唯一原因是“在滥用的情况下尽早失败”(如果这个设计选择不是随机的并且有意义,那么这意味着他很少信任他的特定客户)。
MyObject[]
是具体化的,并且在运行时检查,而List
则不是。人们可以在后者中隐藏非 MyObject 引用(当然,他会在编译时收到未经检查的警告),这将在未来某个未定义的点失败,并出现 ClassCastException ,但他不能对 < code>MyObject[] - 在误用时会立即失败。但请注意,如果客户端是在泛化之前使用此 API 的预构建二进制文件,则没有人会收到未经检查的警告,因此如果此代码尝试迁移预泛型客户端使用的代码,则这是有意义的。
(实现相同结果的另一种方法是使用
List
并且还需要Class
,以便后者可以提供运行时类型检查。但是例如,需要另一个构造函数参数 - 现有客户端不会自动利用它 **更新:** 这基本上描述了 Sauer 在第一条评论中提到的 API 调用,因此不必重新发明它,只需使用即可。那个 :) )。The only reason I see is "fail early in case of misuse" (if this design choice was not random and has a meaning, the meaning is he trusts very little his particular clients).
MyObject[]
is reified, and checked at runtime, whileList<MyObject>
is not. One can sneak non-MyObject references in the latter (he'll get unchecked warnings at compilation of course), which will fail at some undefined future point with aClassCastException
, but he cannot do the same withMyObject[]
- that will fail immediately at the point of misuse.Note though that if the clients are prebuilt binaries that was using this API before it was generified, then nobody got unchecked warnings, so if this code is trying to migrate code used by pre-generics clients, it makes sense.
(Another way to achieve the same result would be using
List<T>
and also requiringClass<T>
, so that the latter can offer the runtime type checks. But that would require for example another constructor parameter - existing clients wouldn't automatically take advantage of that. **Update: ** This basically describes the API call mentioned in the first comment by Sauer, so one does not have to reinvent this, just use that one :) ).造成这种情况的原因可能有几个:
List
更改已修补,但不想进行大规模更改。如果代码的其余部分使用该数组,则有人可能不想费心进行所有其他更改。for(:)
进行迭代但使用[]
而不是get()
进行访问。就我个人而言,这并不是使用数组的充分理由,但也许这只是我的观点。List
仍然是引用数据的方法,任何不注意其余代码(希望有注释)的人可能会尝试添加到 < code>List 这将导致运行时 UnsupportedOperationException。使其成为数组使其用法更加清晰。There may be a few reasons for this:
List
changes were patched without wanting to make wholesale changes. If the rest of the code uses the array, someone may not have wanted to bother with making all the other changes.for(:)
like a Collection but accessed with[]
instead ofget()
. Personally, not a good enough reason to use arrays but maybe that's just me.List
would still be the means for referring to the data and anyone not paying attention to the rest of the (hopefully commented) code might try to add to theList
which would result in a run-time UnsupportedOperationException. Making it an array makes it's usage clear.看来作者打算返回一个不可变的副本,但这样做是多余的。我假设选择 List 作为返回类型,以便可以使用 MyObject 类型轻松创建克隆。
It seems that the writer was intent on returning an immutable copy and has done so redundantly. I'm assuming that a List was chosen as the return type so a clone could be easily created with the MyObject type.
有充分的理由不返回对内部
MyObject[]
属性的引用。调用者可以通过引用对数组进行更改。如果没有理由结果必须是
List
,您还可以返回数组的副本:Update,在添加问题后:
您是对的,如果将内部属性更改为列表,则将其包装为不可修改会更容易。
该类使用数组而不是列表的原因可能是性能。如果数组在对象的生命周期内变化不大并且迭代次数很多,则数组的开销比 List 少。
如果性能是使用数组的原因,您可以通过存储仅用于返回的 List 来防止在 getter 中创建额外的对象,即:
像以前一样使用 allObjs 数组并在 getter 中返回存储的列表:
There is a good reason not to return a reference to the internal
MyObject[]
attribute. Via the reference changes can be made to the array by the caller.If there is no reason why the result has to be a
List
, you can also return a copy of the array:Update, after addition to the question:
You are correct that if the internal attribute is changed into a List, wrapping it to be unmodifyable is easier.
The reason why the class uses an array instead of a List might be performance. If the array does not change (much) during the lifetime of the object and is iterated a lot, an array has less overhead than a List does.
If performance is the reason for using the array, you could prevent extra object creation in the getter by storing the List for the sole purpose of being returned, i.e.:
use the allObjs array like before and return the stored list in the getter:
我用一个笑话来回答吧:
虽然我们当然可以找到一些论据来证明特定决定的合理性,但实际上这很少会产生任何影响,而且通常这样的决定背后没有任何意图。
使用最简单、最容易阅读的选项。可读性往往比聪明性更重要。
Let me answer with a joke:
While we certainly can find some arguments to justify a particular decision, in practice this rarely makes any difference and often there's no intent behind decisions like this.
Use the simplest and easiest to read option. Readability is often more important than cleverness.
我没有看到使用数组而不是列表有任何优势。列表要舒服得多。也许这家伙只是喜欢使用数组:)
I don't see any advantage in using arrays instead of lists. Lists are far more comfortable. Maybe the guy just likes working with arrays:)
我认为这背后的原因可能是数组不可修改。但是,您可以将内部列表保留为 List,并仅在 getter 中返回它的副本,这样内部列表仍然无法从外部修改。
或者使用 Collections.unmodifyingList() 返回的“不可修改”列表...
在这种情况下,我也看不到任何性能优势,因为来回转换无论如何都需要一些周期。
I think the reasoning behind this could be that the array is not modifiable. However, you could keep the internal list as a List and just return a copy of it in the getter, that way the internal list would still not be modifiable from outside.
Or use the "unmodifiable" list returned by Collections.unmodifiableList()...
In this case I don't see any performance benefit either, because the conversion back and forth anyway takes some cycles.
这种方式集合是不可修改的,即调用者不能修改成员数组。
无法使用数组执行此操作,因此编码器将其复制到列表中。
This way the collection is unmodifiable, i.e. the caller can not modify the member array.
There is no way to do this with an array so the coder copies it into a list.
在Java Generics一书中,作者实际上说既然我们有了泛型,我们就应该专门使用集合并且不应再使用数组。就我个人而言,我现在倾向于远离数组,因为集合可以帮助我记住使用集合的意图,例如。设置与列表相对于数组,它并没有真正告诉我有关数据的任何信息。
此外,除了快速复制(System.arraycopy())之外,没有任何事情是我不能对集合做的,而不能对数组做的。
In the Java Generics book, the author actually say that since we have Generics, we should use collection exclusively and should no longer use array. Personally I now tend to stay away from arrays because collections helps me remember my intention of using a collection of things eg. sets vs list as oppose to array which doesn't really tell me anything about the data.
Also there isn't anything thing that I cannot do with collections that I cannot do with an array with the exception of maybe a fast copy (System.arraycopy())