自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

探秘 Java 泛型:從類型參數(shù)到邊界限制與類型擦除

開發(fā)
本文深入探討了 Java 中的泛型概念及其使用方法,并給出了多個(gè)基本示例。理解和運(yùn)用泛型能增強(qiáng)程序類型安全性,消除顯式強(qiáng)制轉(zhuǎn)換需求,使代碼更具重用性和可維護(hù)性。

在 Java 編程中,大家或許都遭遇過令人頭疼的ClassCastException,尤其是在處理如Integer、String等不同類型對(duì)象時(shí)。這個(gè)異常通常是由于將對(duì)象強(qiáng)制轉(zhuǎn)換為錯(cuò)誤的數(shù)據(jù)類型所導(dǎo)致的。不過,Java 中的泛型可以幫助我們解決這一問題。

為什么我們需要泛型?

讓我們從一個(gè)簡(jiǎn)單的例子開始。我們首先將不同類型的對(duì)象添加到一個(gè)ArrayList中。然后打印它們的值。

List list = new ArrayList();
list.add("Hello");
String str = (String) list.get(0);
System.out.println("String: " + str);

這里,我們向ArrayList添加了一個(gè)String對(duì)象。由于代碼是自己編寫,我們清楚元素類型,但編譯器并不知曉。所以從列表獲取值時(shí)得到的是Object類型,必須進(jìn)行顯式強(qiáng)制轉(zhuǎn)換。

list.add(123);
String number = (String) list.get(1);
System.out.println("Number: " + number);

如果我們向這個(gè)列表中添加一個(gè)Integer并嘗試獲取該值,我們將得到一個(gè)ClassCastException,因?yàn)镮nteger對(duì)象不能被強(qiáng)制轉(zhuǎn)換為String。 而使用泛型,就能解決上述兩個(gè)問題。使用菱形運(yùn)算符明確指定列表中保存的對(duì)象類型,可實(shí)現(xiàn)編譯時(shí)檢查,無需顯式強(qiáng)制轉(zhuǎn)換。

List<String> list = new ArrayList<>();
list.add("Hello");
String str = list.get(0); // 無需顯式強(qiáng)制轉(zhuǎn)換
System.out.println("String: " + str);
list.add(123); // 拋出編譯時(shí)錯(cuò)誤

類型參數(shù)命名約定

在前面示例中,List<String>的使用限制了列表可保存的對(duì)象類型。再看Box類處理不同類型數(shù)據(jù)的示例:

public class Box<T> {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.setValue("Hello, world!");
        System.out.println(stringBox.getValue());

        Box<Integer> integerBox = new Box<>();
        integerBox.setValue(123);
        System.out.println(integerBox.getValue());
    }
}

注意Box<T>類的聲明,這里T是類型參數(shù),表示Box類可處理該類型的任意對(duì)象。在main方法中創(chuàng)建Box<String>和Box<Integer>實(shí)例,確保了類型安全。

根據(jù)官方文檔,類型參數(shù)名稱通常為單個(gè)大寫字母。常見的類型參數(shù)名稱有:

  • E - 元素(廣泛用于 Java 集合框架)
  • K - 鍵
  • N - 數(shù)字
  • T - 類型
  • V - 值
  • S、U、V等 - 第二、第三、第四種類型

讓我們看看如何編寫一個(gè)泛型方法:

public static <T> void printArray(T[] inputArr) {
    for (T element : inputArr) {
        System.out.print(element + " ");
    }
    System.out.println();
}

這里,我們接受任何類型的數(shù)組并打印其元素。請(qǐng)注意,你需要在方法返回類型之前的尖括號(hào)<>中指定泛型類型參數(shù)T。方法體遍歷我們作為參數(shù)傳遞的任何類型T的數(shù)組,并打印每個(gè)元素。

public static void main(String[] args) {
    // 創(chuàng)建不同類型的數(shù)組(Integer、Double和Character)
    Integer[] intArr = {1, 2, 3, 4, 5};
    Double[] doubleArr = {1.1, 2.2, 3.3, 4.4, 5.5};
    Character[] charArr = {'H', 'E', 'L', 'L', 'O'};

    System.out.println("Integer數(shù)組包含:");
    printArray(intArr);   // 傳遞一個(gè)Integer數(shù)組

    System.out.println("Double數(shù)組包含:");
    printArray(doubleArr);   // 傳遞一個(gè)Double數(shù)組

    System.out.println("Character數(shù)組包含:");
    printArray(charArr);   // 傳遞一個(gè)Character數(shù)組
}

