主頁 >  其他 > 看完這篇10000字文章,我就不信你還吃不透Java的泛型!

看完這篇10000字文章,我就不信你還吃不透Java的泛型!

2020-11-12 10:12:00 其他

前言

在學習Java基礎的程序中,泛型絕對算得上是一個比較難理解的知識點,尤其對于初學者而言,而且就算是已經有基礎的Java程式員,可能對泛型的理解也不是那么透徹,屬于那種看了明白,時間長了就忘的那種,究其根本,還是對泛型不夠理解,

大部分人對泛型的認識:“基礎知識,但是比較模糊”

為啥要有泛型

泛型這個概念是在Java1.5提出來的,之前是沒有的,那為什么之前沒有,現在要提出來這個概念呢?那你就得想啊:

1、要么是之前的技術太垃圾了,得升級換代下
2、要么是技術發展,搞出來的新玩意,讓Java更好用
3、要么就是填坑,之前的有部分,搞個出來填坑
4、……

那你看,這個泛型,有可能是啥,實際上它就是填坑的,說這個之前,咱們先來看一段代碼:

這段代碼沒有看不懂的吧,就是簡單的一個List集合,這里可能需要你額外注意的就是我這里定義的List不是這樣的哦:

List<String> stringList = new ArrayList<String>();

不知道你看出來區別了嗎?這個應該是大部分我們用的時候會定義的那種,熟悉泛型的可能知道這是怎么回事,但是不熟悉泛型的就記住這么用就ok了,

繼續看上面我舉的那個例子,這里我想說明的就是這里定義的List集合是什么都能裝的,集合一般啥用,不就是往里面存放資料的嘛,把集合看做一個房子,里面可以進去老人和小孩,當然各種貓啊狗啊都可以進去,來,上圖:

咋樣,我的繪畫功底還是可以吧,List就好比一個房子,里面是可以進人,當然也可以進動物,比如各種各樣的小貓小狗啊,當然了,List這里可進入的就是資料了,比如字串啊,整型啊等等,

這個時候就會產生一個問題,啥問題嘞,你看啊,這座房子里面可以進入各種各樣的物種,就是各種型別的啊,如果這個房子會說話的話,它就說了“啥玩意啊,你們啥都往我這來,啥品種都行,也太亂了吧,都記不清楚你們誰是誰了,算了我也不記住你們誰是啥型別了,進來的統一當做‘活物’吧”

就是說啊,對于房子來說,不管你進來的是個啥,我統一把你們當做“活物”,在我這里你們就是一個型別的,同樣的,放到List集合這里來說的話,也是這樣的,就是你字串啊,整型啊都可以放入List集合中,那么List也說了,我不記住你們到底哪個是字串哪個是整型,在我這里統一把你們看做是Object類,至于為啥是Object類,這是因為Object是一切類的父類啊,所以沒有比它更合適啦,不管你是字串還是整型,你們一定都是Object型別的,這點容易理解吧,

這樣看似挺完美的,但是也有潛在的問題啊,什么問題嘞,你看啊,我們還拿房子來說,對于房子來說,在房子里面的都被看成是“活物”型別了,那么如果我要從房子里找一個小狗出來,那么我找出來的型別都是“活物”,可是我要的是小狗啊,你給我來個“活物”,不符合我的要求啊,怎么辦?大家都知道有個強制型別轉換吧,好吧,我就把“活物”給你強制轉換成小狗,這不就符合要求了,但是這樣問題就來了,假如你找出來的就是個小狗,你把它強制轉換成小狗,那倒也沒啥,但是你也有可能會找出來個人啊,這時候你要把一個人強制轉換成小狗,擱誰誰也不樂意啊,你說是不是,

同樣的,對于List集合也是這樣,你什么都可以往里面存盤,然后統一被看成是Object型別,這個時候如果我們從List集合中取值的話,那就要用到強制轉換了,需要把Object型別轉換成我們要的型別,比如我們想要字串,如果取出的本來就是字串,那轉成字串沒啥關系,但是如果取出來的是整型嘞,強制轉換成字串,那整型還不樂意嘞,于是乎,程式就要給你報錯了,來來,看看代碼:

咋一看,貌似沒啥問題,編譯也沒報錯啥的,我們運行一下看看:

吆喝,運行報錯了,這個錯也簡單,就是不能將整型Integer轉換成String字串型別,就是型別不匹配啊,這里要記住這個錯誤型別叫做:ClassCastException
看到這里你也許就明白了,我定義一個List集合,本來只想往里面存入字串嘞,但是不知怎么滴,里面混入了一個整型,因為List并不知道進來的都是什么型別,反正都看作Object型別,都可以進來,那么我們取資料的時候就會發生ClassCastException錯誤,
那這不行啊,我給你List里面存一個資料,我是希望你記住我傳入的是什么型別的資料的,其他的就不允許再傳入了,這樣我取值的時候也不用強制型別轉換,也就不會發生ClassCastException了,

這個你能想到,那么JDK官方更加能想到,于是乎,在Java1.5版本中就引入了泛型的概念,而引入泛型的很大一部分原因就是為了解決我們上述的問題,說白了就是我希望集合可以記得住我存進去的資料是什么型別的,以此做一個篩選,不是同型別的就不允許在一塊存放,這樣也避免了ClassCastException錯誤的出現,因為都是同一型別,也就沒必要做強制型別轉換了,

所以,你現在知道了為啥要有泛型了吧,當然,泛型的引入大部分原因是為了彌補集合的一個缺點,但是泛型的應用是很廣的,不僅僅局限于Java的集合,

泛型的定義和理解

以上還算詳細的和大家介紹了為啥要有泛型的出現,那么泛型是如何定義的呢?

泛型就是引數化型別,也就是說把我們要操作的型別作為了一個引數,比如我們創建集合的時候,允許我們可以指定集合中元素的資料型別,

在JDK1.5中引入了“引數化型別”的概念,這個就是泛型,也就是說泛型和引數化型別是等價的,一回事,那么我們來理解理解啥是引數化型別,

引數化型別

我們看看字面意思,引數化引數化,你想啊,我們有時候看一些魔幻電視劇,比如說某個人獸化了,大致知道啥意思吧,就是他變成了一個怪獸,變形了,哈哈,那么這里的引數化意思大概是不是就是變成了一個引數的意思呢?那么后面還有一個型別,組合起來是不是就是“把型別變成了引數”,那型別是啥啊,不就是String型別,Integer型別這些嘛,現在把這些型別都作為了引數,這就是引數化型別了,

不知道我表達的是否清楚,你明白嗎?

好了,來看看泛型到底長啥樣吧:

List<String> stringList = new ArrayList<String>();

就是這個,我們經常這樣操作的,它就是泛型的應用,你看看它和如下沒有使用泛型的有啥區別:

List stringList = new ArrayList();

很容易看出,就是多了一個這個,那么該如何進一步去理解它嘞?

理解泛型

還記得之前我們說的吧,泛型的引入很大一部分原因是為了讓集合能夠記住他里面的元素的資料型別,怎么讓它記住嘞,實際上實作也很簡單,就是只傳入特定的型別,比如要傳入字串型別,那么久只能傳入字串型別,像整型型別及其他型別就是不允許進入的,這樣的話就能保證集合中的元素都是統一的型別,集合自然就能記住了,

我們再來看之前舉的那個房子的例子:

通俗易懂吧,之前這個房子是開放的,誰都能進,現在嘞,我這個房子是用作狗屋的,自然是只提供小狗來住,那么其他的就不允許進入,你一個人讓你進你也不進啊,怎么搞嘞,那就是在門口搞個檢查裝置,就好比安檢,首先告訴安檢,只能讓小狗進,其他的不讓進,于是乎,每過來一個,安檢都要檢查下是不是指定的小狗型別,不是的話不讓進,是的話就進去,如此一來這個屋子里就都是小狗了,名副其實的狗屋啊,

那放到集合也是一樣的,現在要理解的就是如何給這集合加上安檢啊,再來看沒使用泛型的時候:

List stringList = new ArrayList();

這個時候是開放的,各個資料型別的都可以存放到這個List集合中,現在看下使用了泛型的:

List<String> stringList = new ArrayList<String>();

大家也看到了,就是多了個,我們在實際代碼中看下:

image.png

image.png

顯而易見啊,報錯了,說是我需要一個String,你給傳入一個int,不符合要求,那就不能存入,所以啊,你看明白了嗎?List是一個集合,可以往里面存入資料,現在要進行限制,不是什么型別的都能存入,那就對存入的資料進行檢查,怎么搞,那就在List后面加個,就成了List,看到沒,這個是不是就和我們上面舉例子中的那個安檢很像,負責檢查進來的資料,首先給它指定一個資料型別,這里就是String,然后就是檢查,不是String的都不讓存進來,所以啊,這個就是一個安檢的作用啊,其中的String就是指定的資料型別,這就是泛型啊,也就是引數化型別,String是字串型別,這里就作為一個引數放在這里,保存進List集合中的元素都要是String型別的,

咋樣,明白沒?這就是泛型啊,把String作為一個引數,型別引數化了,你看,是不是這么回事,

這樣一看,是不是覺得泛型也挺好理解的,其實這只是對泛型的基本理解,泛型還是有不少內容的,在理解了泛型的基本概念之后,我們還需要看看泛型的其他內容,當然,我必須告訴你,即使上面我講的你明白了,接下來的內容同樣有可能讓你費解,一起來看下!

泛型進階

菱形語法

咋一看,這個很高級啊,啥意思嘞,其實看代碼就知道怎么回事,我們上面舉了這樣的集合泛型代碼:

List<String> stringList = new ArrayList<String>();

你平常是這樣寫的嗎?我猜有這樣寫的:

List<String> stringList = new ArrayList<>();

有啥區別,很簡單,就是后面的ArrayList后面有尖括號內有沒有這個String,也就是型別引數,這個理解吧,按照我們上面說的,這里加上是為了指明集合中元素的資料型別,那么后面的不寫也行嗎?在Java7之前是必須寫的,也就是必須是這樣的形式:

List<String> stringList = new ArrayList<String>();

但是在Java7開始就可以這樣寫了:

List<String> stringList = new ArrayList<>();

因為在Java7中是可以通過前面的型別引數去推匯出ArrayList中的資料型別的,也就是型別引數不需要了,但是這個<>尖括號是必須的,至于尖括號中的型別,是可以自動被推匯出來的,這個就叫做菱形語法,為啥叫菱形語法嘞,因為這個<>尖括號像菱形啊……

理解型別引數(重點)

還記得什么是型別引數嗎?看這行代碼:

List<String> stringList = new ArrayList<>();

泛型的本質是引數化型別,就是把型別當做引數了,而這個型別引數就是尖括號內的東西了,在上面的這行代碼中,所謂的型別引數就是這個String了,這點明白吧,另外啊,我們都是到Java中的方法中有形參和實參,這個都知道怎么回事吧,那么這里型別引數其實也是有區別的,它也是分為型別形參和型別實參,

那啥是型別形參,啥又是型別實參啊?是不是覺得理解不了?別著急,經過我下面的解釋,你就會覺得這是如此的簡單,

我們上面寫的這行代碼:

List<String> stringList = new ArrayList<>();

這里的型別引數String其實就是型別實參了,也就是實際的型別引數,這樣的型別引數其實就是各個資料型別,泛型不就是引數化型別嘛,型別都被當做引數使用,所以這里的String其實就是實際的型別實參,是個字串型別,咋樣,理解吧?

