[英]Java: generics inheritance confusion
想象一下,我們有以下課程:
public interface MyInterface<T> {
List<T> getList(T t);
}
abstract class BaseClass<T extends Number> implements MyInterface<T> {
@Override
public List<T> getList(Number t) {
return null;
}
}
class ChildClass extends BaseClass<Integer> {
@Override
public List<Integer> getList(Integer t) {
return super.getList(t); //this doesn't compile
}
}
ChildClass
中的getList
不編譯,輸出為:
abstract method getList(T) in com.mypackage.MyInterface cannot be accessed directly
我無法BaseClass.getList
為什么在ChildClass中沒有覆蓋BaseClass.getList
方法。
但令我完全困惑的是使其編譯的修復:
class ChildClass extends BaseClass<Integer> {
@Override
public List<Integer> getList(Integer t) {
return super.getList((Number) t); //Now it compiles!
}
}
所以我將Integer轉換為Number,並解決了這個問題。
誰能解釋一下這段代碼中發生了什么?
您的基類應如下所示:
abstract class BaseClass<T extends Number> implements MyInterface<T> {
@Override
public List<T> getList(T t) {
return null;
}
}
您沒有使用T,而是使用Number類作為參數。
它不會覆蓋,因為抽象方法將Number作為參數,具體方法采用Integer。 它們必須相同才能覆蓋。
您應該更改抽象類實現以將類型T作為參數。
為什么不將超類方法定義為
public List<T> getList(T t)
?
想象中的課程發生了什么。
abstract class BaseClass<T extends Number> implements MyInterface<T> {
@Override
public List<T> getList(Number t) {
return null;
}
}
該類有一個通用參數(T),它必須擴展Number類並實現接口MyInterface
您還嘗試覆蓋不存在的方法,因為此類不會擴展其他任何類。 當一個類正在實現一個接口時,不需要覆蓋接口方法,因為它只是描述。
如果我們刪除@override注釋會發生什么。
abstract class BaseClass<T extends Number> implements MyInterface<T> {
public List<T> getList(Number t) {
return null;
}
}
在這種情況下,我們不從接口實現該方法但是創建一個新方法,這個方法參數是與T相同類型的Number,它可能會導致一些錯誤,該類有兩個相同的方法。 (未經編譯器測試)
這個方法的實現應該是這樣的
abstract class BaseClass<T extends Number> implements MyInterface<T> {
public List<T> getList(T t) { //Because T is allready restricted to be Number
return null;
}
}
當您指定類型時覆蓋它時調用此方法沒有問題
class ChildClass extends BaseClass<Integer> {
@Override
public List<Integer> getList(Integer t) {
return super.getList(t);
}
}
事先你不必為了返回null而實現它,然后在某個子類中覆蓋它。 你能做的就是像這樣創建類
abstract class BaseClass<T extends Number> implements MyInterface<T> {
private List<T> list = new ArrayList<T>(); //The way of initialization is up to You
public List<T> getList() { //Because T is allready restricted to be Number
return list;
}
}
正如其他同事所指出的那樣,問題的原因是父方法的簽名不正確。 鑄造工作的原因在於編譯器如何處理泛型。 它保證如果您使用泛型,則不會出現運行時ClassCastException問題,但僅當您不進行強制轉換時。 一旦你這樣做,你實際上說編譯器會關閉,因為你更清楚你的類型是什么。 但是在此之后你可能會在運行時得到ClassCastException(在這種情況下我不假設)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.