Java泛型T,E,K,V,N,?與Object區(qū)別和含義
通常我們?cè)诳匆恍┰创a時(shí),發(fā)現(xiàn)全是T、?,暈乎乎的:sob:。于是,把泛型掌握好十分重要!
什么是泛型
Java 泛型(generics)是 JDK 5 中引入的一個(gè)新特性, 泛型提供了編譯時(shí)類型安全檢測(cè)機(jī)制,該機(jī)制允許程序員在編譯時(shí)檢測(cè)到非法的類型。
泛型的本質(zhì)是參數(shù)化類型,也就是說(shuō)所操作的數(shù)據(jù)類型被指定為一個(gè)參數(shù)。
泛型有什么好處?寫個(gè)例子一目了然:
我們要封裝一個(gè)消息響應(yīng)類:
public class Result implements Serializable { // 響應(yīng)碼 Integer code; // 是否成功 Boolean success; // 返回體數(shù)據(jù) User user; public Result(Integer code, Boolean success, User user) { this.code = code; this.success = success; this.user = user; } @Override public String toString() { return "Result{" + "code=" + code + ", success=" + success + ", user=" + user + '}'; } public static void main(String[] args) { User user = new User(1, "Tony"); Result result = new Result(200, true, user); System.out.println(result); } } class User implements Serializable { Integer id; String name; public User(Integer id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
Result{code=200, success=true, user=User{id=1, name='Tony'}} 進(jìn)程已結(jié)束,退出代碼0
呼~這樣這個(gè)反應(yīng)體就可以返回請(qǐng)求狀態(tài)和用戶信息了。可現(xiàn)在需求又需要返回關(guān)于手機(jī)的信息,那我們又得封裝一個(gè)能返回手機(jī)信息的響應(yīng)類了...到后面還有衣服、鞋子...那不得累死?這時(shí)候泛型登場(chǎng)了:
public class Result<T> implements Serializable { // 響應(yīng)碼 Integer code; // 是否成功 Boolean success; // 返回體數(shù)據(jù) T data; public Result(Integer code, Boolean success, T data) { this.code = code; this.success = success; this.data = data; } @Override public String toString() { return "Result{" + "code=" + code + ", success=" + success + ", data=" + data + '}'; } public static void main(String[] args) { User user = new User(1, "Tony"); Result<User> resultUser = new Result<>(200, true, user); System.out.println(resultUser); Phone phone = new Phone(999.99, "Yellow"); Result<Phone> resultPhone = new Result<>(200, true, phone); System.out.println(resultPhone); } } class User implements Serializable { Integer id; String name; public User(Integer id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } } class Phone implements Serializable { Double price; String color; @Override public String toString() { return "Phone{" + "price=" + price + ", color='" + color + '\'' + '}'; } public Phone(Double price, String color) { this.price = price; this.color = color; } }
Result{code=200, success=true, data=User{id=1, name='Tony'}} Result{code=200, success=true, data=Phone{price=999.99, color='Yellow'}} 進(jìn)程已結(jié)束,退出代碼0
可見(jiàn),利用泛型,可以統(tǒng)一標(biāo)識(shí)需要返回的實(shí)體類。不管你來(lái)什么類,我都可以給你塞進(jìn)去!
第一次接觸可能看不太明白,下面就詳細(xì)講解
泛型方法
你可以寫一個(gè)泛型方法,該方法在調(diào)用時(shí)可以接收不同類型的參數(shù)。根據(jù)傳遞給泛型方法的參數(shù)類型,編譯器適當(dāng)?shù)靥幚砻恳粋€(gè)方法調(diào)用。
語(yǔ)法規(guī)則
所有泛型方法聲明都有一個(gè)類型參數(shù)聲明部分(由尖括號(hào)分隔),該類型參數(shù)聲明部分在方法返回類型之前
比如說(shuō)這是一個(gè)用來(lái)打印數(shù)組的泛型方法:
private static <E> void printArray(E[] inputArray)
每一個(gè)類型參數(shù)聲明部分包含一個(gè)或多個(gè)類型參數(shù),參數(shù)間用逗號(hào)隔開(kāi)。一個(gè)泛型參數(shù),也被稱為一個(gè)類型變量,是用于指定一個(gè)泛型類型名稱的標(biāo)識(shí)符。
比如這個(gè)方法
private static <E,T> void printArray(E[] inputArray, T data)
類型參數(shù)能被用來(lái)聲明返回值類型,并且能作為泛型方法得到的實(shí)際參數(shù)類型的占位符。
泛型方法體的聲明和其他方法一樣。注意類型參數(shù)只能代表引用型類型,不能是原始類型(int double char等)
泛型標(biāo)記符
- E Element 集合元素
- T Type Java類
- K Key 鍵
- V Value 值
- N Number 數(shù)值類型
- ? 表示不確定的Java類型
這些標(biāo)記并不是限定只有對(duì)應(yīng)的類型才能使用,即使你統(tǒng)一使用A-Z英文字母的其中一個(gè),編譯器也不會(huì)報(bào)錯(cuò)。之所以又不同的標(biāo)記符,這是一種**約定。**在開(kāi)發(fā)中很多規(guī)則都是一種約定,它能提高我們代碼的可讀性,方便團(tuán)隊(duì)見(jiàn)的合作開(kāi)發(fā)
寫個(gè)完整的例子:
public class TFunction { public static void main(String[] args) { // 創(chuàng)建各種類型的數(shù)組 Integer[] intArray = {1, 2, 3, 4, 5}; Double[] doubleArray = {1.1, 2.2, 3.3, 4.4}; Character[] charArray = {'H', 'E', 'L', 'L', 'O'}; System.out.println("整型數(shù)組元素為:"); printArray(intArray); // 傳遞一個(gè)整型數(shù)組 System.out.println("\n雙精度型數(shù)組元素為:"); printArray(doubleArray); // 傳遞一個(gè)雙精度型數(shù)組 System.out.println("\n字符型數(shù)組元素為:"); printArray(charArray); // 傳遞一個(gè)字符型數(shù)組 } // 泛型方法 private static <E> void printArray(E[] inputArray) { // 遍歷打印數(shù)組 Arrays.stream(inputArray).forEach(e -> { System.out.printf("%s ", e); }); System.out.println(); } }
泛型類
泛型類的聲明與非泛型類幾乎相同,唯一的不同在于類名的后面添加了參數(shù)聲明部分
這邊就不舉例子了,因?yàn)殚_(kāi)篇的例子就是封裝了一個(gè)泛型類,當(dāng)時(shí)不太理解的可以再回去看一下
類型通配符
?
我們一般可以使用?來(lái)承接所有的引用類型,搬運(yùn)一個(gè)菜鳥(niǎo)上的例子:
public class GenericTest { public static void main(String[] args) { List<String> name = new ArrayList<String>(); List<Integer> age = new ArrayList<Integer>(); List<Number> number = new ArrayList<Number>(); name.add("icon"); age.add(18); number.add(314); getData(name); getData(age); getData(number); } public static void getData(List<?> data) { System.out.println("data :" + data.get(0)); } }
data :icon data :18 data :314
?extends T
這是**泛型上邊界:**只有T對(duì)象的子類可以被傳入
如果是? extends C,那么只有D和E允許被傳入,否則會(huì)編譯報(bào)錯(cuò)
? super T
這是**泛型下邊界:**只有T對(duì)象的父類可以被傳入
如果是? super D,那么只有C和A允許被傳入,否則會(huì)編譯報(bào)錯(cuò)
T 和 ?
不知道看到這里,有沒(méi)有疑惑。T和?好像作用差不多啊,有什么區(qū)別?
這里解釋一下,T一般作為泛型參數(shù),而?是更多是用來(lái)一個(gè)不確定的引用類型,意會(huì)一下吧~~~
T 和 Object
重頭戲?。?/p>
知道的Object的同志都了解其是Java的超類(所有對(duì)象的父類),不了解的可以去看看我的博客,有做詳細(xì)的解釋。
那么問(wèn)題就來(lái)了,Object好像可以代替泛型的功能?。∷心苡玫椒盒偷牡胤絆bject都可以!
其實(shí),在JDK5之前,都是用的Object,但其存在很多的問(wèn)題,JDK5之后便引入了泛型
Object是所有類的父類,在編碼過(guò)程中就難免出現(xiàn)類型轉(zhuǎn)化問(wèn)題,且在編譯階段不會(huì)報(bào)錯(cuò),到了運(yùn)行階段才暴露問(wèn)題,大大降低了程序的安全性和健壯性!
舉例之前說(shuō)一些轉(zhuǎn)型的分類:
向上轉(zhuǎn)型 用父類聲明一個(gè)子類對(duì)象 例如:Animal是Cat的父類,在聲明時(shí)我們這么寫:
Animal cat = new Cat();
向下轉(zhuǎn)型
將父類對(duì)象強(qiáng)轉(zhuǎn)為其子類實(shí)例:
Animal cat = new Cat(); Cat anotherCat = (Cat) cat;
所以當(dāng)我們使用Object作為泛型來(lái)使用時(shí),不僅寫起來(lái)麻煩,還要不停的進(jìn)行類型轉(zhuǎn)化,還很容易出現(xiàn)問(wèn)題,很遜的誒~
舉個(gè)例子看看:
利用Object定義了一個(gè)數(shù)字變量,我們常識(shí)將其向下轉(zhuǎn)型為Integer和String。將一個(gè)數(shù)字轉(zhuǎn)型為字符串是一件荒唐的事情,可編譯器并不能察覺(jué)這件事,直到程序運(yùn)行了起來(lái)...
類型轉(zhuǎn)換異常?。?!
總結(jié)
泛型的出現(xiàn),當(dāng)類型轉(zhuǎn)化出現(xiàn)問(wèn)題的時(shí)候,在編譯階段就會(huì)暴露出來(lái)。解決了Object存在的諸多問(wèn)題,讓代碼更加優(yōu)雅,程序更加安全,更加健壯。
以上就是Java泛型T,E,K,V,N,?與Object區(qū)別和含義的詳細(xì)內(nèi)容,更多關(guān)于Java 泛型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java并發(fā)編程創(chuàng)建并運(yùn)行線程的方法對(duì)比
這篇文章主要為大家詳細(xì)介紹了Java并發(fā)編程創(chuàng)建并運(yùn)行線程的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03Java實(shí)現(xiàn)常見(jiàn)的排序算法的示例代碼
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)常見(jiàn)的排序算法(選擇排序、插入排序、希爾排序等)的相關(guān)資料,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-10-10springboot項(xiàng)目如何設(shè)置時(shí)區(qū)
這篇文章主要介紹了springboot項(xiàng)目如何設(shè)置時(shí)區(qū)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Java利用Easyexcel導(dǎo)出excel表格的示例代碼
這篇文章主要為大家詳細(xì)介紹了Java利用Easyexcel導(dǎo)出excel表格的示例代碼,文中的代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2022-07-07Java中StringBuilder與StringBuffer使用及源碼解讀
我們前面學(xué)習(xí)的String就屬于不可變字符串,因?yàn)槔碚撋弦粋€(gè)String字符串一旦定義好,其內(nèi)容就不可再被改變,但實(shí)際上,還有另一種可變字符串,包括StringBuilder和StringBuffer兩個(gè)類,那可變字符串有什么特點(diǎn),又怎么使用呢,接下來(lái)就請(qǐng)大家跟我一起來(lái)學(xué)習(xí)吧2023-05-05解決springboot讀取application.properties中文亂碼問(wèn)題
初用properties,讀取java properties文件的時(shí)候如果value是中文,會(huì)出現(xiàn)亂碼的問(wèn)題,所以本文小編將給大家介紹如何解決springboot讀取application.properties中文亂碼問(wèn)題,需要的朋友可以參考下2023-11-11