List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
我的问题是,由于List是一个接口,为什么我们可以将stooges声明为'List',而不是实现List的具体子类(例如ArrayList或LinkedList)?
这是否意味着我们可以拥有一个接口类型的引用变量?这对我来说看起来很奇怪,因为我一直认为接口仅代表多态,我们永远不应该真正使用接口类型变量。
请问有人能给我一些线索吗?
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
需要注意的是,Serializable 是一个标记接口,有点奇怪。它不能保证方法存在,而是保证实现 Serializable 接口的类的创建者已经考虑了与类序列化相关的许多问题(重写 readObject/writeObject 方法,与其他序列化形式的兼容性以及其他问题 http://www.javapractices.com/topic/TopicAction.do?Id=45)。因此,Serializable 仍然提供了一个保证,就像 List 一样,但它不是关于方法签名的,而是关于语言的一项附加特性。
在Java中,使用接口作为引用类型是一种完全合法的做法。例如,在其类内部,Serializable
接口将会这样做,以便可以序列化传递给它的任何对象。
这也是Java提供类似于多重继承的方式。例如:
public interface A { }
public class B implements A {}
public class program {
B bClass = new B();
A aObject = (A)bClass;
}
List
接口的Arrays.asList
使用哪种实现。那么你怎么知道要使用哪个?(请参阅列表接口的javadoc以查看它有哪些实现)Arrays.asList
决定使用另一种实现,您的代码将被破坏。Arrays.asList
的签名是返回List<T>
,因此,如果您想将具体实现作为变量,则必须转换返回值,这是不好的做法,或者创建新的-比如说ArrayList
-并将所有元素复制到其中,这只是不必要的开销。Effective Java by Bloch 是一本关于Java最佳实践的好书。特别是第52条讲到了这个问题:“如果存在适当的接口类型...就应该使用接口类型声明。”
总的来说,为了最大限度地提高灵活性和可理解性,您应该使用最能反映上下文的类型,通常是接口。在您提供的示例中,确切的实现是否重要,还是只要它是一个List。当然,如果代码需要ArrayList特定的方法或者代码依赖于ArrayList特定的行为,那么请使用具体类。
有时会有例外情况,比如使用GWT-RPC,但这是出于实现原因。
这是多态性的一个很好的例子,如果你感兴趣,可以在这里查看Arrays.asList()的源代码Arrays.asList(T...a),你会发现它接受可变长度的输入,并定义了自己的私有静态具体类ArrayList来实现List接口,而不是使用众所周知的java.util.ArrayList或其他JavaCollection类型,这可能是为了使其更有效率或其他原因。你想要实现自己的类并将其返回给用户,而不会通过实现细节来压倒他,因为有一个接口可以让他通过你的私有类进行处理。