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ù)化類型,也就是說所操作的數(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)和用戶信息了??涩F(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可見,利用泛型,可以統(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ù)聲明部分在方法返回類型之前
比如說這是一個(gè)用來(lái)打印數(shù)組的泛型方法:
private static <E> void printArray(E[] inputArray)
每一個(gè)類型參數(shù)聲明部分包含一個(gè)或多個(gè)類型參數(shù),參數(shù)間用逗號(hào)隔開。一個(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)記符,這是一種**約定。**在開發(fā)中很多規(guī)則都是一種約定,它能提高我們代碼的可讀性,方便團(tuán)隊(duì)見的合作開發(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)殚_篇的例子就是封裝了一個(gè)泛型類,當(dāng)時(shí)不太理解的可以再回去看一下
類型通配符
?
我們一般可以使用?來(lái)承接所有的引用類型,搬運(yùn)一個(gè)菜鳥上的例子:
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 和 ?
不知道看到這里,有沒有疑惑。T和?好像作用差不多啊,有什么區(qū)別?
這里解釋一下,T一般作為泛型參數(shù),而?是更多是用來(lái)一個(gè)不確定的引用類型,意會(huì)一下吧~~~

T 和 Object
重頭戲?。?/p>
知道的Object的同志都了解其是Java的超類(所有對(duì)象的父類),不了解的可以去看看我的博客,有做詳細(xì)的解釋。
那么問題就來(lái)了,Object好像可以代替泛型的功能?。∷心苡玫椒盒偷牡胤絆bject都可以!
其實(shí),在JDK5之前,都是用的Object,但其存在很多的問題,JDK5之后便引入了泛型
Object是所有類的父類,在編碼過程中就難免出現(xiàn)類型轉(zhuǎn)化問題,且在編譯階段不會(huì)報(bào)錯(cuò),到了運(yùn)行階段才暴露問題,大大降低了程序的安全性和健壯性!
舉例之前說一些轉(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)問題,很遜的誒~
舉個(gè)例子看看:

利用Object定義了一個(gè)數(shù)字變量,我們常識(shí)將其向下轉(zhuǎn)型為Integer和String。將一個(gè)數(shù)字轉(zhuǎn)型為字符串是一件荒唐的事情,可編譯器并不能察覺這件事,直到程序運(yùn)行了起來(lái)...

類型轉(zhuǎn)換異常?。?!
總結(jié)
泛型的出現(xiàn),當(dāng)類型轉(zhuǎn)化出現(xiàn)問題的時(shí)候,在編譯階段就會(huì)暴露出來(lái)。解決了Object存在的諸多問題,讓代碼更加優(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-03
springboot項(xiàng)目如何設(shè)置時(shí)區(qū)
這篇文章主要介紹了springboot項(xiàng)目如何設(shè)置時(shí)區(qū)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java利用Easyexcel導(dǎo)出excel表格的示例代碼
這篇文章主要為大家詳細(xì)介紹了Java利用Easyexcel導(dǎo)出excel表格的示例代碼,文中的代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2022-07-07
Java中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中文亂碼問題
初用properties,讀取java properties文件的時(shí)候如果value是中文,會(huì)出現(xiàn)亂碼的問題,所以本文小編將給大家介紹如何解決springboot讀取application.properties中文亂碼問題,需要的朋友可以參考下2023-11-11

