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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

源码必备知识:泛型

發布時間:2025/3/20 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 源码必备知识:泛型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?前言?

📘 博客主頁:to Keep博客主頁
🙆歡迎關注,👍點贊,📝留言評論
?首發時間:2022年3月3日
📨 博主碼云地址:博主碼云地址
📕參考書籍:java核心技術 卷1
📢編程練習:牛客網+力扣網
由于博主目前也是處于一個學習的狀態,如有講的不對的地方,請一定聯系我予以改正!!!

學習目標:
1 基本掌握泛型的基本概念與運用
2 能夠理解并且看懂java底層源碼的內容即可

文章目錄

  • 一 泛型的引入
  • 二 泛型的語法
    • 2.1 小結
    • 2.2 擦除機制(javap - c命令)
  • 三 泛型的上界
    • 3.1 語法格式
    • 3.2 較為復雜的上界
    • 3.3 泛型中的父子類
    • 3.4 泛型方法
    • 3.5 定義語法
    • 3.6 非靜態的方法
  • 四 通配符
    • 4.1通配符的上界
    • 4.2 通配符確認父子關系
    • 4.3 通配符上界的特點
    • 4.4 通配符的下界
    • 4.5 通配符的下界-父子類的關系
    • 4.6 通配符下界的特點
  • 五 總結:

一 泛型的引入

根據泛型的一個概念,在這里我們可以先寫一個自己實現的一個簡易的順序表,不需要考慮其他的,只需借助這個代碼來幫助自己理解泛型