那啥是型別形參呢?我們來看看List介面是如何定義的?

原始碼中List介面是這樣定義的,當然,看到尖括號,這就是泛型,只不過好像跟我們之前看的不太一一樣,之前這里的尖括號都是具體的型別,比如String,這里弄了一個E,這是啥玩意啊,

首先啊,你看,還記得Lsit集合人家是什么都可以存盤的嘛,也就是整型啊,字串都可以,現在使用泛型之后,相當于你可以這樣寫代碼:

List<String> stringList = new ArrayList<>();

那么你這里的List集合就只能存盤字串型別的,當然,如果我想讓List集合專門存盤整型資料呢?那是不是要這樣寫:

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

可是這樣的話,你發現問題沒?那我原始碼中的List該怎樣?現在要求就是我實際寫代碼中List后面的泛型可以寫成各種資料型別,這就要求原始碼中的List定義必須是具備通用特性的,那就用個啥來做個抽象的,泛型中就是使用一些大寫的英文字母來作為型別形參,比如這里的E就是一個型別形參,實際中你可以寫成String啊或者Interger,以便達到List集合只存盤特定型別資料的目的,而String這些就是型別實參了,

咋樣,明白吧,我之前學習這里的時候也比較疑惑這個E是啥啊,想必大家也見過T,這都是啥,這些其實就是泛型中的型別形參,我們在創建具體的類,介面或者方法的時候可以把這些型別形參轉換成具體的型別形參,大家可以看看Map的定義,是這樣的:

這里是一個K和一個V,所以啊這些都是有個基本命名的,大致有如下這些:

E 元素 集合框架使用
K 鍵 映射關系鍵的型別
V 值 映射關系中值得型別
N 數字 主要用于表示數字
T 通用型別1
S 通用型別1
U 通用型別1
V通用型別1

咋樣,看到這里是不是有種豁然開朗的感覺呢?這些就是實際的型別形參,比如上面的Map,型別形參是這樣的:

Map<K,V>

實際的型別實參樣式是這樣的:

Map<String,String>

ok了吧!理解力型別引數的形參和實參,我們再看接下來的內容,

泛型使用

我們在上面介紹泛型的時候,基本上都是使用集合類來說明,這很大一部分原因是因為泛型的提出有相當大的原因是為了彌補集合的缺陷,當然我也說了,泛型絕不僅僅是局限于集合,我們可以自定義泛型,比如自定義泛型介面和泛型類以及方法,

1、定義泛型介面

我們還是再來看下JDK中的List的定義,就是它:

這是定義了一個泛型的List介面,接下來我們來自己定義一個泛型介面,看看是怎么定義的,來,上代碼:

我們這里自定義了一個泛型介面,這個泛型的型別形參是E,包含一個showTypeName方法,目的是列印出泛型實際型別實參的型別名稱,接下來寫一個類去實作這個泛型介面:

這里要注意了,我們寫一個類,然后去實作上面我們自定義的泛型介面,這時候我們的類名后面也是要寫上泛型的,就是不能這樣,否則報錯:

然后就是實作泛型介面中的方法了,獲取傳入的型別實參的型別名稱,接下來我們使用這個類看下:

到這里是不是就比較熟悉啦,跟我們之前一直舉例的List集合有點相似吧,我們看輸出結果:

得出我們輸入的型別形參型別是String型別,以上就是泛型介面定義的一個非常簡單的例子了,咋樣,不知道你看明白了嗎?

2、自定義泛型類

上面我們簡單說了下泛型介面的自定義,大致上就是你要知道泛型介面如何定義,類如何去實作一個泛型介面,接下來我門來看如何自定義一個泛型類,直接看代碼:

這里簡單自定義了一個泛型類,這里要注意,我門上面說過了什么是型別形參,并且介紹了幾個約定俗成的,實際上這里的型別形參,你用任何一個大寫的英文字母都是ok的,比如這里我就用了一個大寫的G,然后看看如何使用這個泛型類:

