欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?中泛型?T?和???的區(qū)別詳解

 更新時間:2022年01月09日 10:39:45   作者:dying?擱淺  
本文主要介紹了Java?中泛型?T?和???的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

泛型中 T 類型變量 和 ? 通配符 區(qū)別

定義不同 :T 是類型變量,? 是通配符

使用范圍不同:

  • ? 通配符用作 參數(shù)類型、字段類型、局部變量類型,有時作為返回類型(但請避免這樣做)
  • T 用作 聲明類的類型參數(shù)、通用方法的類型參數(shù) (這里注意 類型參數(shù) 和 參數(shù)類型 是兩個概念)

通常我們使用 ? 的時候并并不知道也不關(guān)心這個時候的類型,這里只想使用其通用的方法,而且 ? 通配符是無法作用于聲明類的類型參數(shù),一般作用于方法和參數(shù)上。而 類型變量 T 在類定義時具有更廣泛的應(yīng)用。

在某些程度的使用上 ? 通配符與 T 參數(shù)類型是可以等效的,但是 T 參數(shù)類型并不支持下界限制 即 T super SomeTing 而 通配符支持 ? super SomeThing

如果你想寫一個通用的方法且該方法的邏輯不關(guān)心類型那么就大膽的用 ? 通配符來進(jìn)行適配和限制吧,如果你需要作用域類型(這可能在操作通用數(shù)組類型時更明顯)或者聲明類的類型參數(shù)時請使用 T 類型變量

類型參數(shù)定義了一種代表作用域類型的變量(例如,T),通配符只是定義了一組可用于泛型類型的允許類型。通配符的意思是“在這里使用任何類型”

在泛型的使用中我們經(jīng)常可以看到這樣的用法:

public class Box<T> {
? ? // T stands for "Type"
? ? private T t;

? ? public void set(T t) { this.t = t; }
? ? public T get() { return t; }
}
List<? extends Integer> intList = new ArrayList<>();
List<? extends Number>  numList = intList;  // OK. List<? extends Integer> is a subtype of List<? extends Number>
public interface GenericProgressiveFutureListener<F extends ProgressiveFuture<?>> extends GenericFutureListener<F> {
    void operationProgressed(F future, long progress, long total) throws Exception;
}

如果你其用法和概念仍有疑問,那不妨繼續(xù)閱讀本文

了解他們的概念:Generic Types Wildcards ,以及使用。

Generic Types 類型變量

通用類型即 T、F、K、V 這樣的寫法,它是一種是通過類型參數(shù)化的通用類或接口,也可以稱之為 類型變量

類型變量可以是任何非原始類型:任何類類型、任何接口類型、任何數(shù)組類型,甚至是另一個類型變量

按照慣例,類型參數(shù)名稱是單個大寫字母。

最常用的類型參數(shù)名稱是:

  • E - 元素(被 Java 集合框架廣泛使用)
  • K - 鍵
  • N - 數(shù)字
  • T - 類型
  • V - 值
  • S、U、V 等 - 第 2、3、4 種類型

用法

1.聲明通用的類型 – 泛型類:

當(dāng)我們想對通用的對象類型進(jìn)行操作時我們可能想到使用 Object ,但是使用 Object 在編譯時無法進(jìn)行檢查,因為 Object 是所有類的父類,這可能導(dǎo)致我們意圖在傳入 Integer 并可以取出 Inerger 時,在另一部分代碼錯誤的傳入了 String

public class Box {
? ? private Object object;

? ? public void set(Object object) { this.object = object; }
? ? public Object get() { return object; }
}

為了避免上述的問題,我們可以選擇使用 類型變量

public class Box<T> {
? ? // T stands for "Type"
? ? private T t;

? ? public void set(T t) { this.t = t; }
? ? public T get() { return t; }
}

你也可以使用多個類型參數(shù)

public interface Pair<K, V> {
? ? public K getKey();
? ? public V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {

? ? private K key;
? ? private V value;

? ? public OrderedPair(K key, V value) {
?? ?this.key = key;
?? ?this.value = value;
? ? }

? ? public K getKey()?? ?{ return key; }
? ? public V getValue() { return value; }
}

2.聲明通用的方法 – 泛型方法:

泛型方法 是引入自己的類型參數(shù)的方法。這類似于聲明泛型類型,但類型參數(shù)的范圍僅限于聲明它的方法。允許靜態(tài)和非靜態(tài)泛型方法,以及泛型類構(gòu)造函數(shù)。

泛型方法的語法包括一個類型參數(shù)列表,在尖括號內(nèi),它出現(xiàn)在方法的返回類型之前。對于靜態(tài)泛型方法,類型參數(shù)部分必須出現(xiàn)在方法的返回類型之前。

public class Util {
? ? public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
? ? ? ? return p1.getKey().equals(p2.getKey()) &&
? ? ? ? ? ? ? ?p1.getValue().equals(p2.getValue());
? ? }
}

public static <T> void printListT(List<T> list) {
? ? for (Object elem : list)
? ? ? ? System.out.println(elem + " ");
? ? System.out.println();
}

一個完整的調(diào)用是

JestTestMain.<String>printListT(names);

但是通??梢允÷灶愋?,這里使用到的功能是 類型推斷

JestTestMain.printListT(names);

有界類型參數(shù)

同時我們可以對類型參數(shù)進(jìn)行限制通過 extends 關(guān)鍵字

