2013-04-07 51 views
3

我在閱讀Java文檔時遇到了一個奇怪的情況。這裏是鏈接到Arrays.asList方法Oracle的Java文檔,http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList(T...)關於Java接口和多態性

有一個在文檔

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

我的問題就是一個例子,因爲列表是一個接口,我們爲什麼可以聲明走狗作爲'List',而不是一個實現List的具體子類(例如ArrayList或LinkedList)? 那麼這是否意味着我們可以有一個接口類型的引用變量?它對我來說看起來不太古怪,因爲我總是認爲接口僅僅代表多態性,我們絕不應該使用接口類型變量。

任何人都可以給我一些線索嗎?

+3

'我們不應該真的使用接口類型變量'完全相反是正確的! – A4L 2013-04-07 14:27:36

+0

我明白,對於多態我們應該聲明函數參數並返回類型和數組類型作爲接口類型變量。但對於我在問題中提到的情況,我很困惑。 – Bpache 2013-04-07 14:29:32

+2

java中的局部變量,函數參數和返回類型幾乎沒有區別。能夠將對象視爲接口是接口的主要功能之一。 – 2013-04-07 14:31:38

回答

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; 
} 

這種方式可以用不同的引用類型引用同一個對象,並且不會搞亂繼承鏈!

+1

是的,我明白了!謝謝 ! – Bpache 2013-04-07 14:32:39

3

認爲List接口是一種保證。任何實現List的類都將保證具有接口的方法。當Arrays.asList()返回一個List時,你實際上沒有獲得一個接口,你會得到一個具體的類,保證實現List接口中列出的方法。

至於你的「我們不應該真的使用接口類型變量」,你實際上應該這樣做。它被稱爲「編程到接口」。如果你可以返回一個List而不是像LinkedList那樣的話,它會更加靈活。你的方法的調用者並沒有被耦合到你可能使用和返回一個LinkedList的特定實現內部實現。如果在某個時候你想要返回一個ArrayList而不是LinkedList,調用者不必更改任何代碼,因爲他們只關心接口。

What does it mean to "program to an interface"?

筆記只是一個字的,可序列化是一個標記接口和一點點奇怪,因爲這一點。它並不保證方法在那裏,而是保證實現可序列化的類的創建者已經考慮了與序列化類有關的許多問題(重寫readObject/writeObject,與其他序列化表單的兼容性以及其他問題http://www.javapractices.com/topic/TopicAction.do?Id=45) 。所以Serializable仍然提供一個保證,比如List,但它不是關於方法簽名,而是關於該語言的一種超常語言特徵。

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

0

該接口定義了一個contract或用於實施specification。哪些是方法和他們的簽名。所以實現接口的類必須尊重contract。這樣,您可以更改實現而不影響使用接口聲明變量的代碼。

在這個例子中你提到:

  1. 你不知道是什麼,除非你看看代碼實現的List接口Arrays.asList的使用。那麼你怎麼知道使用哪一個? (請參閱javadoc的列表界面以查看它具有哪些實現)

  2. 該實現有待更改,如果Arrays.asList決定使用另一個實現呢?你的代碼將被破壞。

  3. 方法Arrays.asList的簽名是返回List<T>所以,如果你想有一個具體的實現作爲變量,你必須強制轉換返回值是不好的做法,或創建新的 - 讓我們說ArrayList - 和將所有元素複製到它中,這只是一個不必要的開銷。

0

Effective Java by Bloch是一本關於Java最佳實踐的好書。特別是,item #52談到了這一點:「如果存在適當的接口類型...使用接口類型聲明。」

一般概念是,爲了獲得最大的靈活性和可理解性,您應該使用最能反映上下文的類型,這通常是界面。在這個例子中,你提供了一個確切的實現,或者它只是一個List。當然,如果代碼需要一個ArrayList特定的方法,或者如果代碼依賴於ArrayList特定的行爲,那麼請使用具體的類。

有偶爾的例外情況,比如using GWT-RPC,但這是出於實施的原因。

0

這真是多態性功率的很好的例子,如果你喜歡,你可以看看Arrays.asList()這裏Arrays.asList(T...a),你會發現,它需要varibale長度的輸入和定義自己的私人靜混凝土的源代碼類的ArrayList實現列表界面,而不是使用衆所周知的java.util.ArrayList或其他Java 收集類型, 這可能是爲了使之更有效率或東西,你想實現自己的類並將其返回給用戶,而不會因爲實施細節而使其壓倒他e是他可以通過私人課程處理的界面。