成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

了解泛型擦除嗎?知道類型擦除會造成多態的沖突嗎?如何解決?

開發 前端
如果是重載,那么子類中兩個setValue方法,一個是參數Object類型,一個是Date類型,可是根本就沒有這樣的一個子類繼承自父類的Object類型參數的方法。所以說,確實是重寫了,而不是重載了。

泛型的代碼只存在于編譯階段,在進入JVM之前,與泛型相關的信息會被擦除掉,稱之為類型擦除。

  • 無限制類型擦除:當在類的定義時沒有進行任何限制,那么在類型擦除后將會被替換成Object,例如<T>、<?> 都會被替換成Object。
  • 有限制類型擦除:當類定義中的參數類型存在上下限(上下界),那么在類型擦除后就會被替換成類型參數所定義的上界或者下界,例如<? extend Person>會被替換成Person,而<? super Person> 則會被替換成Object。

泛型的橋接方法

類型擦除會造成多態的沖突,而JVM解決方法就是橋接方法。

舉例

現在有這樣一個泛型類:

class Pair<T> {  

    private T value;  

    public T getValue() {  
        return value;  
    }  

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

然后一個子類繼承它

class DateInter extends Pair<Date> {  

    @Override  
    public void setValue(Date value) {  
        super.setValue(value);  
    }  

    @Override  
    public Date getValue() {  
        return super.getValue();  
    }  
}

在這個子類中,設定父類的泛型類型為Pair<Date>,在子類中,覆蓋了父類的兩個方法,原意是這樣的:將父類的泛型類型限定為Date,那么父類里面的兩個方法的參數都為Date類型。

public Date getValue() {  
    return value;  
}  

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

實際上,類型擦除后,父類的的泛型類型全部變為了原始類型Object,所以父類編譯之后會變成下面的樣子:

class Pair {  
    private Object value;  

    public Object getValue() {  
        return value;  
    }  

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

再看子類的兩個重寫的方法的類型:setValue方法,父類的類型是Object,而子類的類型是Date,參數類型不一樣,這如果實在普通的繼承關系中,根本就不會是重寫,而是重載。 在一個main方法測試一下:

public static void main(String[] args) throws ClassNotFoundException {  
        DateInter dateInter = new DateInter();  
        dateInter.setValue(new Date());                  
        dateInter.setValue(new Object()); //編譯錯誤  
}

如果是重載,那么子類中兩個setValue方法,一個是參數Object類型,一個是Date類型,可是根本就沒有這樣的一個子類繼承自父類的Object類型參數的方法。所以說,確實是重寫了,而不是重載了。

為什么這樣?

原因是這樣的,傳入父類的泛型類型是Date,Pair<Date>,本意是將泛型類變為如下:

class Pair {  
    private Date value;  
    public Date getValue() {  
        return value;  
    }  
    public void setValue(Date value) {  
        this.value = value;  
    }  
}

然后在子類中重寫參數類型為Date的兩個方法,實現繼承中的多態。

可是由于種種原因,虛擬機并不能將泛型類型變為Date,只能將類型擦除掉,變為原始類型Object。這樣,原來是想進行重寫,實現多態,可是類型擦除后,只能變為了重載。這樣,類型擦除就和多態有了沖突。于是JVM采用了一個特殊的方法,來完成這項功能,那就是橋方法。

原理

用javap -c className的方式反編譯下DateInter子類的字節碼,結果如下:

class com.tao.test.DateInter extends com.tao.test.Pair<java.util.Date> {  
  com.tao.test.DateInter();  
    Code:  
       0: aload_0  
       1: invokespecial #8                  // Method com/tao/test/Pair."<init>":()V  
       4: return

public void setValue(java.util.Date);  //我們重寫的setValue方法  
    Code:  
       0: aload_0  
       1: aload_1  
       2: invokespecial #16                 // Method com/tao/test/Pair.setValue:(Ljava/lang/Object;)V  
       5: return

public java.util.Date getValue();    //我們重寫的getValue方法  
    Code:  
       0: aload_0  
       1: invokespecial #23                 // Method com/tao/test/Pair.getValue:()Ljava/lang/Object;  
       4: checkcast     #26                 // class java/util/Date  
       7: areturn  

public java.lang.Object getValue();     //編譯時由編譯器生成的橋方法  
    Code:  
       0: aload_0  
       1: invokevirtual #28                 // Method getValue:()Ljava/util/Date 去調用我們重寫的getValue方法;  
       4: areturn  

