簡體   English   中英

Java泛型名稱沖突,具有相同的擦除

[英]Java generics name clash , has the same erasure

我有超級Foo。 還有一個擴展它的類Bar。

public class Bar extends Foo

Foo中的功能:

protected void saveAll(Collection<?> many)

欄中的功能:

public void saveAll(Collection<MyClass> stuff) {
   super.saveAll(stuff);
}

得到錯誤:

 Name clash: The method saveAll(Collection<MyClass>) of type Bar has the same erasure as saveAll(Collection<?>) of type Foo but does not override it.

我究竟做錯了什么?

您使用不兼容的類型覆蓋saveAll方法。 也許你想做的事情如下:

public class Bar extends Foo<MyClass>

函數在Foo<E>

protected void saveAll(Collection<E> many)

和Bar中的功能:

public void saveAll(Collection<MyClass> stuff) {
   super.saveAll(stuff);
}

由於Java的類型擦除功能,JVM將無法知道它是具有參數化類型MyClass還是應該調用的第一個類型的方法。

如果可能或適用,我見過避免這種情況的最常用模式是將類Foo更改為具有參數化類型:

public class Foo<T> {
    protected void saveAll(Collection<T> many) {}
}

然后讓Bar簡單地為您的特定類型實現Foo

public class Bar extends Foo<MyClass> {
    public void saveAll(Collection<MyClass> many) {
        super.saveAll(many);
    }
}

在運行時,參數類型將替換為Object 因此saveAll(Collection<?>)saveAll(Collection<MyClass>)被轉換為saveAll(Collection) 這是一個名字沖突。 在這里查看詳細信息。

你可以這樣做:

public class Foo<T> {
    protected void saveAll(Collection many) {
        // do stuff
    }
}

public class Bar extends Foo<MyClass> {
}

當編譯器編譯為字節代碼時,會發生一個名為Erasure的進程。 這將從集合中刪除類型信息。 我相信它將手動執行轉換等作為生成字節代碼的過程的一部分。 如果刪除類的通用部分(即<..>),則會看到有兩個saveAll方法。 錯誤是你有兩個保存所有方法將相同的簽名。 集合在字節代碼中具有類型對象。

嘗試刪除<..>,這可能會更清楚。 當你把<...>放回去時,請考慮方法的名稱。 如果它們不同則應編譯。

此外,我不認為這是一個休眠問題,所以應刪除此標記。 這是一個java泛型問題。

你在這里可以做的是鍵入類

public class Bar extends Foo<MyClass>

然后將方法類型賦予T

public void saveAll(Collection<MyClass> stuff) {
   super.saveAll(stuff);
}

然后Foo的聲明會是這樣的

public abstract class Bar extends Foo<T> {
    public void saveAll(Collection<T> stuff) {
}

您只需使用不同的簽名覆蓋方法。

什么是好主意是使用Joshua Bloch在Effective Java Second Edition中描述的PECS(生產者 - 擴展,消費者 - 超級)規則。

根據這條規則它應該是這樣的。

在Foo類中:

public class Foo<E>{

protected void saveAll(Collection<? super E> many){....}

protected void getAll(Collection<? extends E> many){....}

}

雖然現有答案是正確的,但是當您聲明實際類型不在“ extends ...”子句中但在實際類名中時,很容易發生此錯誤:

錯誤:

public class Bar<MyClass> extends Foo
{
    ...
}

正確:

public class Bar extends Foo<MyClass>
{
    ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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