我們再來看看輸出結果:

咋樣,泛型類的自定義是不是也比較簡單,接下來我們看看,一個類如何去繼承一個泛型類,

3、繼承泛型類

直接看代碼吧:

這里就是直接繼承了上述我們實作的泛型類,這里要注意了,我們繼承的泛型類,不能再是型別形參的形式了,也就是不能這個樣子:

也就是當你繼承了一個泛型類的時候,就要指定真實的型別實參,這個時候就要確定型別了,

4、原始型別

我們上面說了繼承泛型類的時候,后面不能再跟泛型形參的形式了,但是你是可以完全去除泛型的,也就是這樣的形式:

這樣也可以的,這被稱作是原始型別,那么這樣的話,實際使用輸出是什么呢?我們來使用這個類:

這時候其實就是把原先的型別形參G當做Object型別的了,而之前我們這樣的形式:

就相當于把原先的型別形參G全部當做是String型別了,所以你這里就會報錯了:

因為這時候就只能傳入String了,

并不存在泛型類

我們拿JDK中的List來舉例說明,首先看下面的代碼:

List<String> stringList = new ArrayList<>();

這行代碼想必你已經非常熟悉了吧,再看個熟悉的代碼:

List stringList = new ArrayList();

經過上面那么多的講解,你肯定知道了,上面那種我們使用了泛型的形式,下面則沒有,也就是說本身List是什么都可以存盤的,但是現在加上泛型之后,就只能存盤特定資料型別了,比如這里的List,也就是從List變成了List了,但是實際上啊,這里并沒有生成新的List,其實本質上還是List,只不過List做了規定,只能裝載String型別的資料,但是實際上List還是原來的那個List,所以啊,實作類ArrayList并不是一個新的類,不過可以看做是ArrayList的一個子類,

所以啊,泛型類,實際上是不存在的,

通配符

泛型中還有個通配符的概念,這個該怎么理解呢?還是看例子比較好理解,來看代碼:

假如這里有這么一個方法,也沒啥特別,要非說特別那就是方法中的引數是一個List,為啥特別,因為List是一個泛型介面啊,你看:

但是上面我們的List并沒有指定實際的型別實參,這樣就會產生一些問題,它會產生泛型警告的問題,那么最好我們還是指定實際的型別形參,但是這里也有問題啊,就是這里我并不確定以后傳入過來的List的實際型別實參是啥,也就是說可能傳入這樣的一個List:

List<String> stringList = new ArrayList<>();

也有可能傳入這樣的一個List:

List<String> integerList = new ArrayList<>();

那該怎么指定嘞?這樣嗎:

看著好像很對,我們試試:

很不幸,這里報錯了,其實這里一句話可以概括:

String是Object的子類,但是List卻不是List的子類

記住這個,就知道這里肯定是不行的,那該怎么辦嘞?這里就要使用到通配符了,就是這樣:

就一個問號就搞定啦,這個時候我們使用這個Test方法的時候就是既可以傳入這樣的List:

List<String> stringList = new ArrayList<>();

也可以傳入這樣的List:

所以啊,使用通配符之后可以傳入的型別就多了,但是有的時候可能不需要傳入所有的,希望還是有一定的限制的,這個時候就需要通配符的上下限設定了,關于這個,限于篇幅問題,就不展開來講了,

泛型方法

這里把泛型方法單獨拿出來講是覺得這個泛型方法理解起來還是需要費點勁兒的!實際情況也確實如此,泛型方法有點不好理解,

那啥是泛型方法嘞,簡單來說啊,泛型方法就是:

宣告方法的時候,可以定義一個或多個泛型形參

這里我們拿泛型類來對比一下,對于泛型類,比如這個:

