亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java不能真正泛型的原因是什么?

 更新時(shí)間:2021年08月02日 15:03:20   作者:沉默王二  
今天我來給大家講一下,Java 不能實(shí)現(xiàn)真正泛型的原因是什么?感興趣的朋友可以看一下,如果能給你到來一些幫助,請(qǐng)關(guān)注小編的其他內(nèi)容

簡(jiǎn)單來回顧一下類型擦除,看下面這段代碼。

public class Cmower {
    public static void method(ArrayList<String> list) {
        System.out.println("Arraylist<String> list");
    }
    public static void method(ArrayList<Date> list) {
        System.out.println("Arraylist<Date> list");
    }
}

在淺層的意識(shí)上,我們會(huì)認(rèn)為 ArrayList<String> list 和 ArrayList<Date> list 是兩種不同的類型,因?yàn)?String 和 Date 是不同的類。

但由于類型擦除的原因,以上代碼是不會(huì)編譯通過的——編譯器會(huì)提示一個(gè)錯(cuò)誤:

‘method(ArrayList)' clashes with ‘method(ArrayList)'; both methods have same erasure

也就是說,兩個(gè) method() 方法經(jīng)過類型擦除后的方法簽名是完全相同的,Java 是不允許這樣做的。

也就是說,按照我們的假設(shè):如果 Java 能夠?qū)崿F(xiàn)真正意義上的泛型,兩個(gè) method() 方法是可以同時(shí)存在的,就好像方法重載一樣。

public class Cmower {
    public static void method(String list) {
    }
    public static void method(Date list) {
    }
}

為什么 Java 不能實(shí)現(xiàn)真正意義上的泛型呢?背后的原因是什么?

第一,兼容性

Java 在 2004 年已經(jīng)積累了較為豐富的生態(tài),如果把現(xiàn)有的類修改為泛型類,需要讓所有的用戶重新修改源代碼并且編譯,這就會(huì)導(dǎo)致 Java 1.4 之前打下的江山可能會(huì)完全覆滅。

想象一下,你的代碼原來運(yùn)行的好好的,就因?yàn)?JDK 的升級(jí),導(dǎo)致所有的源代碼都無法編譯通過并且無法運(yùn)行,是不是會(huì)非常痛苦?

類型擦除就完美實(shí)現(xiàn)了兼容性,Java 1.5 之后的類可以使用泛型,而 Java 1.4 之前沒有使用泛型的類也可以保留,并且不用做任何修改就能在新版本的 Java 虛擬機(jī)上運(yùn)行。

老用戶不受影響,新用戶可以自由地選擇使用泛型,可謂一舉兩得。

第二,不是“實(shí)現(xiàn)不了”

這部分內(nèi)容參考自 R大@RednaxelaFX

Pizza,1996 年的實(shí)驗(yàn)語言,在 Java 的基礎(chǔ)上擴(kuò)展了泛型。

Pizza 教程地址:http://pizzacompiler.sourceforge.net/doc/tutorial.html

這里插一下 Java 的版本歷史,大家好有一個(gè)時(shí)間線上的觀念。

  • 1995年5月23日,Java語言誕生
  • 1996年1月,JDK1.0 誕生
  • 1997年2月18日,JDK1.1發(fā)布
  • 1998年2月,JDK1.1被下載超過2,000,000次
  • 2000年5月8日,JDK1.3發(fā)布
  • 2000年5月29日,JDK1.4發(fā)布
  • 2004年9月30日18:00 PM,J2SE1.5 發(fā)布

也就是說,Pizza 在 JDK 1.0 的版本上就實(shí)現(xiàn)了“真正意義上的”泛型,我引過來兩段例子,大家一看就明白了。

首先是 StoreSomething,一個(gè)泛型類,標(biāo)識(shí)符是大寫字母 A 而不是我們熟悉的大寫字母 T。

class StoreSomething<A> {
     A something;
     StoreSomething(A something) {
         this.something = something;
     }
     void set(A something) {
         this.something = something;
     }
     A get() {
         return something;
     }
}

這個(gè) A 呢,可以是任何合法的 Java 類型:

StoreSomething<String> a = new StoreSomething("I'm a string!");
StoreSomething<int> b = new StoreSomething(17+4);
b.set(9);
int i = b.get();
String s = a.get();