class myarraylist{public Object[] objects = new Object[10];//把val值放到pos位置下public void set(int pos,Object val){objects[pos]=val;}//獲取pos位置下的值public Object get(int pos){return objects[pos];} } public class TestDemo {public static void main(String[] args) {myarraylist myarraylist = new myarraylist();myarraylist.set(0,1);//放入整型myarraylist.set(1,"hello");//放入字符串myarraylist.set(2,' ');//放入字符} }

我們不難發現,所創建的對象不僅僅可以存放整形,字符串,以及字符,也就是任何數據類型都可以存放,而且當我們獲取元素時,我們也不難發現,此時會發向下轉型,導致編譯不通過而報錯,此時需要強制類型轉換,轉換成(Object)類型

那么有沒有一種語法支持可以存放我們指定的類型,并且不用在強制類型轉換這么麻煩,那么接下來所要學習的泛型了。

二 泛型的語法

class 泛型類名稱<類型形參列表> {
// 這里可以使用類型參數
}
class ClassName<T1, T2, …, Tn> {
}

根據泛型的語法規則,此時我們就可以改寫一下上面的代碼:

class myarraylist<T>{public T[] objects = (T[])new Object[10];//把val值放到pos位置下public void set(int pos,T val){objects[pos]=val;}//獲取pos位置下的值public T get(int pos){return objects[pos];} } public class TestDemo {public static void main(String[] args) {myarraylist<Integer> myarraylist = new myarraylist<>();myarraylist.set(0,1);//放入整型myarraylist.set(1,3);//myarraylist.set(2,"array");int a = myarraylist.get(0);} }

2.1 小結

1 是一個占位符,表示當前類是一個泛型類(一般還可能用,等來表示)
2 結合圖片和代碼,我們可以發現當這個對象利用泛型指定要存儲的類型,那么只能存放這一種類型,并且如果放入的不是指定的這種類型,那么編譯器就會自動報錯,這也說明了我們泛型作用所處于的機制是在編譯時期
3 一般在創建對象的時候,第二個<>會根據第一個填入的類型而確定,所以是省略掉的,可以不用填
4 仔細發現,我們此時也不用進行強制類型轉換了
5 在這里也許有人會奇怪,為什么不能new一個T類型的數組,而是new了一個Object數組,之后強制轉換成為T類型數組,這就和我們泛型的擦除機制有關了,這里也提示一下,我們這樣的寫法也是不對的,真正的創建數組是要根據反射來進行創作的,我們只是為了讓代碼不報錯,能夠進行運行!
6 泛型: 就是一種作用在編譯時期的語法,目的就是指定當前的容器,要持有什么類型的對象,讓編譯器去做檢查??梢宰屛覀冹`活的利用創建不同的對象可以放不同的類型。

2.2 擦除機制(javap - c命令)

我們通過javap -c去看一下底下的字節碼文件,我們可以發現,所有的T都被替換成了Object了,所以java泛型當中所有的T在運行時就都會變成Object(而當我們去打印myarraylist這個引用時,會發現后面是不帶尖括號的,這就是擦除機制而擦除的)

擦除機制的解惑
(并不是所有的都會被擦除機制擦除成Object,如何有上界,類型擦除就會變成上界,例如下面即將講的Number和Comparable上界進行類型擦除時,就會擦成Number或者Comparable)

三 泛型的上界

在定義泛型類時,我們需要對傳入的類型變量進行約束

3.1 語法格式

class 泛型類名稱<類型形參 extends 類型邊界> {
}

此時我們可以有如下代碼:

在語法種規定,只接受Number的子類型作為T的類型實參,顯然String不是Number的子類型,所以編譯器才會報錯!

3.2 較為復雜的上界


此時較為復雜的情況就是當上界出現的是一個Comparatable接口時,此時,我們寫了一個函數,是求數組中的最大值,但是這里是不能直接比較的,如果是一個引用類型是不能夠用大于或者小于號來判斷的,正確的寫法如下:

這里要特別注意一下,如果需要Comparable進行比較是需要實現Comparable接口,所以這里的T類型是必須符合實現了Comparable的

3.3 泛型中的父子類

由于擦除機制的存在,所以是不能都會被擦除,所以是沒有父子類關系的。

3.4 泛型方法

3.5 定義語法

方法限定符 <類型形參列表> 返回值類型 方法名稱(形參列表){}

3.6 非靜態的方法


非靜態的泛型方法是可以省略<類型形參列表>。
靜態的泛型方法

靜態的是不能夠省略的,因為靜態的是不依賴于對象的,而是屬于類的,當沒有創建對象,是不會有T傳過來的,所以必須要指明<類型形參列表>

四 通配符

? 用于在泛型的使用,即為通配符,就是解決泛型中父子類的問題

泛型T就像是個變量,等著你將來傳一個具體的類型,而通配符則是一種規定,
規定你能傳哪些參數

4.1通配符的上界

語法格式:

<? extends 上界>

我們先假設:

Animal
Cat extends Animal
Dog extends Animal


此時我們可以對比print1與print2,我們可以發現print1是泛型上界,print2使用的是通配符,print1與print2有著共同的特點,就是放入的元素必須是Animal的子類
兩者區別:
1 泛型方法在靜態是必須要寫出類型形參列表,而通配符是不用的
2 對于print1,一個列表中所能傳入的只能是Animal中的其中一種子類,而print2就不一樣了,一個列表中不僅僅可以放Animal一種,可以放多種。

4.2 通配符確認父子關系

MyArrayList<? extends Number> 是 MyArrayList 或者 MyArrayList的父類類型
MyArrayList<?> (MyArrayList<? extends Object > )是 MyArrayList<? extends Number> 的父類型

4.3 通配符上界的特點

只適合讀取數據,不合適寫入數據:

ArrayList arrayList1 = new ArrayList<>();
ArrayList arrayList2 = new ArrayList<>();
List<? extends Number> list = arrayList1;
//list.add(1,1);//報錯,此時list的引用的子類對象有很多,再添加的時候,任何子類型都可以,為了安全,java不讓這樣進行添加操作。
Number a = list.get(0);//可以通過
Integer i = list.get(0);//編譯錯誤,只能確定是Number子類,所以不一定是Integer類型

4.4 通配符的下界

<? super 下界>

例如:<? super Integer>//代表 可以傳入的實參的類型是Integer或者Integer的父類類型

4.5 通配符的下界-父子類的關系

MyArrayList<? super Integer> 是 MyArrayList的父類類型
MyArrayList<?> 是 MyArrayList<? super Integer>的父類類型

4.6 通配符下界的特點

前提:假設student類繼承person類,則:

ArrayList<? super Person> list = new ArrayList();
//ArrayList<? super Person> list2 = new ArrayList();//編譯報錯,list2只能引用Person或者Person父類類型的list
list.add(new Person());//添加元素時,只要添加的元素的類型是Person或者Person的子類就可以
list.add(new Student());
Person s = list.get(0);//error
Object s = list.get(0);//可以

在放入數據的時候,只要是person的子類或者person也可以,但是要注意的是,在讀取數據的時候,不能像通配符上界那樣,利用person去接收,正確的做法應該利用Object去接收,這是因為下界是引用其父類,存數據類型的時候只能存入(變成的類型為)當前類或者當前類的子類,從而取出數據的時候并不能確定其實例數據類型。

五 總結:

對于泛型以及通配符,我們以自己要達到學習目標為主即可,不必過多糾結,能看懂源碼就可以。以上僅代表個人理解,如有錯誤,希望多多指教!及時改正!

總結

以上是生活随笔為你收集整理的源码必备知识:泛型的全部內容,希望文章能夠幫你解決所遇到的問題。

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