如 <T extends Number> 這里的泛型參數(shù)就限制了必須繼承于 Number 類。

public static <T extends Number> void printListT(List<T> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}

同時 Java 也支持多重限定,如 <T extends CharSequence & Comparable<T> & Serializable> 但是如果其中限定包含 類 需要寫在最前面

public static <T extends CharSequence & Comparable<T> & Serializable> void printListT(List<T> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}

Wildcards 通配符

通配符即指 ?

在泛型代碼中,? 表示未知類型。通配符可用于多種情況:

作為參數(shù)、字段或局部變量的類型,有時作為返回類型(但請避免這樣做)。

通配符從不用作泛型方法調(diào)用、泛型類實例創(chuàng)建或超類型的類型參數(shù)。

用法

通配符分為 3 種:

1.上界通配符:? extend 上界類型

List public static void process(List list) { /* ... */ }

我們可以使用上界通配符來放寬對變量的限制

2.無界通配符:?

如 List<?> 這表示未知類型的列表,一般有兩種情況下無界通配符是有用的:

  • 你正在編寫可以使用 Object類中提供的功能實現(xiàn)的方法
  • 當(dāng)代碼使用不依賴于類型參數(shù)的泛型類中的方法時。例如,List.size或 List.clear。事實上,Class<?> 之所以如此常用,是因為 Class<T>中的大多數(shù)方法都不依賴于 T。

如何理解這句話的意思呢?來看一個例子:

public static void printList(List<Object> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}

printList 的意圖是想打印任何類型的列表,但是它沒有達(dá)到目標(biāo),其只打印了 Object 實例的列表。它不能打印 List<Integer>、List<String>、List<Double>等,因為它們不是 List<Object> 的子類型。

編譯時將會報錯。

這里我們換成通配符將正確運(yùn)行

public class JestTestMain {
? ? public static void main(String[] args) {
? ? ? ? List<String> names= Lists.newArrayList();
? ? ? ? names.add("張三");
? ? ? ? names.add("張三1");
? ? ? ? names.add("張三2");
? ? ? ? printList(names);
? ? }

? ? public static void printList(List<?> list) {
? ? ? ? for (Object elem : list)
? ? ? ? ? ? System.out.println(elem + " ");
? ? ? ? System.out.println();
? ? }
}

打?。?/p>

張三 
張三1 
張三2 

這里需要明白的一點是,List<Object> 和 List<?> 并不相同,你可以向 List<Object> 中插入 Object 對象,或者任何其子類對象,但是你只能向 List<?> 中插入 null 值。

3.下界通配符:? super 子類

如:<? super Integer>

假設(shè)你要編寫一個將 Integer 對象放入列表的方法。為了最大限度地提高靈活性,希望該方法適用于 List<Integer>、List<Number>和 List<Object> 任何可以保存 Integer 值的東西。

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}

類型擦除

我們要知道的一件事兒,編譯器在編譯時清除了所有類型參數(shù),也就是說會將我們的類型參數(shù)進(jìn)行實際的替換。

就算如此我們?nèi)杂惺褂梅盒偷睦碛?/p>

  • Java 編譯器在編譯時對泛型代碼執(zhí)行更嚴(yán)格的類型檢查。
  • 泛型支持編程類型作為參數(shù)。
  • 泛型能夠?qū)崿F(xiàn)泛型算法。

Java 語言中引入了泛型以在編譯時提供更嚴(yán)格的類型檢查并支持泛型編程。為了實現(xiàn)泛型,Java 編譯器將類型擦除應(yīng)用于:

  • 如果類型參數(shù)是無界的,則將泛型類型中的所有類型參數(shù)替換為其邊界或 Object。因此,生成的字節(jié)碼僅包含普通的類、接口和方法。
  • 必要時插入類型轉(zhuǎn)換以保持類型安全。
  • 生成橋接方法以保留擴(kuò)展泛型類型中的多態(tài)性。

類型擦除確保不會為參數(shù)化類型創(chuàng)建新類;因此,泛型不會產(chǎn)生運(yùn)行時開銷。

下面舉兩個例子

// 類型擦除前
public class Pair<K, V> {

? ? public Pair(K key, V value) {
? ? ? ? this.key = key;
? ? ? ? this.value = value;
? ? }

? ? public K getKey(); { return key; }
? ? public V getValue(); { return value; }

? ? public void setKey(K key) ? ? { this.key = key; }
? ? public void setValue(V value) { this.value = value; }

? ? private K key;
? ? private V value;
}
// 類型擦除后
public class Pair {

? ? public Pair(Object key, Object value) {
? ? ? ? this.key = key;
? ? ? ? this.value = value;
? ? }

? ? public Object getKey() ? { return key; }
? ? public Object getValue() { return value; }

? ? public void setKey(Object key) ? ? { this.key = key; }
? ? public void setValue(Object value) { this.value = value; }

? ? private Object key;
? ? private Object value;
}

// 類型擦除前
public static <T extends Comparable<T>> int findFirstGreaterThan(T[] at, T elem) {
? ? // ...
}
// 類型擦除后
public static int findFirstGreaterThan(Comparable[] at, Comparable elem) {
? ? // ...
}

最后感興趣的同學(xué)可以參考:

Java Tutorial on Generics
Generics in the Java programming language

到此這篇關(guān)于Java 中泛型 T 和 ? 的區(qū)別詳解的文章就介紹到這了,更多相關(guān)Java 泛型T和? 區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論