我們在實體化這個類的時候需要指明具體的型別實參,比如是String還是Intenger之類的,那么對于泛型方法而言,它就是在定義的時候是泛型形參,而實際呼叫的時候需要指定泛型實參(也就是泛型的具體型別)

定義及使用泛型方法

接下來我們來看如何定義泛型,首先我們來看一個正常的方法定義:

這是一個很正常的方法定義,但是里面的邏輯似乎不正常,為啥?覺得這樣沒必要啊,你看我們這里需要給引數傳入的就是String型別,你這里還輸出型別名稱,好像只有給你輸出來你才相信似的,好像是這兒回事,那我們接著來看,如何定義一個泛型方法,

你想啊,我們怎么定義類,是不是有個關鍵字class,如何定義介面呢?是不是用關鍵字interface,所以,定義這些比較特殊的東西,必定有個特殊的東西,那么如何定義泛型方法呢?你看:

這里就簡單定義了一個泛型方法,這里需要注意的就是,你憑啥說你定義的是一個泛型方法呢?這里的一個象征就是紅框中的泛型,也就是說啊,你要定義一個泛型方法的話,那么你就必須在權限修飾符(這里是public)和回傳值之間寫上,這個是泛型標志,代表你這個是一個泛型方法,對了,這里的T就是個泛型形參,也可以是其他的大寫字母,這個之前講過的,所以啊,你在看這個泛型方法,比如我們呼叫這個泛型方法:

是不是覺得邏輯沒啥問題啊,因為傳入的是個泛型,所以這里通過一個泛型方法,可以傳入不同的型別,以便查看其型別,這里要注意了,我們寫的平常的方法,方法傳入的是確定的型別,但是使用泛型后,可以傳入各種型別,那么就可以測驗一些不知道是什么型別的型別名稱了,可能有點繞,理解下!

所以啊,泛型方法的定義的語法如下:

修飾符 <T,E,……> 回傳值型別 方法名稱(形參串列){
方法體……
}

我們來對照一下我們定義的泛型方法:

這里的public就是修飾符,就是泛型串列,為啥說串列,其實是它可以包含多個泛型形參名稱,也就是那些個大寫的英文字母,后面的void就是回傳值型別了,然后就是方法名稱和形參串列了,

重點總結

我們還是來看這個泛型方法的定義:

這里有幾個知識點需要強調一下:

1、權限修飾符和回傳值中間的這個泛型串列,也即是很重要,就相當于是泛型方法的標志,有了這個你才能叫做泛型方法
2、代表將使用泛型型別T,只有這個時候,你在方法中才可以使用泛型型別T
3、另外你需要知道的就是這個T啊就是泛型形參的命名,可以是T,E,K等等這些,反正就是大寫的英文字母就ok了

泛型方法的的學習建議

對于Java基礎中的泛型這塊,我一直覺得是個比較重要的知識點,當然,事實也是如此,所以這個知識點需要理解透徹了,但是另外一個現實情況就是,泛型的理解還是有一定門檻的,尤其對于初學者而言,那么泛型中的泛型方法可能又稍微難理解一點,那么對于這塊的學習,剛開始不建議死扣,有個基本認識即可,比如我上面介紹的那些關于泛型方法的基本知識點,剛開始了解這些即可,當然,泛型方法不僅僅是這些,只不過我們暫且不深入學習,

學習還是要一步步來,后續會單獨出文章詳細聊聊泛型方法的,

泛型擦除與轉換

這個泛型擦除是啥嘞?一般的話面試的時候要是問泛型的話,那就大概率會被問到這個泛型擦除了,先來看一段代碼:

猜想一下,這兩個ArrayList的型別一樣嗎?看一下結果:

可以看到,這兩個是完全一樣的,也就是說,這里的泛型實參String和Integer并沒有對ArrayList造成什么本質上的影響,其實這里蠻好理解的:

這里的泛型就相當于一個安檢,指定了一個具體的資料型別,想要往這個集合中存入資料就得經過泛型這個安檢檢查,和指定資料型別不一樣的都不允許存盤,這就保證了存盤的型別都是指定的型別,也就是說啊,我這個集合只想存盤統一的資料型別,怎么做嘞,那就搞個檢查裝置(就是泛型),起到一個過濾資料的作用,但是你這檢查裝置只是起到一個檢查過濾的作用,并不影響我本身,舉個例子就是好比我要開個針對程式員的大會,選了一個酒店,那么這個酒店目前只允許程式員進入,所以找個保安(泛型)站在門口,只允許程式員進入,不是程式員的不讓進,那么在大會開始之前(編譯階段),保安會在門口把門,只讓程式員進,等到人員都到場了,那么可以確定的是酒店里都是程式員了,那么保安此時的任務就結束了,然后保安就可以撤了(泛型擦除),然后我們就開始開會了(運行階段)

這就是泛型擦除了,咋樣,我說的夠明白嗎?也就是說啊,泛型就是在編譯階段做了一個檢查,在編譯階段,不符合你指定的型別的資料都會檢查報錯,比如下面的代碼:

ArrayList<String> stringArrayList = new ArrayList<>();

因為指定了具體的泛型實參String,那么你這里就只能添加字串,編譯階段是會檢查的,一旦你添加的不是字串,它就會報錯,你看:

等你添加完畢,這個ArrayList里面就都是字串型別了,到了運行階段,這里的泛型資訊就被擦除了,沒泛型啥事了,也就是本身ArrayList啥都可以存盤,現在是加了個泛型,可以確保我存盤的都是同種型別的,

再舉個例子就是,有一座茅草屋,本來這個茅草屋誰都可以進去,但是現在規定(相當于加了泛型),身價一個億的才能進去,但是即使進去的都是身價一個億的,這個茅草屋還是原來那個茅草屋,它也不可能變成豪華別墅啊(只是舉例子,拒絕杠精)

除了擦除,還有個轉換,舉個例子也就很容易明白,看代碼:

這是我們之前自定義的一個簡單的泛型類,現在我們使用這個類:

我們這里指定具體的泛型實參是String字串型別,那么這個時候,代碼的實際編譯階段,這個G就全部被替換成了String,也就是變成了這個樣子:

這就是一個型別的轉換了,說的簡單點就是你定義的泛型形參在編譯的階段會被全部替換成你實際指定的泛型實參,

總結

好了,限于文章的篇幅,關于泛型有些點并沒有詳細展開來講,或者有的點也沒講,對于知識的學習,是需要不斷的深入和反復的迭代的,想要一次性把一個知識全部學完也是不可能的,只能說,需要不斷的學習,所以關于泛型的講解就到這了,下面我簡單說下我個人對泛型的一些理解吧,希望對你有錦上添花的作用,

其實我一直覺得泛型這個東西有點像保安,就是看大門的,按照你的規定,允許誰可以進,誰不可以進,當然,這里的進不進就是可不可以存盤的問題了,比如集合,是否可以向其添加資料,這是在你給規定之后,而這個規定你可以制定的多種多樣,這么一來,就靈活多變了,其實關于泛型吧,剛開始理解是一道坎,理解了就覺得通透了,但是理解了也不一定算是掌握了,后面看一些原始碼,使用泛型的很多,可是你還是不一定懂,但是在理解了的前提下,你才有可能讀懂那些原始碼,學習就是這樣,需要不斷的迭代,反復的打磨,不能停啊!

好了,泛型就說到這里,歡迎大家提出你的看法和建議,一起交流學習,文中若有不當之處,還望提出!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/211760.html

標籤:其他

上一篇:Mybatis-plus的自動填充與樂觀鎖(springboot)

下一篇:握草!美團P8整理的280頁超詳細Docker實戰檔案簡直太香了,讓你對如日中天的Docker有更深入的了解。

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more