對(duì)吧?這就是我們想要的“真正意義上的泛型”,A 不僅僅可以是引用類型 String,還可以是基本數(shù)據(jù)類型。要知道,Java 的泛型不允許是基本數(shù)據(jù)類型,只能是包裝器類型。

除此之外,Pizza 的泛型還可以直接使用 new 關(guān)鍵字進(jìn)行聲明,并且 Pizza 編譯器會(huì)從構(gòu)造方法的參數(shù)上推斷出具體的對(duì)象類型,究竟是 String 還是 int。要知道,Java 的泛型因?yàn)轭愋筒脸脑?,程序員是無法知道一個(gè) ArrayList 究竟是 ArrayList<String> 還是 ArrayList<Integer> 的。

ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<String> strs = new ArrayList<String>();
System.out.println(ints.getClass());
System.out.println(strs.getClass());

輸出結(jié)果:

class java.util.ArrayList class java.util.ArrayList

都是 ArrayList 而已。

那 Pizza 這種“真正意義上的泛型”為什么沒有被 Java 采納呢?這是大家都很關(guān)心的問題。

事實(shí)上,Java 的核心開發(fā)組對(duì) Pizza 的泛型設(shè)計(jì)非常感興趣,并且與 Pizza 的設(shè)計(jì)者 Martin 和 Phil 取得了聯(lián)系,新合作了一個(gè)項(xiàng)目 Generic Java,爭(zhēng)取在 Java 中添加泛型支持,但不引入 Pizza 的其他功能,比如說函數(shù)式編程。

這里再補(bǔ)充一點(diǎn)維基百科上的資料,Martin Odersky 是一名德國(guó)計(jì)算機(jī)科學(xué)家,他和其他人一起設(shè)計(jì)了 Scala 編程語言,以及 Generic Java(還有之前的 Pizza),他實(shí)現(xiàn)的 Generic Java 編譯器成為了 Java 編譯器 javac 的基礎(chǔ)。

站在馬后炮的思維來看,Pizza 的泛型設(shè)計(jì)和函數(shù)式編程非常具有歷史前瞻性。然而 Java 的核心開發(fā)組在當(dāng)時(shí)似乎并不想把函數(shù)式編程引入到 Java 中。

以至于 Java 在 1.4 之前仍然是不支持泛型的,為什么 Java 1.5 的時(shí)候又突然支持泛型了呢?

當(dāng)然是到了不支持不行的時(shí)候了。

沒有泛型之前,我們可以這樣寫代碼:

ArrayList list = new ArrayList();
list.add("沉默王二");
list.add(new Date());

不管是 String 類型,還是 Date 類型,都可以一股腦塞進(jìn) ArrayList 當(dāng)中,這看起來似乎很方便,但取的時(shí)候就悲劇了。

String s = list.get(1);

這樣取行嗎?

不行。

還得加上強(qiáng)制轉(zhuǎn)換。

String s = (String) list.get(1);

但我們知道,這行代碼在運(yùn)行的時(shí)候必然會(huì)出錯(cuò):

Exception in thread "main" java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.String

這就又回到“兼容性”的問題了。

Java 語言和其他編程語言不一樣,有著沉重的歷史包袱,1.5 之前已經(jīng)有大量的程序部署在生產(chǎn)環(huán)境下了,這時(shí)候如果一刀切,原來沒有使用泛型的代碼直接扼殺了,后果不堪想象。

Java 一直以來都強(qiáng)調(diào)兼容性,我認(rèn)為這也是 Java 之所以能被廣泛使用的主要原因之一,開發(fā)者不必?fù)?dān)心 Java 版本升級(jí)的問題,一個(gè)在 JDK 1.4 上可以跑的代碼,放在 JDK 1.5 上仍然可以跑。

這里必須得說明一點(diǎn),J2SE1.5 的發(fā)布,是 Java 語言發(fā)展史上的重要里程碑,為了表示該版本的重要性,J2SE1.5 也正式更名為 Java SE 5.0,往后去就是 Java SE 6.0,Java SE 7.0。。。。

但 Java 并不支持高版本 JDK 編譯生成的字節(jié)碼文件在低版本的 JRE(Java 運(yùn)行時(shí)環(huán)境)上跑。

針對(duì)泛型,兼容性具體表現(xiàn)在什么地方呢?

ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<String> strs = new ArrayList<String>();
ArrayList list;
list = ints;
list = strs;

