繁体   English   中英

关于Java接口和多态

[英]About the Java interface and polymorphism

我在阅读Java doc时遇到了一个奇怪的案例。 以下是Arrays.asList方法中Oracle java文档的链接, http: //docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList (T ...)

文档中有一个例子

List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");

我的问题是,由于List是一个接口,为什么我们可以将stooges声明为'List',而不是实现List的具体子类(例如ArrayList或LinkedList)? 那么这是否意味着我们可以有一个接口类型的引用变量? 它看起来很奇怪,因为我一直认为接口只代表多态,我们永远不应该真正使用接口类型变量。

有谁能请给我一些线索?

将List接口视为保证。 任何实现List的类都将保证具有接口的方法。 当Arrays.asList()返回一个List,你实际上并没有获得一个接口时, 你会得到一个具体的类,保证实现List接口中列出的方法

至于你的“我们永远不应该真正使用接口类型变量”,你实际上是想这样做。 它被称为“编程到界面”。 如果你可以返回List而不是像LinkedList这样的东西,它会更加灵活。 您的方法的调用者没有耦合到您可能使用和返回LinkedList的特定实现内部实现。 如果在某些时候您想要返回ArrayList而不是LinkedList,则调用者不必更改任何代码,因为他们只关心接口。

“编程到界面”是什么意思?

简而言之,Serializable是一个标记界面,因此有点奇怪。 它并不保证方法存在,而是保证实现serializable的类的创建者已经考虑了与序列化类相关的许多问题(重写readObject / writeObject,与其他序列化表单的兼容性以及其他问题http: //www.javapractices.com/topic/TopicAction.do?Id=45 )。 所以Serializable仍然提供像List一样的保证,但它不是关于方法签名,而是关于语言的语言特征。

http://en.wikipedia.org/wiki/Marker_interface_pattern

使用接口作为引用类型是Java中完全有效的实践。 例如, Serializable接口将在它的类中执行此操作,以便可以序列化传递给它的任何对象。

这也是Java提供类似于多重继承的东西的方式。 例如:

public interface A { }
public class B implements A {}

public class program {
     B bClass = new B();
     A aObject = (A)bClass;
}

这样,可以使用不同的引用类型引用相同的对象,并且不会弄乱继承链!

接口定义了实现的contractspecification 哪种方法及其签名。 因此,实现接口的类必须尊重该contract 这样,您可以更改实现,而不会影响使用接口声明变量的代码。

在你提到的例子中:

  1. 除非您查看代码,否则您不知道Arrays.asList正在使用List接口的实现。 那么你怎么知道使用哪一个? (有关列表界面,请参阅javadoc以了解它具有哪些实现)

  2. 实现可能会发生变化,如果Arrays.asList决定使用其他实现呢? 你的代码将被破坏。

  3. 方法Arrays.asList的签名是它返回List<T>所以如果你想要一个具体的实现作为变量你必须Arrays.asList那个不好的做法的返回值或创建新的 - 让我们说ArrayList - 和将所有元素复制到其中,这只是一个不必要的开销。

Bloch的Effective Java是一本关于Java最佳实践的好书。 特别是, 第52项讨论了这个问题:“如果存在适当的接口类型......使用接口类型声明。”

一般的概念是,为了获得最大的灵活性和可理解性,您应该使用最能反映上下文的类型,通常是接口。 在这个例子中,您提供了确切的实现,或者只是它是一个List。 当然,如果代码需要特定于ArrayList的方法,或者代码依赖于特定于ArrayList的行为,那么请使用具体类。

偶尔有例外,例如使用GWT-RPC时 ,这是出于实现原因。

这是多态性能力的一个很好的例子,如果你喜欢你可以查看Arrays.asList()这里的Arrays.asList(T ... a)的源代码,你会发现它需要varibale长度输入并定义它自己的私有静态具体类ArrayList实现List接口而不是使用众所周知的java.util.ArrayList或其他java Collection类型,这可能是为了使它更高效或者某种东西,你想要实现自己的类并将它返回到用户没有通过实现细节压倒他,因为有一个接口他可以处理你的私人课程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM