【再探】Java—泛型

?Java 泛型本質是參數化類型,可以用在類、接口和方法的創建中。

1 “擦除式”泛型

Java的“擦除式”的泛型實現一直受到開發者的詬病。

“擦除式”的實現幾乎只需要在Javac編譯器上做出改進即可,不要改動字節碼、虛擬機,也保證了以前沒有使用泛型的庫可以之間運行在java 5.0 之上。但是這個帶來了以下弊端:

  1. 例如對于List<String> 和 List<Integer> ,在運行時由于擦除了,所以這兩個都變成了List,因此它們在運行中是同一類型。(而對于C#的泛型來說,無論在源碼中、編譯后及運行時它們始終是不同的類型)。這導致在運行時,獲取不到類型信息。
  2. “擦除式”的實現,是在元素被賦值時編譯器自動插入類型檢查指令,訪問元素時,自動插入類型強制轉換指令。這樣頻繁的類型檢查及轉換,導致Java的泛型性能差于C#的泛型。
public class EraseGeneric {private static class Holder<T> {T t;public T getT() {return t;}public void setT(T t) {this.t = t;}}public static void main(String[] args) {Holder<String> holder = new Holder<>();holder.setT("hello");String str = holder.getT();}}

圖 Holder類被編譯后的字節碼片段

圖 main 方法中,對于Holder類型的賦值及訪問操作字節碼

1.1 擦除的補償

如果要在運行時獲取類型信息,那么可以通過引入類型標簽來對擦除進行補償。

public class TypeTagGeneric {private static class User {public User() {}}private static <T> void fun(Class<T> kind) throws InstantiationException, IllegalAccessException {T t = kind.newInstance();System.out.println(t);}public static void main(String[] args) throws InstantiationException, IllegalAccessException {fun(User.class);int[] array1 = new int[10];String[] array2 = new String[10];}}

2 協變與逆變

A 類型是B的父類型,對于某個構造器,構造出的復雜類型A`與B`。

協變

A`仍然是B`的父類型。比如Java中的數組,A[] 仍是B[]的父類型。

逆變

B`是A`的父類型。

抗變

A`與B`沒有任何繼承關系。例如List<A> 與List<B>沒有任何繼承關系。

表 協變、逆變與抗變

2.1 數組與泛型

T[] t = new T[10]; 這個代碼是錯誤的,Java中規定不能創建泛型數組。

因為Java 在運行時,無法獲取泛型的類型信息,因為在創建數組時,也就無法獲取到泛型參數所表示的確切類型。

2.1.1 數組的類型

Java中數組的種類有兩種:

  1. 基礎類型的數組:[ + 開頭大寫字母。

int[] : [I

  1. 引用類型的數組:[ + L + 類型。

String[] array2 : [Ljava/lang/String

public class ArrayGeneric {private static class Fruit {}private static class Apple extends Fruit {}public static void main(String[] args) {Fruit[] fruits = new Fruit[10];Apple[] apples = new Apple[10];System.out.println(fruits instanceof Fruit[]); // trueSystem.out.println(fruits instanceof Apple[]); // falseSystem.out.println(apples instanceof Fruit[]); // trueSystem.out.println(apples instanceof Apple[]); // truefruits = apples;
//        apples = fruits; // 編譯錯誤System.out.println(fruits.getClass().getSuperclass()); // class java.lang.ObjectSystem.out.println(apples.getClass().getSuperclass()); // class java.lang.Object
//        getSuperclass() 方法:如果此 Class 表示 Object 類、一個接口、一個基本類型或 void,則返回 null。
//        如果此對象表示一個數組類,則返回表示該 Object 類的 Class 對象。否則返回該類的超類。}}

2.2 通配符

泛型中的通配符用于在兩個類型之間建立某種類型的向上轉型關系。

協變

? extends T, 例如List<? extends Fruit> list。確定了元素類型的父類為Fruit,但不能確定其確切類型,因此不能往該容器添加新的元素(只能添加null)。但是可以從容器中提取元素,類型為Fruit。

逆變

? super T,例如List<? super Apple> list,確定了元素為Apple的父類,因為可以往容器中添加元素,但不能提取元素。

表 通配符的協變與逆變

public class CovarianceAndContravariance {private static class Fruit {}private static class Apple extends Fruit {}private static <T extends Apple> void setItem(List<? super Apple> list, T item) {list.add(item);}private static Fruit getItem(List<? extends Fruit> list,int pos) {return list.get(pos);}public static void main(String[] args) {List<? super Apple> list = new ArrayList<>();setItem(list,new Apple());List<? extends Fruit> list2 = Arrays.asList(new Fruit(),new Apple());Fruit item = getItem(list2, 0);}}

2.2.1 無界通配符

無界通配符,例如List<?>, 其相當于List<? extends Object>,但不等價于List(相當于List<Object>)。其有兩個作用:

  1. 告訴編譯器,我用了泛型,只是還沒確定哪個類型;
  2. 用于捕獲類型。
public class CaptureGeneric {private static class Holder<T> {}private static <T> void fun1(Holder<T> holder) {System.out.println(holder);}private static void fun2(Holder<?> holder) {fun1(holder);}public static void main(String[] args) {Holder holder = new Holder(); //  原生類型fun1(holder); // 警告,Unchecked assignment:fun2(holder); // 不會警告,無邊界通配符將不會這個原生類型的類型參數(Object)}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/13828.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/13828.shtml
英文地址,請注明出處:http://en.pswp.cn/web/13828.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

光伏電站在線監測智能診斷系統:開啟無人值守新紀元

光伏電站在線監測智能診斷系統&#xff1a;開啟無人值守新紀元 大家都知道光伏電站是通過汲取著太陽的光芒&#xff0c;為人類提供源源不斷的電能源。然而&#xff0c;隨著光伏電站規模的擴大和復雜性的增加&#xff0c;如何有效提高發電效率、減少人工維護成本&#xff0c;實…

YOLOV5算法多目標檢測系統

歡迎大家點贊、收藏、關注、評論啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代碼。 文章目錄 一項目簡介 二、功能三、系統四. 總結 一項目簡介 一、項目背景與意義 隨著計算機視覺技術的飛速發展&#xff0c;目標檢測已成為許多實際應用場景中的關鍵技術&…

AWS存儲之 Storage Gateway

AWS Storage Gateway是一項混合存儲服務&#xff0c;它允許您在本地環境和AWS云之間無縫地集成存儲解決方案。它提供了一種簡單、安全地方式&#xff0c;讓您可以將本地應用程序連接到云存儲服務&#xff0c;如Amazon S3、Amazon Glacier、Amazon EBS等。 比如一個公司如果想將…

數據結構之二叉樹的超詳細講解(2)--(堆的概念和結構的實現,堆排序和堆排序的應用)

個人主頁&#xff1a;C忠實粉絲 歡迎 點贊&#x1f44d; 收藏? 留言? 加關注&#x1f493;本文由 C忠實粉絲 原創 數據結構之二叉樹的超詳細講解(2)--(堆的概念和結構的實現,堆排序和堆排序的應用) 收錄于專欄【數據結構初階】 本專欄旨在分享學習數據結構學習的一點學習筆記…

電腦卸載linux安裝windows后每次開機都出現grub

原因分析 這是因為電腦硬盤中還存在linux系統的引導程序&#xff0c;并且啟動順序還在windows之前&#xff0c;有時候通過bios根本找不到它的存在&#xff0c;以至于每次windows開機出現grub之后都要輸入exit退出linux的引導之后才能使得電腦進入windows&#xff0c;這個有時會…

算法訓練營第三十六天 | LeetCode 1005 K次取反后最大化的數組、LeetCode 134 加油站

LeetCode 1005 K次組飯后最大化的數組 這題貪的主要是數值最大化。如果K > 負數個數&#xff0c;我們就先將負數全部轉換成它的相反數&#xff0c;并將K--&#xff0c;之后K剩余的值可以對2取模&#xff0c;為0的話直接得出最后結果&#xff0c;為的話我們要在當前所有值里…

Python | Leetcode Python題解之第108題將有序數組轉換為二叉搜索樹

題目&#xff1a; 題解&#xff1a; class Solution:def sortedArrayToBST(self, nums: List[int]) -> TreeNode:def helper(left, right):if left > right:return None# 選擇任意一個中間位置數字作為根節點mid (left right randint(0, 1)) // 2root TreeNode(nums…

純血鴻蒙APP實戰開發——邊緩存邊播放案例

介紹 OhosVideoCache是一個支持邊播放邊緩存的庫&#xff0c;只需要將音視頻的url傳遞給OhosVideoCache處理之后再設置給播放器&#xff0c; OhosVideoCache就可以一邊下載音視頻數據并保存在本地&#xff0c;一邊讀取本地緩存返回給播放器&#xff0c;使用者無需進行其他操作…

NDIS小端口驅動(五)

在需要的時候&#xff0c;我們也許需要NDIS微型端口程序信息&#xff0c;下面會從多個方面來討論如何查詢NDIS微型端口驅動。 查詢無連接微型端口驅動程序 若要查詢無連接微型端口驅動程序維護的 OID&#xff0c;綁定協議調用 NdisOidRequest 并傳遞 一個NDIS_OID_REQUEST 結…

Mac 安裝 git

文章目錄 前言一、介紹二、下載三、驗證四、配置五、Git常用命令六、git提交和撤銷工作流程代碼提交和提交同步代碼撤銷和撤銷同步 FAQ1.homebrew 下載解決方法一&#xff08;強烈推薦&#xff09;&#xff1a;解決方法二&#xff1a; 總結 前言 Git 是一個開源的分布式版本控…

Java - Stream流式編程

Stream流式操作 Stream流式操作&#xff0c;就是學習java.util.stream包下的API&#xff0c;Stream不同于java的輸入輸出流&#xff0c;是實現對集合&#xff08;Collection&#xff09;的復雜操作&#xff0c;例如查找、替換、過濾和映射數據等&#xff0c;集合是一種靜態的數…

LeetCode547省份數量

題目描述 有 n 個城市&#xff0c;其中一些彼此相連&#xff0c;另一些沒有相連。如果城市 a 與城市 b 直接相連&#xff0c;且城市 b 與城市 c 直接相連&#xff0c;那么城市 a 與城市 c 間接相連。省份 是一組直接或間接相連的城市&#xff0c;組內不含其他沒有相連的城市。給…

第十一章 文件及IO操作

第十一章 文件及IO操作 文件的概述及基本操作步驟 文件&#xff1a; 存儲在計算機的存儲設備中的一組數據序列就是文件不同類型的文件通過后綴名進行區分 文本文件&#xff1a;由于編碼格式的不同&#xff0c;所占磁盤空間的字節數不同(例如GBK編碼格式中一個中文字符占2字…

cesium繪制三角網可視化及mesh網格數據解析

可視化運行效果(水質污染擴散) 實現運行效果 術語 Mesh網格數據解析 Mesh&#xff08;網格&#xff09;在不同領域有不同的應用和定義。在計算機網絡中&#xff0c;Mesh網絡指的是一種無中心的網狀結構&#xff0c;每個節點都與其他節點相連。而在3D計算機圖形學中&#…

云原生Kubernetes: K8S 1.26版本 部署KubeSphere

目錄 一、實驗 1.環境 2.K8S 1.26版本部署HELM 3.K8S 1.26版本 部署KubeSphere 4.安裝KubeSphere DevOps 二、問題 1.如何安裝Zadig 2.擴展插件Zadig安裝失敗 3.calico 如何實現不同node通信 4.如何清除docker占用的磁盤空間 5.如何強制刪除資源 6.namespace刪除不…

CGAL 點云生成高程模型數據(DSM)

點云生成高程模型 一、什么是DSM?二、C++代碼三、結果可視化一、什么是DSM? DSM(Digital Surface Model)是一種數字高程模型,通常用于描述地表地形的數字化表示。它是由一系列離散的高程數據點組成的三維地形模型,其中每個點都具有其相應的高程值。 ??DSM主要用于獲取和…

宿舍管理系統--畢業設計

畢業設計&#x1f4bc;MD5加密&#x1f512;SSM框架&#x1f3a8;Layui框架&#x1f384; 實現功能 管理員的登錄與登出 管理員,班級,學生,宿舍&#xff0c;衛生&#xff0c;訪客各模塊增刪改查 個別模塊關聯查詢 各個模塊數據導出Excel 一些截圖

[4]CUDA中的向量計算與并行通信模式

CUDA中的向量計算與并行通信模式 本節開始&#xff0c;我們將利用GPU的并行能力&#xff0c;對其執行向量和數組操作討論每個通信模式&#xff0c;將幫助你識別通信模式相關的應用程序&#xff0c;以及如何編寫代碼 1.兩個向量加法程序 先寫一個通過cpu實現向量加法的程序如…

軟件設計:基于 python 代碼快速生成 UML 圖

1. 官方文檔 PlantUML Language Reference Guide Comate | 百度研發編碼助手 百度 Comate (Coding Mate Powered by AI) 是基于文心大模型的智能代碼助手&#xff0c;結合百度積累多年的編程現場大數據和外部優秀開源數據&#xff0c;可以生成更符合實際研發場景的優質代碼。…

自動化測試里的數據驅動和關鍵字驅動思路的理解

&#x1f345; 視頻學習&#xff1a;文末有免費的配套視頻可觀看 &#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 初次接觸自動化測試時&#xff0c;對數據驅動和關鍵字驅動不甚理解&#xff0c;覺得有點故弄玄須…