我在阅读Java文档时遇到了一个奇怪的案例。以下是Arrays.asList方法http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList(T...)
上Oracle的java doc链接doc
中有一个例子List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
我的问题是,由于List是一个接口,为什么我们可以将stooges声明为'List',而不是实现List的具体子类(例如ArrayList或LinkedList)? 那么这是否意味着我们可以有一个接口类型的引用变量?它看起来很奇怪,因为我一直认为接口只代表多态,我们永远不应该真正使用接口类型变量。
有人可以给我一些线索吗?
答案 0 :(得分:3)
将List接口视为保证。任何实现List的类都将保证具有接口的方法。当Arrays.asList()返回一个List,你实际上并没有获得一个接口,你得到一个具体的类,保证实现List接口中列出的方法。
至于你的“我们永远不应该真正使用接口类型变量”,你实际上是想这样做。它被称为“编程到界面”。如果你可以返回List而不是像LinkedList这样的东西,它会更加灵活。您的方法的调用者没有耦合到您可能使用和返回LinkedList的特定实现内部实现。如果在某些时候你想要返回一个ArrayList而不是LinkedList,调用者就不必更改任何代码,因为他们只关心接口。
What does it mean to "program to an interface"?
请注意,Serializable是一个标记界面,因此有点奇怪。它并不保证方法存在,而是保证实现serializable的类的创建者已经考虑了与序列化类相关的许多问题(重写readObject / writeObject,与其他序列化形式的兼容性以及其他问题{{ 3}})。所以Serializable仍然提供像List一样的保证,但它不是关于方法签名,而是关于语言的语言特征。
答案 1 :(得分:1)
使用接口作为引用类型是Java中完全有效的实践。例如,Serializable
接口将在其类中执行此操作,以便可以序列化传递给它的任何对象。
这也是Java提供类似Multiple Inheritance的东西的方式。例如:
public interface A { }
public class B implements A {}
public class program {
B bClass = new B();
A aObject = (A)bClass;
}
这样可以使用不同的引用类型引用相同的对象,并且不会弄乱继承链!
答案 2 :(得分:0)
接口为实现定义contract
或specification
。哪种方法及其签名。因此,实现接口的类必须尊重contract
。这样,您可以更改实现,而不会影响使用接口声明变量的代码。
在你提到的例子中:
除非您查看代码,否则您不知道List
接口Arrays.asList
的实现正在使用。那么你怎么知道使用哪一个? (请参阅javadoc以获取列表界面以查看它具有的实现)
实施可能会发生变化,如果Arrays.asList
决定使用其他实施,该怎么办?您的代码将被破坏。
方法Arrays.asList
的签名是它返回List<T>
所以如果你想要一个具体的实现作为变量,你必须强制转换那个不好的做法的返回值或者创建新的 - 让我们说ArrayList
- 并将所有元素复制到其中,这只是一个不必要的开销。
答案 3 :(得分:0)
Effective Java by Bloch是一本关于Java最佳实践的好书。特别是,item #52讨论了这个问题:“如果存在适当的接口类型......使用接口类型声明。”
一般概念是,为了获得最大的灵活性和可理解性,您应该使用最能反映上下文的类型,通常是接口。在这个例子中,您提供了确切的实现,或者只是它是一个List。当然,如果代码需要特定于ArrayList的方法,或者代码依赖于特定于ArrayList的行为,那么请使用具体的类。
偶尔有例外,例如using GWT-RPC,但这是出于实施原因。
答案 4 :(得分:0)
这是多态性能力的一个很好的例子,如果你喜欢你可以在这里查看 Arrays.asList()的源代码Arrays.asList(T...a),你会发现它需要varibale长度输入并定义自己的私有静态具体类 ArrayList ,它实现 List 接口,而不是使用众所周知的 java.util.ArrayList 或其他java < em> Collection 类型, 这可能是为了使它更高效或者某种东西,你想要实现自己的类并将它返回给用户而不会被实现细节压倒他,因为有一个接口他可以通过它来处理你的私人类。