简体   繁体   中英

About the Java interface and polymorphism

I just met an strange case when reading the 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...)

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)? 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. Any class that implements List will be guaranteed to have the methods of the interface. 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 .

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. The caller of your method isn't coupled to your specific implementation internal implementation which might use, and return, a 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.

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. 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 ). 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.

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

Using an Interface as a reference type is a perfectly valid practice in 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.

This is also how Java provides something that resembles Multiple Inheritance . 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. Which is the methods and their signature. So a class that implements an interface has to respect that 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. So how would you know which one to use? (see javadoc for list interface to see what implementations it has)

  2. The implementation is subject for change, what if Arrays.asList decides to use another implementation? 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.

Effective Java by Bloch is a great book on Java best practices. In particular, item #52 talks about this: "If the appropriate interface types exist ... declared using the interface types."

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. 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.

There are occasional exceptions, such as when using GWT-RPC , but this is for implementation reasons.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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