简体   繁体   English

关于Java接口和多态

[英]About the Java interface and polymorphism

I just met an strange case when reading the Java doc. 我在阅读Java doc时遇到了一个奇怪的案例。 Here is the link to Oracle's java doc on Arrays.asList method, http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList(T...) 以下是Arrays.asList方法中Oracle java文档的链接, http: //docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList (T ...)

There is an example in the doc 文档中有一个例子

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

My question is, as List is an interface, why can we declare stooges as a 'List', rather than a concrete subclass implementing List(eg ArrayList or LinkedList)? 我的问题是,由于List是一个接口,为什么我们可以将stooges声明为'List',而不是实现List的具体子类(例如ArrayList或LinkedList)? So does it mean that we can have a reference variable of interface type? 那么这是否意味着我们可以有一个接口类型的引用变量? It looks quit weird to me as I always think that interface stands only for polymorphism, and we should never really use a interface type variable. 它看起来很奇怪,因为我一直认为接口只代表多态,我们永远不应该真正使用接口类型变量。

Could anyone please give me some clue on this? 有谁能请给我一些线索?

Think of the List interface as a guarantee. 将List接口视为保证。 Any class that implements List will be guaranteed to have the methods of the interface. 任何实现List的类都将保证具有接口的方法。 When Arrays.asList() returns a List you're not actually getting an interface, you're getting a concrete class that is guaranteed to implement the methods listed in the List interface . 当Arrays.asList()返回一个List,你实际上并没有获得一个接口时, 你会得到一个具体的类,保证实现List接口中列出的方法

As to your "we should never really use a interface type variable" you're actually suppose to do that. 至于你的“我们永远不应该真正使用接口类型变量”,你实际上是想这样做。 It's called "programming to the interface". 它被称为“编程到界面”。 It's much more flexible if you can return a List as opposed to something like a LinkedList. 如果你可以返回List而不是像LinkedList这样的东西,它会更加灵活。 The caller of your method isn't coupled to your specific implementation internal implementation which might use, and return, a LinkedList. 您的方法的调用者没有耦合到您可能使用和返回LinkedList的特定实现内部实现。 If at some point you wanted to return a ArrayList instead of the LinkedList the caller would not have to change any code because they only care about the interface. 如果在某些时候您想要返回ArrayList而不是LinkedList,则调用者不必更改任何代码,因为他们只关心接口。

What does it mean to "program to an interface"? “编程到界面”是什么意思?

Just a word of note, Serializable is a marker interface and a little odd because of that. 简而言之,Serializable是一个标记界面,因此有点奇怪。 It doesn't guarantee that methods are there, but instead guarantees that the creator of the class that implements serializable has thought about the many issues associated with serializing a class (overriding readObject/writeObject, compatiblity with other serialized forms, and other issues http://www.javapractices.com/topic/TopicAction.do?Id=45 ). 它并不保证方法存在,而是保证实现serializable的类的创建者已经考虑了与序列化类相关的许多问题(重写readObject / writeObject,与其他序列化表单的兼容性以及其他问题http: //www.javapractices.com/topic/TopicAction.do?Id=45 )。 So Serializable is still offering a guarantee, like List is, but it isn't about method signatures, it's about an extralinguistic feature of the language. 所以Serializable仍然提供像List一样的保证,但它不是关于方法签名,而是关于语言的语言特征。

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

Using an Interface as a reference type is a perfectly valid practice in Java. 使用接口作为引用类型是Java中完全有效的实践。 For example, the Serializable interface will do this inside it's class, so that any object that is passed to it can be serialized. 例如, Serializable接口将在它的类中执行此操作,以便可以序列化传递给它的任何对象。

This is also how Java provides something that resembles Multiple Inheritance . 这也是Java提供类似于多重继承的东西的方式。 For example: 例如:

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

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

That way the same object can be referenced with different reference types, and all without messing up an inheritance chain! 这样,可以使用不同的引用类型引用相同的对象,并且不会弄乱继承链!

The interface defines a contract or a specification for an implementation. 接口定义了实现的contractspecification Which is the methods and their signature. 哪种方法及其签名。 So a class that implements an interface has to respect that contract . 因此,实现接口的类必须尊重该contract This way you can change implementation without affecting the code that uses interfaces for declaring variables. 这样,您可以更改实现,而不会影响使用接口声明变量的代码。

In the example you mentioned: 在你提到的例子中:

  1. You don't know what implementation of the List interface Arrays.asList is using unless you look into the code. 除非您查看代码,否则您不知道Arrays.asList正在使用List接口的实现。 So how would you know which one to use? 那么你怎么知道使用哪一个? (see javadoc for list interface to see what implementations it has) (有关列表界面,请参阅javadoc以了解它具有哪些实现)

  2. The implementation is subject for change, what if Arrays.asList decides to use another implementation? 实现可能会发生变化,如果Arrays.asList决定使用其他实现呢? Your code will be broken. 你的代码将被破坏。

  3. The signature of the method Arrays.asList is that it returns List<T> so if you want to have a concrete implementation as variable you'll have to cast that return value which is bad practice or to create new - let's say ArrayList - and copy all the elements into it, which is just an unnecessary overhead. 方法Arrays.asList的签名是它返回List<T>所以如果你想要一个具体的实现作为变量你必须Arrays.asList那个不好的做法的返回值或创建新的 - 让我们说ArrayList - 和将所有元素复制到其中,这只是一个不必要的开销。

Effective Java by Bloch is a great book on Java best practices. Bloch的Effective Java是一本关于Java最佳实践的好书。 In particular, item #52 talks about this: "If the appropriate interface types exist ... declared using the interface types." 特别是, 第52项讨论了这个问题:“如果存在适当的接口类型......使用接口类型声明。”

The general notion is that, for greatest flexibility and understandability, you should use the type that best reflects the context, which is usually the interface. 一般的概念是,为了获得最大的灵活性和可理解性,您应该使用最能反映上下文的类型,通常是接口。 In the example, you provided, does the exact implementation matter or just that it is a List. 在这个例子中,您提供了确切的实现,或者只是它是一个List。 Of course, if the code requires an ArrayList-specific method or if the code is relies on an ArrayList-specific behavior, then use the concrete class. 当然,如果代码需要特定于ArrayList的方法,或者代码依赖于特定于ArrayList的行为,那么请使用具体类。

There are occasional exceptions, such as when using GWT-RPC , but this is for implementation reasons. 偶尔有例外,例如使用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