(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();
我知道,对于(1),List接口的实现可以交换。似乎(1)通常在应用程序中使用,无论是否需要(我自己总是使用它)。
我想知道是否有人使用(2)?
此外,情况实际上需要使用(1)而不是(2)的频率是多少(请给我一个例子)(即(2)是不够的..除了编码到接口和最佳实践等)。
(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();
我知道,对于(1),List接口的实现可以交换。似乎(1)通常在应用程序中使用,无论是否需要(我自己总是使用它)。
我想知道是否有人使用(2)?
此外,情况实际上需要使用(1)而不是(2)的频率是多少(请给我一个例子)(即(2)是不够的..除了编码到接口和最佳实践等)。
当前回答
列表接口有几个不同的类——ArrayList和LinkedList。LinkedList用于创建索引集合,ArrayList用于创建排序列表。你可以在你的参数中使用它,但是你可以允许其他使用你的代码,库等的开发人员使用不同类型的列表,而不仅仅是你在这个方法中使用的
ArrayList<Object> myMethod (ArrayList<Object> input) {
// body
}
你只能在ArrayList中使用它,而不是LinkedList,但是你可以允许在其他地方使用它的方法,这只是你的选择,所以使用接口可以允许它:
List<Object> myMethod (List<Object> input) {
// body
}
在这个方法参数中,你可以使用任何你想使用的List类:
List<Object> list = new ArrayList<Object> ();
list.add ("string");
myMethod (list);
结论:
尽可能在任何地方使用接口,不要限制您或其他人使用他们想要使用的不同方法。
其他回答
我所知道的(2)可以更好的唯一情况是使用GWT,因为它减少了应用程序的占用空间(不是我的想法,但谷歌web工具包团队是这么说的)。但是对于在JVM(1)中运行的常规java来说,可能总是更好。
有人又问了这个问题(重复),这让我在这个问题上更深入了一些。
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
ArrayList<String> aList = new ArrayList<String>();
aList.add("a");
aList.add("b");
}
如果我们使用字节码查看器(我使用http://asm.ow2.org/eclipse/index.html) weĺl看到以下(仅列表初始化和赋值)为我们的列表片段:
L0
LINENUMBER 9 L0
NEW ArrayList
DUP
INVOKESPECIAL ArrayList.<init> () : void
ASTORE 1
L1
LINENUMBER 10 L1
ALOAD 1: list
LDC "a"
INVOKEINTERFACE List.add (Object) : boolean
POP
L2
LINENUMBER 11 L2
ALOAD 1: list
LDC "b"
INVOKEINTERFACE List.add (Object) : boolean
POP
对于alist来说:
L3
LINENUMBER 13 L3
NEW java/util/ArrayList
DUP
INVOKESPECIAL java/util/ArrayList.<init> ()V
ASTORE 2
L4
LINENUMBER 14 L4
ALOAD 2
LDC "a"
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
L5
LINENUMBER 15 L5
ALOAD 2
LDC "b"
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
区别在于list调用INVOKEINTERFACE,而aList调用invokvirtual。根据Bycode大纲插件参考,
invokeinterface用于调用Java中声明的方法 接口
虽然invokevirtual
调用除接口方法(使用 Invokeinterface)、静态方法(使用invokestatic)等等 特殊情况由invokspecial处理。
总之,invokvirtual从栈中弹出objectref,而对于invokeinterface
解释器从操作数堆栈中取出'n'项,其中'n'是8位无符号 从字节码获取的整数参数。第一项是 Objectref,对正在调用其方法的对象的引用。
如果我理解正确的话,区别基本上是每种方法检索objectref的方式。
(3) Collection myCollection = new ArrayList<?>();
我通常用这个。只有当我需要List方法时,我才会使用List。数组列表也是一样。你总是可以切换到更“窄”的界面,但你不能切换到更“宽”的界面。
我会说1是首选,除非
你依赖于ArrayList中可选行为*的实现,在这种情况下显式使用ArrayList更清楚 你将在一个需要ArrayList的方法调用中使用ArrayList,可能用于可选的行为或性能特征
我的猜测是,在99%的情况下,您可以使用List,这是首选。
为实例removeAll,或add(null)
事实上,有些情况下(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<>();