簡體   English   中英

Java:泛型繼承混淆

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM