![](/img/trans.png)
[英]Java Inheritance - Base class methods being overriding by derived class when using base variable for derived object
[英]Calling base and derived static methods of a type variable
我有以下示例:
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
A<ConcreteErrorHandler> a = new A<ConcreteErrorHandler>();
a.m(); //Exception here!
}
public static class AbstractErrorHandler {
public static void handle(){
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler{
public static void handle(){
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler>{
public void m(){
T.handle();
}
}
}
為什么調用基類的方法,而不是派生的方法? handle()
方法的簽名完全相同。 我知道靜態方法不會繼承,但是在我的情況下不應該拋出編譯時錯誤嗎?
有人可以解釋這種行為嗎?
原因是編譯器不知道 AbstractErrorHandler
哪個確切子類型將在運行時替換T
這就是為什么它只是將方法調用T.handle()
綁定到AbstractErrorHandler.handle()
方法。
這里的問題是你將繼承與Java中的類的static
特性混合在一起。
為了使其工作(正確),您必須擺脫.handle()
方法的static
修飾符,並在A
類中保留T
的實例。 這個T
實例(在運行時)將是AbstractErrorHandler
一些特定子類,然后將執行實際的 .handle()
方法。
例如:
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
A<ConcreteErrorHandler> a = new A<ConcreteErrorHandler>(new ConcreteErrorHandler());
a.m();
}
public static class AbstractErrorHandler {
public void handle() {
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler {
public void handle() {
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler> {
T instance;
A(T instance) {
this.instance = instance;
}
public void m() {
instance.handle();
}
}
}
有界類型參數的擦除是綁定(在綁定交集的情況下,綁定中的第一個類型)。 所以在你的情況下, T extends AbstractErrorHandler
被擦除為AbstractErrorHandler
,你的方法被有效地替換為:
public void m() { AbstractErrorHandler.handle(); }
參見例如JLS 4.6
類型變量(第4.4節)的擦除是其最左邊界的擦除。
因為基本上你的方法m
將編譯成
public void m(){
AbstractErrorHandler.handle();
}
我相信這是因為static
是類作用域的,你告訴編譯器使用T extends AbstractErrorHandler
隱式使用T extends AbstractErrorHandler
。
由於類型擦除在運行時發生,因此運行時將采用最高級別級別。
m
的實現只使用T
這是一個AbstractErrorHandler,盡管事實上你聲明它是main方法中的具體類型,這不在m
方法的范圍內。
Java編譯器擦除通用代碼中的所有類型參數,您無法驗證在運行時使用泛型類型的參數化類型。 因此使用上限類型AbstractErrorHandler
。
有關詳細信息,請參閱: https : //docs.oracle.com/javase/tutorial/java/generics/restrictions.html
原因是因為您使用的是隱藏不覆蓋的泛型和java靜態方法 。 在編譯時,唯一知道的信息是AbstractErrorHandler
類(泛型在java中編譯時工作,沒有帶有泛型信息的字節碼),並且調用的方法是類之一。 如果將方法句柄形式static更改為“instance”,則調用的實現是“正確的”(因為該方法被覆蓋而不是隱藏),如下例所示。
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
A<AbstractErrorHandler> a = new A<AbstractErrorHandler>();
a.m(new ConcreteErrorHandler()); //Exception here!
}
public static class AbstractErrorHandler {
public void handle(){
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler{
public void handle(){
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler>{
public void m(T t){
t.handle();
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.