开发Java,你总是通过使用List接口作为存储列表的变量的类型来学习创建ArrayList的最佳方法。像这样
List<String> myList = new ArrayList<String>();
但是,通过查看包中包含的很多android示例,他们已经使用Class创建了列表。
ArrayList<String> myList = new ArrayList<String>();
为什么这样做有什么理由?它是更快,更轻还是明确设置类的东西?
答案 0 :(得分:12)
我建议阅读Performance Myths,它解释了将变量定义为List或ArrayList的优点和问题。
答案 1 :(得分:10)
就个人而言,我相信“你一直学到的东西”错过了重点。这样:
List<String> myList = new ArrayList<String>();
维护效益很小。如果要将其更改为其他实现,则在使用实现类型时仍然只需更改一行。但是,完全不同的事情是:
public void process(List<String> list) {
在这里,使用接口非常重要,因为它允许调用该方法的人使用不同的实现,而不得不更改方法签名(他们可能无法使用做)。
答案 2 :(得分:9)
在像Android设计的手机这样的资源受限环境中,最好避免使用Interface,因为它涉及额外的虚拟函数调用。
答案 3 :(得分:2)
虽然可能会带来性能优势,但它几乎肯定很小,并且是过早优化的一个例子。
更可能的解释是,这些例子的作者希望让你专注于他(或她)试图教你的事情。保持变量和它引用的对象相同的类型是一个值得思考的东西。发布的代码示例是一种代码,当您非常确定永远不必修改它时,在这种情况下,使用ArrayList作为变量类型是完全正确的。
答案 4 :(得分:1)
编译在List&lt;&gt;上运行的代码时对象,编译器必须使用接口调用,这比在具体类型上的常规虚拟调用更昂贵。
当然,在一段代码中,编译器看到正在实例化的对象,并且可以证明某些内容被声明为List&lt;&gt;始终是一个ArrayList&lt;&gt;,编译器应该只能发出一个常规调用而不是一个接口调用,但是没有内联并对已经实例化的对象进行操作的方法不会从这个优化中受益。
普遍使用的加速虚拟调用的优化,即内联缓存(通常是多态内联缓存或PIC,不要与位置无关代码混淆),受益于观察到只有一个子类的实例通过某种声明类型的变量。在这种情况下,在代码运行了一段时间之后,JIT可以乐观地猜测List&lt;&gt;对象将只是一个ArrayList&lt;&gt;,在猜测错误的情况下生成一个陷阱,然后使用ArrayList&lt;&gt;调用
现代处理器非常快速地执行检查(因为它们是超标量且具有良好的分支预测),因此您不会注意到所有这些虚拟调用和单个实现接口调用的成本。但它确实使VM工作变得困难,检测,生成和修补所有代码。
对于在HotSpot上以稳定状态运行的服务器软件,它无关紧要,但是为了在移动设备上快速启动它可能会有所不同 - 我不知道Google的VM有多好。
一篇关于它的好文章由Cliff Click,Jr。博士(自定义大铁硬件,热点虚拟机): http://www.azulsystems.com/blog/cliff-click/2010-04-08-inline-caches-and-call-site-optimization
当然还有维基百科上的“内联缓存”。
答案 5 :(得分:1)
Interface x = new Implementation()
模式是一种流行的天真的抽象尝试。
变量声明和初始化语句Type x = new Constructor();
绝对是实现细节的一部分。它不是公共API的一部分(除非是public final
,但List是可变的,因此不合适)
作为一个实施细节,我们是谁试图愚弄这种“抽象”?最好保持类型尽可能具体。它是数组列表还是链表?它应该是线程安全吗?选择对于实现很重要,我们仔细选择了具体的列表。然后我们宣布它只是一个列表,好像它没关系,我们不在乎?
将其声明为List的唯一合理理由是我懒得输入。这也涵盖了如果我需要移动到另一个列表impl的论点,我只有一个地方可以修改。
这个原因只有在变量范围很小的情况下才合法,我们可以一目了然地看到它的所有用法。否则,声明最具体的类型,以便在使用该变量的所有代码中显示其性能和语义特征。
答案 6 :(得分:0)
除了在Android示例中他们使用更明确的类型之外,没有太大区别。也许有些Android方法依赖于接收ArrayList而不仅仅是List。
答案 7 :(得分:0)
这是一个众所周知的“设计原则”,关于如何制作一个好的设计,“程序到界面,而不是实现”。就像Michael Borgwardt所说的那样,也许它并不关心将这个原则与你的局部变量一起使用,但如果你有类型之间的关联,那么编程到接口而不是实现使用的好处是有意义的。 OOP。实现接口而不是impl允许在运行时进行动态多态分配。比方说,
interface IAa { say(); }
class A implements IAa { public void say() { .. says A ... } }
class B implements IAa { public void say() { .. says B ... } }
class App {
public void someFoo() {
IAa myA = new A();
myA.say(); // says A
myA = new B();
myA.say(); // says B
}
...
}
我不认为,Android编程会有所不同:)