簡體   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