Type List vs type ArrayList in Java
1 2 3 | (1) List<?> myList = new ArrayList<?>(); (2) ArrayList<?> myList = new ArrayList<?>(); |
我理解使用(1)可以交换列表接口的实现。似乎(1)通常用于应用程序中,而不管需要什么(我自己总是使用这个)。
我想知道是否有人使用(2)?
此外,这种情况实际需要使用(1)到(2)的频率(我能举一个例子吗)(即,除了对接口和最佳实践的编码之外,(2)还不够。)
几乎总是第一个优先于第二个。第一种方法的优点是,
您可以在这里阅读
I am wondering if anyone uses (2)?
对。但很少有合理的理由(IMO)。
当人们本应使用
像
Collections.singletonList(...) 或Arrays.asList(...) 这样的实用方法不会返回ArrayList 。List API中的方法不保证返回相同类型的列表。
例如,在https://stackoverflow.com/a/1481123/139985中,由于
您需要了解
Also, how often does the situation actually require using (1) over (2) (i.e. where (2) wouldn't suffice..aside 'coding to interfaces' and best practices etc.)
问题的"多久"部分在客观上是无法回答的。
(and can I please get an example)
有时,应用程序可能要求您在
这是编码到类而不是接口IMO的唯一合理原因。
(理论上,你的表现可能会略有改善……在某些情况下…在某些平台上…但除非你真的需要最后的0.05%,否则这样做是不值得的。这不是一个合理的理由,依我看。)
You can’t write efficient code if you don’t know whether random access is efficient or not.
这是一个有效的观点。然而,Java提供了更好的处理方法;
1 2 3 |
如果用一个不实现
您还可以动态测试…使用
注意,
我看到人们对
例如,您可能认为
用途:
而不是:
供参考:
(主要发布用于收集图表)
在类型集变量中存储对
这样,如果您决定使用
此外,对集合进行操作的方法应指定集合类型的参数:
然后该方法可以用于所有集合实现。
理论上,我们应该对链表提出同样的建议,即保存类型列表变量中的LinkedList引用。然而,在Java库中,列表接口对于EDCOX1、0和EDCOX1 9个类都是通用的。特别是,它有用于随机访问的get和set方法,即使这些方法对于链表效率非常低。
如果不知道随机访问是否有效,就不能编写有效的代码。
这显然是标准库中的严重设计错误,我不建议使用因为这个原因,列表接口。
看看这个错误有多尴尬collections类的
如果代码是列表的"所有者",则使用(2)。例如,对于局部变量,这是正确的。没有理由使用抽象类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); } } |
当您编写
编写
因此,第一个版本使您的代码在将来更加灵活。
查看Java文档:
类
接口
事实上,有时(2)不仅是首选,而且是强制性的,我很惊讶,这里没有人提到这一点。
序列化!
如果您有一个可序列化类,并且希望它包含一个列表,那么您必须声明该字段是一个具体的、可序列化的类型,如
显然,大多数人不需要序列化,而忘记了这一点。
一个例子:
1 2 3 4 | public class ExampleData implements java.io.Serializable { // The following also guarantees that strings is always an ArrayList. private final ArrayList<String> strings = new ArrayList<>(); |
我认为使用(2)的人不知道Liskov替换原则或依赖倒置原则。或者他们真的必须使用
(3)collection myCollection=new arraylist();
我通常使用这个。只有当我需要列表方法时,我才会使用列表。与arraylist相同。您总是可以切换到更"窄"的界面,但不能切换到更"宽"的界面。
以下两项中的一项:
1 2 | (1) List<?> myList = new ArrayList<?>(); (2) ArrayList<?> myList = new ArrayList<?>(); |
通常首选第一种。由于您将只使用来自
I am wondering if anyone uses (2)
是的,有时(很少阅读)。当我们需要的方法是
Also, how often (and can I please get an example) does the situation
actually require using (1) over (2)
几乎总是你喜欢选项(1)。这是OOP中的一个经典设计模式,您总是试图将代码从特定的实现和程序分离到接口。
有人再次问这个问题(副本),这让我在这个问题上做得更深入了。
1 2 3 4 5 6 7 8 9 10 | 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),我们会怎么做?我看到下面的列表片段(仅列表初始化和分配):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
对于主义者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
区别在于列表最终调用invokeInterface,而alist调用invokeVirtual。根据bycode大纲插件引用,
invokeinterface is used to invoke a method declared within a Java
interface
调用虚拟机时
invokes all methods except interface methods (which use
invokeinterface), static methods (which use invokestatic), and the few
special cases handled by invokespecial.
总之,invokeVirtual在invokeInterface中从堆栈中弹出ObjectRef
the interpreter pops 'n' items off the operand stack, where 'n' is an 8-bit unsigned
integer parameter taken from the bytecode. The first of these items is
objectref, a reference to the object whose method is being called.
如果我正确理解这一点,那么区别主要在于每种方法如何检索objectref。
列表是一个接口。它没有方法。在列表引用上调用方法时。实际上,它在这两种情况下都调用arraylist方法。
以后可以把
我唯一知道(2)更好的地方是在使用GWT时,因为它减少了应用程序的占地面积(不是我的想法,但是GoogleWebToolkit团队这么说)。但是对于JavaM(1)内部运行的普通Java可能总是更好。
1 2 3 | ArrayList<Object> myMethod (ArrayList<Object> input) { // body } |
您只能将它与
1 2 3 | List<Object> myMethod (List<Object> input) { // body } |
在这个方法参数中,您可以使用任何您想要使用的
1 2 3 4 5 | List<Object> list = new ArrayList<Object> (); list.add ("string"); myMethod (list); |
结论:
尽可能在任何地方使用接口,不要限制您或其他人使用他们想要使用的不同方法。
我想说1是首选,除非
- 您依赖于arraylist中可选行为*的实现,在这种情况下,显式地使用arraylist更清楚
- 您将在需要arraylist的方法调用中使用arraylist,可能用于可选的行为或性能特征。
我的猜测是,在99%的情况下,你可以通过列表,这是首选。
- 例如,
removeAll 或add(null) 。