kji*_*kji 537 java interface list decoupling
(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();
Run Code Online (Sandbox Code Playgroud)
我理解,使用(1),可以交换List接口的实现.似乎(1)通常在应用程序中使用而不管需要(我自己总是使用它).
我想知道是否有人使用(2)?
此外,经常(并且我可以得到一个例子)情况实际上需要使用(1)over(2)(即where(2)不足以对接口和最佳实践等进行编码)
kgi*_*kis 426
几乎总是第一个优先于第二个.第一个优点是List可以改变(ArrayList例如)的实现,而不会影响代码的其余部分.这将是一项艰巨的任务List,不仅因为你需要改变LinkedList到ArrayList任何地方,还因为你可能已经使用了List特定的方法.
你可以阅读有关ArrayList实现此处.您可以从一开始LinkedList,但不久之后发现另一个实现更合适.
Ste*_*n C 110
我想知道是否有人使用(2)?
是.但很少有正当理由(IMO).
人们会因为ArrayList他们应该使用的List时间而被烧毁:
实用方法喜欢Collections.singletonList(...)或Arrays.asList(...)不返回ArrayList.
ListAPI中的方法不保证返回相同类型的列表.
例如,某人被烧毁,在/sf/answers/103678641/中,海报遇到"切片"问题,因为ArrayList.sublist(...)没有返回ArrayList...并且他设计了他的代码ArrayList用作类型他所有的列表变量.他最终通过将子列表复制到一个新的"解决"问题ArrayList.
您需要知道如何List通过使用RandomAccess标记接口来解决行为的问题.是的,它有点笨重,但替代方案更糟糕.
此外,情况多久经常需要使用(1)over(2)(即where(2)不足以"对接口进行编码"和最佳实践等)
问题的"多久"部分是客观上无法回答的.
(我可以举一个例子)
有时,应用程序可能需要您使用的方法ArrayListAPI是不是该在ListAPI.例如ensureCapacity(int),trimToSize()或removeRange(int, int).(最后一个只有在你创建了一个声明方法的ArrayList子类型时才会出现public.)
这是编写到类而不是接口IMO的唯一合理原因.
(从理论上讲,在某些情况下......在某些平台上......你的性能会略有改善......但除非你真的需要最后的0.05%,否则不值得这样做.这不是一个合理的理由,国际海事组织.)
如果您不知道随机访问是否有效,则无法编写有效的代码.
这是一个有效的观点.但是,Java提供了更好的方法来处理它; 例如
public <T extends List & RandomAccess> void test(T list) {
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
如果使用未实现的列表调用它,RandomAccess则会出现编译错误.
instanceof如果静态类型太笨拙,你也可以动态测试......使用... 您甚至可以编写代码以使用不同的算法(动态),具体取决于列表是否支持随机访问.
请注意,这ArrayList不是唯一实现的列表类RandomAccess.其他包括CopyOnWriteList,Stack和Vector.
我已经看到人们提出相同的论点Serializable(因为List没有实现它)......但上面的方法也解决了这个问题.(在某种程度上,它可以使用运行时类型完全解决.ArrayList如果任何元素不可序列化,则会导致序列化失败.)
Max*_*tin 39
例如,您可能认为a LinkedList是您的应用程序的最佳选择,但后来决定ArrayList可能是性能原因的更好选择.
使用:
List list = new ArrayList(100); // will be better also to set the initial capacity of a collection
Run Code Online (Sandbox Code Playgroud)
代替:
ArrayList list = new ArrayList();
Run Code Online (Sandbox Code Playgroud)
以供参考:

(主要用于收集图)
naz*_*art 24
将引用存储在一个或类型为Set的变量中被认为是好的样式.HashSetTreeSet
Set<String> names = new HashSet<String>();
这样,如果您决定使用TreeSet替换,则只需更改一行.
此外,对集合进行操作的方法应指定Set类型的参数:
public static void print(Set<String> s)
然后,该方法可用于所有集合实现.
理论上,我们应该对链表做出相同的建议,即在List类型的变量中保存LinkedList引用.但是,在Java库中,List接口ArrayList对于LinkedList类和类都是通用的.特别是,它具有获取和设置随机访问的方法,即使这些方法对于链表非常低效.
你可以不写高效的代码,如果你不知道随机访问是否是有效与否.
这显然是标准库中的一个严重的设计错误,因此我不建议使用List接口.
要查看错误是多么令人尴尬,请查看Collections类binarySearch方法的源代码.该方法采用List参数,但二进制搜索对链表没有意义.然后代码笨拙地试图发现列表是否是链表,然后切换到线性搜索!
在Set接口和Map接口,都是精心设计的,你应该使用它们.
maz*_*ork 13
如果代码是列表的"所有者",我使用(2).例如,对于仅本地变量,这是真的.没有理由使用抽象类型List而不是ArrayList.另一个证明所有权的例子:
public class Test {
// This object is the owner of strings, so use the concrete type.
private final ArrayList<String> strings = new ArrayList<>();
// This object uses the argument but doesn't own it, so use abstract type.
public void addStrings(List<String> add) {
strings.addAll(add);
}
// Here we return the list but we do not give ownership away, so use abstract type. This also allows to create optionally an unmodifiable list.
public List<String> getStrings() {
return Collections.unmodifiableList(strings);
}
// Here we create a new list and give ownership to the caller. Use concrete type.
public ArrayList<String> getStringsCopy() {
return new ArrayList<>(strings);
}
}
Run Code Online (Sandbox Code Playgroud)
wzb*_*zon 11
List实际上,当您编写时,您的对象List仅实现了接口,但您没有指定对象所属的类.
编写时ArrayList,指定对象类是可调整大小的数组.
因此,第一个版本将使您的代码在未来更加灵活.
看看Java文档:
类ArrayList -List接口的可调整大小的数组实现.
接口List - 有序集合(也称为序列).该接口的用户可以精确控制列表中每个元素的插入位置.
Array - 容器对象,其包含固定数量的单个类型的值.
(3)Collection myCollection = new ArrayList();
我通常使用这个.而只有当我需要列出方法,我将使用清单.与ArrayList相同.你总是可以切换到更"窄"的界面,但你不能切换到更"宽".
实际上有些情况下(2)不仅是首选而是强制性的,我很惊讶,没有人在这里提到这一点.
序列化!
如果你有一个可序列化的类,并且你希望它包含一个列表,那么你必须声明该字段是具体的和可序列化的类型,ArrayList因为List接口不会扩展java.io.Serializable
显然大多数人不需要序列化而忘记了这一点.
一个例子:
public class ExampleData implements java.io.Serializable {
// The following also guarantees that strings is always an ArrayList.
private final ArrayList<String> strings = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)
在以下两个中:
(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();
Run Code Online (Sandbox Code Playgroud)
首先通常是优选的.由于您将仅使用List接口中的方法,因此它为您提供了使用其他实现的自由,List例如LinkedList将来.因此它将您与特定实现分离.现在有两点值得一提:
我想知道是否有人使用(2)
有时是(很少读).当我们需要的方法是实现ArrayList但不是接口的一部分时List.例如ensureCapacity.
此外,多久(我可以得到一个例子)情况实际上需要使用(1)over(2)
几乎总是你更喜欢选项(1).这是OOP中的经典设计模式,您始终尝试将代码从特定实现和程序与接口分离.
列表是一个接口。它没有方法。当您调用 List 引用上的方法时,实际上在这两种情况下都会调用 ArrayList 的方法。
将来您可以更改List obj = new ArrayList<>为 List obj = new LinkList<>或其他实现List 接口的类型。
| 归档时间: |
|
| 查看次数: |
386077 次 |
| 最近记录: |