  public void setValue(java.lang.Object);   //編譯時由編譯器生成的橋方法  
    Code:  
       0: aload_0  
       1: aload_1  
       2: checkcast     #26                 // class java/util/Date  
       5: invokevirtual #30                 // Method setValue:(Ljava/util/Date; 去調用我們重寫的setValue方法)V  
       8: return
}

從編譯的結果來看,本意重寫setValue和getValue方法的子類,但是反編譯后竟然有4個方法,其實最后的兩個方法,就是編譯器自己生成的橋方法。可以看到橋方法的參數類型都是Object,也就是說,子類中真正覆蓋父類兩個方法的就是這兩個我們看不到的橋方法。而在setvalue和getValue方法上面的@Oveerride只不過是假象。而橋方法的內部實現,就只是去調用自己重寫的那兩個方法。

所以,虛擬機巧妙的使用了橋方法,來解決了類型擦除和多態的沖突。

并且,還有一點也許會有疑問,子類中的橋方法Object getValue()和Date getValue()是同時存在的,可是如果是常規的兩個方法,他們的方法簽名是一樣的,如果是我們自己編寫Java代碼,這樣的代碼是無法通過編譯器的檢查的(返回值不同不能作為重載的條件),但是虛擬機卻是允許這樣做的,因為虛擬機通過參數類型和返回類型來確定一個方法,所以編譯器為了實現泛型的多態允許自己做這個看起來“不合法”的事情,然后交給虛擬機去區別

責任編輯:武曉燕 來源: sevenCoding
相關推薦

2022-03-02 14:41:03

泛型反序列化

2024-06-07 10:05:31

2021-08-24 08:05:41

泛型類型擦除Class

2024-01-15 08:28:31

Spring事件

2019-09-04 00:20:10

JSON泛型擦除

2023-03-06 08:33:24

IDEA反編譯類型

2020-12-21 16:18:07

JavaTypeToken泛型擦除

2025-01-13 07:00:00

Java泛型編程

2021-07-29 09:20:18

Java泛型String

2021-07-01 06:47:30

Java泛型泛型擦除

2022-03-31 09:01:10

Swift類型擦除類型安全性

2021-06-29 09:01:50

Swift閉包語言

2024-09-11 16:56:39

2023-05-30 18:13:59

Git代碼

2018-06-27 09:51:17

2021-06-24 09:08:34

Java代碼泛型

2023-10-11 12:35:29

Maven

2023-11-29 08:19:45

Go泛型缺陷

2022-05-09 14:09:23

多線程線程安全

2016-10-31 20:56:57

Javascript閉包內存泄漏
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区精品视频 | 国产精品网页 | 99久久99久久精品国产片果冰 | 日韩毛片在线视频 | 午夜视频一区二区三区 | 久久成人亚洲 | 天天看夜夜 | 午夜视频一区二区三区 | 欧美一区二区激情三区 | 国产精品欧美一区喷水 | 日本三级线观看 视频 | 日本啊v在线 | 一级网站| 亚洲一区综合 | 亚洲激情一区二区 | 激情三区 | 秋霞电影一区二区三区 | 麻豆久久久久 | 第四色播日韩第一页 | 偷拍自拍网站 | 久久在线精品 | 人人艹人人 | 黄网站在线播放 | 日本小电影在线 | 精品亚洲一区二区三区 | 蜜桃视频在线观看免费视频网站www | 成人在线视频观看 | 九久久| 中文字幕乱码亚洲精品一区 | 国产精品永久免费视频 | 插插插干干干 | 九九热在线精品视频 | 成人在线视频一区 | 国产精品三级久久久久久电影 | 欧美一区二区成人 | 亚洲a视 | 一级黄色播放 | 国产精品视频偷伦精品视频 | 祝你幸福电影在线观看 | 一级毛片视频 | 福利久久|