日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java泛型中的子类型化

發布時間:2023/12/3 java 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java泛型中的子类型化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

泛型類型為Java程序引入了新的類型安全范圍。 在同一類型上,泛型類型可以表現得很好,尤其是在使用通配符時 。 在本文中,我想解釋子類型如何與Java泛型一起工作。

關于泛型類型子類型化的一般思考

不同泛型類型相同的類或接口的不定義亞型層級線性盡可能通用參數類型的子類型的層次結構。 例如,這意味著List <Number>不是List <Integer>的超類型。 下面的突出示例很好地說明了為什么禁止這種子類型化:

// assuming that such subtyping was possible ArrayList<Number> list = new ArrayList<Integer>(); // the next line would cause a ClassCastException // because Double is no subtype of Integer list.add(new Double(.1d))

在進一步詳細討論之前,讓我們首先考慮一下有關類型的一般信息:類型為程序引入了冗余。 當您將變量定義為Number類型時,請確保該變量僅引用知道如何處理Number定義的任何方法(例如Number.doubleValue)的對象。 這樣,您可以確保可以安全地在變量當前表示的任何對象上調用doubleValue,并且不再需要跟蹤變量引用的對象的實際類型。 (只要引用不為null。null引用實際上是Java嚴格類型安全性的少數例外之一。當然,null的“對象”不知道如何處理任何方法調用。)但是,如果您試圖將String類型的對象分配給此Number類型的變量,Java編譯器將認識到該對象實際上不理解Number所需的方法,并且會引發錯誤,因為它不能保證將來可能會調用例如doubleValue將被理解。 但是,如果我們缺少Java中的類型,則程序不會僅憑此更改其功能。 只要我們從不進行錯誤的方法調用,那么沒有類型的Java程序就等效。 從這個角度來看,類型僅僅是為了防止我們的開發人員在愚蠢的事情上奪走一點自由。 此外,類型是隱式記錄程序的一種好方法。 (諸如Smalltalk之類的其他編程語言不知道類型,并且除了在大多數時候困擾之外,這也有其好處。)

有了這個,讓我們回到泛型。 通過定義通用類型,您可以允許通用類或接口的用戶為其代碼添加某種類型安全性,因為他們可以限制自己僅以某種方式使用您的類或接口。 例如,當您通過定義List <Number>將List定義為僅包含Numbers時,建議您每次嘗試將String類型的對象添加到此列表中時,Java編譯器都將引發錯誤。 在使用Java泛型之前,您只需要相信列表僅包含數字即可。 當您將集合的引用交給第三方代碼中定義的方法或從該代碼接收到集合時,這可能會特別痛苦。 使用泛型,即使在編譯時,您也可以確保List中的所有元素都是某個超類型。

同時,通過使用泛型,您會在泛型類或接口內失去一些類型安全性。 例如,當您實現通用列表時

class MyList<T> extends ArrayList<T> { }

您不知道MyList中T的類型,并且必須期望該類型可以像Object一樣簡單。 這就是為什么您可以限制通用類型要求某些最小類型的原因:

class MyList<T extends Number> extends ArrayList<T> {double sum() { double sum = .0d;for(Number val : this) {sum += val.doubleValue();}return sum;} }

這使您可以假定MyList中的任何對象都是Number的子類型。 這樣,您就可以在泛型類中獲得某種類型的安全性。

通配符

Java中的通配符等效于說出任何類型 。 因此,在實例化類型(即定義泛型類的某些實例應代表哪種具體類型)時,不允許使用通配符。 例如,在將對象實例化為新的ArrayList <Number>時發生類型實例化,其中您隱式調用包含在其類定義中的ArrayList的類型構造函數

class ArrayList<T> implements List<T> { ... }

ArrayList <T>是帶有單個參數的簡單類型構造函數。 因此,在ArrayList的類型構造函數定義(ArrayList <T>)中或在此構造函數的調用(新ArrayList <Number>)中,都不允許使用通配符。 但是,如果僅引用類型而不實例化新對象,則可以使用通配符,例如在局部變量中。 因此,允許以下定義:

