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是用返回值+方法名+參數的方式來計算函數簽名的,所以編譯器就可以借助這一原則來生成一個橋方法。不過這種計算函數簽名的方法僅僅存在於虛擬機中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM