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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解java的泛型

發(fā)布時(shí)間:2024/2/28 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解java的泛型 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 簡介
  • 泛型和協(xié)變
  • 泛型在使用中會(huì)遇到的問題
  • 類型擦除要注意的事項(xiàng)
  • 總結(jié)

簡介

泛型是JDK 5引入的概念,泛型的引入主要是為了保證java中類型的安全性,有點(diǎn)像C++中的模板。

但是Java為了保證向下兼容性,它的泛型全部都是在編譯期間實(shí)現(xiàn)的。編譯器執(zhí)行類型檢查和類型推斷,然后生成普通的非泛型的字節(jié)碼。這種就叫做類型擦除。編譯器在編譯的過程中執(zhí)行類型檢查來保證類型安全,但是在隨后的字節(jié)碼生成之前將其擦除。

這樣就會(huì)帶來讓人困惑的結(jié)果。本文將會(huì)詳細(xì)講解泛型在java中的使用,以避免進(jìn)入誤區(qū)。

泛型和協(xié)變

有關(guān)協(xié)變和逆變的詳細(xì)說明可以參考:

深入理解協(xié)變和逆變

這里我再總結(jié)一下,協(xié)變和逆變只有在類型聲明中的類型參數(shù)里才有意義,對(duì)參數(shù)化的方法沒有意義,因?yàn)樵摌?biāo)記影響的是子類繼承行為,而方法沒有子類。

當(dāng)然java中沒有顯示的表示參數(shù)類型是協(xié)變還是逆變。

協(xié)變意思是如果有兩個(gè)類 A<T> 和 A<C>, 其中C是T的子類,那么我們可以用A<C>來替代A<T>。

逆變就是相反的關(guān)系。

Java中數(shù)組就是協(xié)變的,比如Integer是Number的子類,那么Integer[]也是 Number[]的子類,我們可以在需要 Number[] 的時(shí)候傳入 Integer[]。

接下來我們考慮泛型的情況,List<Number> 是不是 List<Integer>的父類呢?很遺憾,并不是。

我們得出這樣一個(gè)結(jié)論:泛型不是協(xié)變的。

為什么呢?我們舉個(gè)例子:

List<Integer> integerList = new ArrayList<>();List<Number> numberList = integerList; // compile errornumberList.add(new Float(1.111));

假如integerList可以賦值給numberList,那么numberList可以添加任意Number類型,比如Float,這樣就違背了泛型的初衷,向Integer list中添加了Float。所以上面的操作是不被允許的。

剛剛我們講到Array是協(xié)變的,如果在Array中帶入泛型,則會(huì)發(fā)生編譯錯(cuò)誤。比如new List<String>[10]是不合法的,但是 new List<?>[10]是可以的。因?yàn)樵诜盒椭?表示的是未知類型。

List<?>[] list1 = new List<?>[10];List<String>[] list2 = new List<String>[10]; //compile error

泛型在使用中會(huì)遇到的問題

因?yàn)轭愋筒脸脑?#xff0c;List<String>和List<Integer>在運(yùn)行是都會(huì)被當(dāng)做成為List。所以我們?cè)谑褂梅盒蜁r(shí)候的一些操作會(huì)遇到問題。

假如我們有一個(gè)泛型的類,類中有一個(gè)方法,方法的參數(shù)是泛型,我們想在這個(gè)方法中對(duì)泛型參數(shù)進(jìn)行一個(gè)拷貝操作。

public class CustUser<T> {public void useT(T param){T copy = new T(param); // compile error} }

上面操作會(huì)編譯失敗,因?yàn)槲覀儾⒉恢繲是什么,也不知道T到底有沒有相應(yīng)的構(gòu)造函數(shù)。

直接clone T是沒有辦法了,如果我們想copy一個(gè)Set,set中的類型是未定義的該怎么做呢?

public void useTSet(Set<?> set){Set<?> copy1 = new HashSet<?>(set); // compile errorSet<?> copy2 = new HashSet<>(set);Set<?> copy3 = new HashSet<Object>(set); }

可以看到?是不能直接用于實(shí)例化的。但是我們可以用下面的兩種方式代替。

再看看Array的使用:

public void useArray(){T[] typeArray1= new T[20]; //compile errorT[] typeArray2=(T[]) new Object[20];T[] typeArray3 = (T[]) Array.newInstance(String.class, 20);}

同樣的,T是不能直接用于實(shí)例化的,但是我們可以用下面兩種方式代替。

類型擦除要注意的事項(xiàng)

因?yàn)轭愋筒脸脑?#xff0c;我們?cè)诮涌趯?shí)現(xiàn)中,實(shí)現(xiàn)同一個(gè)接口的兩個(gè)不同類型是無意義的:

public class someClass implements Comparable<Number>, Comparable<String> { ... } // no

因?yàn)樵诰幾g過后的字節(jié)碼看來,兩個(gè)Comparable是一樣的。

同樣的,我們使用T來做類型強(qiáng)制轉(zhuǎn)換也是沒有意義的:

public <T> T cast(T t, Object o) { return (T) o; }

因?yàn)榫幾g器并不知道這個(gè)強(qiáng)制轉(zhuǎn)換是對(duì)還是錯(cuò)。

總結(jié)

本文討論了泛型在java中使用中可能會(huì)存在的問題,希望大家能夠喜歡。

本文的例子https://github.com/ddean2009/learn-java-collections

更多精彩內(nèi)容且看:

  • 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學(xué),超級(jí)賬本,以太坊,Libra,比特幣等持續(xù)更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續(xù)更新
  • Spring 5.X系列教程:滿足你對(duì)Spring5的一切想象-持續(xù)更新
  • java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細(xì)文章教程

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/java-generics-in-deep/

本文來源:flydean的博客

歡迎關(guān)注我的公眾號(hào):程序那些事,更多精彩等著您!

總結(jié)

以上是生活随笔為你收集整理的深入理解java的泛型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。