ArrayList<?> list;

通過定義此變量,可以為任何通用類型的ArrayList創建占位符。 但是,由于對通用類型的這種限制很小,因此無法通過此變量對其的引用將對象添加到列表中。 這是因為您對變量列表所代表的泛型做出了這樣的一般假設,即添加一個類型為String的對象并不安全,因為超出列表的列表可能需要某種其他任何子類型的對象。 通常,此必需的類型是未知的,并且不存在任何類型的子類型的對象,可以安全地添加該對象。 (例外是取消了類型檢查的空引用。但是,您永遠不應在集合中添加空值。)同時,從列表中刪除的所有對象都將是對象類型,因為這是關于a的唯一安全假設此變量表示的所有可能列表的常見超類型 。 因此,您可以使用extends和super關鍵字形成更復雜的通配符:

ArrayList<?> list = new ArrayList<List<?>>();

在此示例中,由于不將通配符應用于類型實參,而不應用于構造的類型本身,因此滿足了不得使用通配符類型構造ArrayList的要求。

至于泛型類的子類型化,我們可以總結一下,如果原始類型是子類型,并且泛型類型都是彼此的子類型,則某些泛型類型是另一種類型的子類型。 因此,我們可以定義

List<? extends Number> list = new ArrayList<Integer>();

因為原始類型ArrayList是List的子類型,并且因為泛型Integer是?的子類型? 擴展Number。

最后,請注意,通配符List <?>是List <?的快捷方式。 擴展Object>,因為這是一種常用的類型定義。 但是,如果泛型類型構造函數確實實施了另一個較低的類型邊界,例如

class GenericClass<T extends Number> { }

變量GenericClass <?>而是GenericClass <?的快捷方式。 擴展Number>。

取放原則

這種觀察將我們引到了“ 獲取-放出”原理 。 另一個著名的例子可以最好地解釋這一原理:

class CopyClass {<T> void copy(List<T> from, List<T> to) {for(T item : from) to.add(item);} }

此方法定義不是很靈活。 如果您有一些列表List <Integer>,則無法將其內容復制到某些List <Number>甚至List <Object>。 因此,“獲取和放置”原則規定,當您僅從通用實例(通過return參數)讀取對象時,應始終使用下限通配符(?extends),而在以下情況下應始終使用上限通配符(?super)。您只提供通用實例方法的參數。 因此,更好的MyAddRemoveList實現如下所示:

class CopyClass {<T> void copy(List<? extends T> from, List<? super T> to) {for(T item : from) to.add(item);} }

由于您僅從一個列表中讀取內容,然后再寫入另一個列表中,因此很遺憾,這是很容易被忽略的,您甚至可以在Java核心API中找到不采用“獲取與放置”原理的類。 (請注意,上述方法還描述了泛型類型構造函數。)

請注意,類型List <? 擴展T>和List <? 超級T>都沒有List <T>的要求那么具體。 還要注意,這種子類型對于非通用類型已經是隱式的。 如果定義的方法要求使用Number類型的方法參數,則可以自動接收任何子類型的實例,例如Integer。 但是,即使期望超型Number,也始終可以安全地讀取您收到的此Integer對象。 而且由于無法寫回該引用,即您不能用Double的實例覆蓋Integer對象,因此Java語言不需要通過聲明方法簽名(如void someMethod(<?擴展Number> number)。 同樣,當您答應從方法中返回整數時,調用者只需要一個Number類型的對象,您仍然可以從方法中返回( 寫 )任何子類型。 同樣,由于無法從假設的返回變量中讀取值,因此在方法簽名中聲明返回類型時,不必通過通配符放棄這些假設的讀取權限。

參考: 我的Java日常博客中來自我們JCG合作伙伴 Rafael Winterhalter的Java泛型子類型化 。

翻譯自: https://www.javacodegeeks.com/2013/12/subtyping-in-java-generics.html

總結

以上是生活随笔為你收集整理的Java泛型中的子类型化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。