表現(xiàn)在上面這段代碼必須得能夠編譯運(yùn)行。怎么辦呢?

就只能搞類型擦除了!

真所謂“表面上一套,背后玩另外一套”呀!

編譯前進(jìn)行泛型檢測(cè),ArrayList<Integer> 只能放 Integer,ArrayList<String> 只能放 String,取的時(shí)候就不用擔(dān)心類型強(qiáng)轉(zhuǎn)出錯(cuò)了。

但編譯后的字節(jié)碼文件里,是沒有泛型的,放的都是 Object。

Java 神奇就神奇在這,表面上萬物皆對(duì)象,但為了性能上的考量,又存在 int、double 這種原始類型,但原始類型又沒辦法和 Object 兼容,于是我們就只能寫 ArrayList<Integer> 這樣很占用內(nèi)存空間的代碼。

這恐怕也是 Java 泛型被吐槽的原因之一了。

總結(jié)

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Java自定義映射resultMap定義及用法

    Java自定義映射resultMap定義及用法

    MyBatis的每一個(gè)查詢映射的返回類型都是ResultMap,當(dāng)我們提供返回類型屬性是resultType時(shí),MyBatis會(huì)自動(dòng)給我們把對(duì)應(yīng)值賦給resultType所指定對(duì)象的屬性,當(dāng)我們提供返回類型是resultMap時(shí),將數(shù)據(jù)庫中列數(shù)據(jù)復(fù)制到對(duì)象的相應(yīng)屬性上,可以用于復(fù)制查詢,兩者不能同時(shí)用
    2022-11-11
  • SpringCloud+Redis實(shí)現(xiàn)Api接口限流防止惡意刷接口

    SpringCloud+Redis實(shí)現(xiàn)Api接口限流防止惡意刷接口

    接口限流是為了保護(hù)系統(tǒng)和服務(wù),防止因?yàn)檫^多的請(qǐng)求而崩潰,本文主要介紹了SpringCloud+Redis實(shí)現(xiàn)Api接口限流防止惡意刷接口,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • maven報(bào)錯(cuò):Failed to execute goal on project問題及解決

    maven報(bào)錯(cuò):Failed to execute goal on p

    這篇文章主要介紹了maven報(bào)錯(cuò):Failed to execute goal on project問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java Spring注解之@Async的基本用法和示例

    Java Spring注解之@Async的基本用法和示例

    Spring為任務(wù)調(diào)度與異步方法執(zhí)行提供了注解支持,通過在方法上設(shè)置@Async注解,可使得方法被異步調(diào)用,下面這篇文章主要給大家介紹了關(guān)于Java Spring注解之@Async的基本用法和示例,需要的朋友可以參考下
    2022-03-03
  • Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別)

    Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別)

    這篇文章主要介紹了Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別) ,需要的朋友可以參考下
    2017-02-02
  • Spring Boot 配置 IDEA和DevTools 熱部署的方法

    Spring Boot 配置 IDEA和DevTools 熱部署的方法

    這篇文章主要介紹了Spring Boot 配置 IDEA和DevTools 熱部署的方法,需要的朋友可以參考下
    2018-02-02
  • 深入淺出分析Java抽象類和接口【功能,定義,用法,區(qū)別】

    深入淺出分析Java抽象類和接口【功能,定義,用法,區(qū)別】

    這篇文章主要介紹了Java抽象類和接口,結(jié)合實(shí)例形式深入淺出的分析了java抽象類與接口的功能功能,定義,用法及區(qū)別,需要的朋友可以參考下
    2017-08-08
  • 基于Java中Math類的常用函數(shù)總結(jié)

    基于Java中Math類的常用函數(shù)總結(jié)

    下面小編就為大家?guī)硪黄贘ava中Math類的常用函數(shù)總結(jié)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-09-09
  • Spring配置文件中parent與abstract的使用

    Spring配置文件中parent與abstract的使用

    這篇文章主要介紹了Spring配置文件中parent與abstract的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java獲取當(dāng)前操作系統(tǒng)的信息實(shí)例代碼

    Java獲取當(dāng)前操作系統(tǒng)的信息實(shí)例代碼

    這篇文章主要介紹了Java獲取當(dāng)前操作系統(tǒng)的信息實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12

最新評(píng)論