Java中的類型擦除與橋方法

類型擦除

Java在語法中雖然存在泛型的概念,但是在虛擬機中卻沒有泛型的概念,虛擬機中所有的類型都是普通類。無論何時定義一個泛型類型,編譯後類型會被都被自動轉換成一個相應的原始類型。

比如這個類

public class Parent<T>
{
	public void sayHello(T value)
	{
		System.out.println("This is Parent Class, value is " + value);
	}
}

在編譯後就變成了

public class Parent
{
	public void sayHello(Object value)
	{
		System.out.println("This is Parent Class, value is " + value);
	}
}

對類型變量進行替換的規則有兩條:

  • 若爲無限定的類型,如<T>,被替換爲Object
  • 若爲限定類型,如<T extends Comparable & Serializable>,則用第一個限定的類型變量來替換,在這裏被替換爲Comparable

橋方法

類型擦除後,就產生了一個奇怪的現象。

假設有一個超類:

public class Parent<T>
{
	public void sayHello(T value)
	{
		System.out.println("This is Parent Class, value is " + value);
	}
}

以及一個子類:

public class Child extends Parent<String>
{
	public void sayHello(String value)
	{
		System.out.println("This is Child class, value is " + value);
	}
}

最後有以下測試代碼,企圖實現多態:

public class MainApp
{
	public static void main(String[] args)
	{
		Child child = new Child();
		Parent<String> parent = child;

		parent.sayHello("This is a string");
	}
}

運行的時候,會對Child類的方法表進行搜索,先分析一下Child類的方法表裏有哪些東西:

1. sayHello(Object value) : 從類型被擦除後的超類中繼承過來
2. sayHello(String value) : 自己新增的方法,和超類毫無聯繫
3. 一些從Object類繼承來的方法,這裏忽略

按理來說,這段測試代碼應該不能通過編譯,因爲要實現多態的話,所調用的方法必須在子類中重寫,但是在這裏Child類並沒有重寫Parent類中的sayHello(Object value)方法,只是單純的繼承而已,並且新加了一個參數不同的同名方法。

但是結果是可以正常運行。

原因是編譯器在Child類中自動生成了一個橋方法

public void sayHello(Object value)
{
	sayHello((String) value);
}

可以看出,這個橋方法實際上就是對超類中sayHello(Obejct)的重寫。這樣做的原因是,當程序員在子類中寫下以下這段代碼的時候,本意是對超類中的同名方法進行重寫,但因爲超類發生了類型擦除,所以實際上並沒有重寫成功,因此加入了橋方法的機制來避免類型擦除與多態發生衝突。

public class Child extends Parent<String>
{
	public void sayHello(String value)
	{
		System.out.println("This is Child class, value is " + value);
	}
}

橋方法並不需要自己手動生成,一切都是編譯器自動完成的。

橋方法與Geter

同樣的,如果超類中有getter的話,在使用多態的時候也可能發生衝突。假設有超類被類型擦除後存在這樣一個方法:

Obejct getValue()

然後在子類中,程序員想要重寫這個方法,因此新增了一個這樣的方法:

String getValue()

但是正如前面所述,重寫並沒有起作用,甚至還應該報錯,因爲在子類中,根據 函數簽名=方法名+參數 的原則,從超類繼承的方法與新增的方法衝突了。

但實際上這樣的代碼是可以工作的,原因在於,JVM是用返回值+方法名+參數的方式來計算函數簽名的,所以編譯器就可以藉助這一原則來生成一個橋方法。不過這種計算函數簽名的方法僅僅存在於虛擬機中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章