我們可以通過傳遞不同類型的數(shù)組(Integer、Double、Character)來調(diào)用這個(gè)泛型方法,你會(huì)看到你的程序?qū)⒋蛴〕鲞@些數(shù)組的每個(gè)元素。

泛型的限制

在泛型中,我們使用邊界來限制泛型類、接口或方法可以接受的類型。有兩種類型:

1. 上界

這用于將泛型類型限制為上限。要定義上界,你使用extends關(guān)鍵字。通過指定上界,你確保類、接口或方法接受指定的類型及其所有子類。 語法如下:<T extends SuperClass>。例如,修改Box類:

class Box<T extends Number> {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

在這個(gè)例子中,T可以是任何擴(kuò)展Number的類型,如Integer、Double或Float。

2. 下界

這用于將泛型類型限制為下限。要定義下界,你使用super關(guān)鍵字。通過指定下界,你確保類、接口或方法接受指定的類型及其所有超類。 語法如下:<T super SubClass>。以下是使用下界的示例:

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

下界<? super Integer>的使用確保你可以將指定的類型及其所有超類(在這種情況下是Integer、Number或Object的列表)傳遞給printList方法。

什么是通配符?

你在上一個(gè)示例中看到的?被稱為通配符。你可以使用它們來引用未知類型。你可以使用帶有上界的通配符,在這種情況下它看起來像這樣:<? extends Number>。它也可以與下界一起使用,如<? super Integer>。

類型擦除

我們?cè)陬悺⒔涌诨蚍椒ㄖ惺褂玫姆盒皖愋蛢H在編譯時(shí)可用,并且在運(yùn)行時(shí)會(huì)被刪除。這樣做是為了確保向后兼容性,因?yàn)榕f版本的Java(Java 1.5之前)不支持它。 編譯器利用泛型類型信息確保類型安全。類型擦除過程如下:

  • 對(duì)于有界泛型類型,編譯器會(huì)將其擦除為它的上界類型。例如,class Box<T extends Number>,T會(huì)被擦除為Number。
  • 對(duì)于無界泛型類型(如class Box<T>),T會(huì)被擦除為Object。所以在運(yùn)行時(shí),實(shí)際上并不能獲取到泛型參數(shù)的具體類型信息。
import java.util.ArrayList;
import java.util.List;
class GenericExample<T> {
    private List<T> list = new ArrayList<>();
    public void add(T element) {
        list.add(element);
    }
    public T get(int index) {
        return list.get(index);
    }
}

當(dāng)編譯器編譯這段代碼時(shí),T會(huì)被擦除。對(duì)于add方法,實(shí)際上變成了類似public void add(Object element)(如果T是無界的)。對(duì)于get方法,返回值類型也被擦除為Object,不過編譯器會(huì)在需要的時(shí)候插入強(qiáng)制類型轉(zhuǎn)換。

結(jié)論

本文深入探討了 Java 中的泛型概念及其使用方法,并給出了多個(gè)基本示例。理解和運(yùn)用泛型能增強(qiáng)程序類型安全性,消除顯式強(qiáng)制轉(zhuǎn)換需求,使代碼更具重用性和可維護(hù)性。希望通過本文的介紹,大家能在 Java 編程中更好地運(yùn)用泛型,提升代碼質(zhì)量。

責(zé)任編輯:趙寧寧 來源: 程序猿技術(shù)充電站
相關(guān)推薦

2023-03-24 15:53:24

JavaJava 泛型開發(fā)

2023-04-10 16:34:45

編程Java開發(fā)

2024-06-07 10:05:31

2009-08-24 14:51:25

C# 泛型泛型類型

2011-04-13 09:16:55

泛型

2021-08-24 08:05:41

泛型類型擦除Class

2022-03-02 14:41:03

泛型反序列化

2025-03-26 01:45:00

泛型C#開發(fā)者

2009-09-08 16:36:10

LINQ查詢基于泛型類

2022-06-19 22:54:08

TypeScript泛型工具

2020-12-21 16:18:07

JavaTypeToken泛型擦除

2009-04-24 09:33:12

LINQ查詢非泛型

2021-07-01 06:47:30

Java泛型泛型擦除

2009-08-24 14:20:13

C# 強(qiáng)制類型轉(zhuǎn)換

2023-03-06 08:33:24

IDEA反編譯類型

2024-03-06 08:17:18

Java泛型安全

2021-07-29 09:20:18

Java泛型String

2024-11-05 09:11:09

TypeScript開發(fā)者代碼

2013-03-20 09:27:33

C#泛型

2019-09-04 00:20:10

JSON泛型擦除
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)