簡體   English   中英

Java:如何覆蓋這個通用方法?

[英]Java:How to override this generic method?

public <S extends T> List<S> save(Iterable<S> entities) {
        //...
}

如果我使用以下方法來覆蓋

@Override
public List<MyType> save(Iterable<MyType> structures) {
    List<MyType> result = new ArrayList<>();
    //...
    return result;
}

我收到以下錯誤:

method does not override or implement a method from a supertype

name clash: save(Iterable<MyType>) in MyTypeRepositoryImpl and <S>save(Iterable<S>) in SimpleJpaRepository have the same erasure, yet neither overrides the other
  where S,T are type-variables:
    S extends T declared in method <S>save(Iterable<S>)
    T extends Object declared in class SimpleJpaRepository

我該如何解決這個問題? 我不需要該方法是通用的,事實上它不應該是通用的。 我的意思是

@Override
public <S extends MyType> List<S> save(Iterable<S> structures) {
    List<S> result = new ArrayList<>();
    //...
    return result;
}

將不起作用,因為該方法可以創建與 List 不“兼容”的 MyType 的新對象。

我怎樣才能使這項工作?

編輯:

為了澄清。 我正在嘗試覆蓋 Spring 數據 SimpleJpaRepository 的不同 save() 方法(由 QuerydslJpaRepository 擴展)

類定義:

public class MyTypeRepositoryImpl
    extends QueryDslJpaRepository<MyType, Long>
    implements MyTypeRepository

@NoRepositoryBean
public interface MyTypeRepository
    extends JpaRepository<MyType, Long>,
    QueryDslPredicateExecutor<MyType> 

這(來自 Spring Data)

public class QueryDslJpaRepository<T, ID extends Serializable> 
extends SimpleJpaRepository<T, ID> 
implements QueryDslPredicateExecutor<T>

編輯2:

該方法為每個元素調用 save(MyType entity) ,該方法包含以下邏輯:

  1. 實體有一個唯一的字段
  2. 獲取該字段值並檢查具有該值的實體是否已存在
  3. 如果是,則使用該實體(調用 entityManager.merge)-> 不起作用返回 MyType 而不是 S
  4. 如果沒有創建一個新的 -> 這里創建了新的對象。 不適用於泛型類型

對於 4. 我可以設置 id = null 並使用傳入的對象。 這對 3 不起作用。

所以我很疑惑為什么這個方法有這個簽名。 它使我無法使用它,我不明白為什么要使用 Ts DAO 保存 T 的子類。 save 方法是唯一帶有 . 所有其他人都只使用 T。我可以將其強制轉換為 S 以使其編譯,但這看起來也很丑陋……因為除 T 之外的任何其他類型都會導致異常。

一個方法要覆蓋另一個方法,它必須至少應用於被覆蓋方法的所有有效參數。 您的基本方法是通用public <S extends T> List<S> save(Iterable<S> entities) 所以它將接受任何擴展T類型S 但是,您的覆蓋更具限制性,因為它只接受MyType集合,因此它不是有效的覆蓋。

如果您使用T定義了基類,並且該方法僅接受T ,並且派生類將T鎖定為MyType那么您應該沒問題。

為了給出更好的答案,我們需要查看兩個類的類聲明。 我建議如下:

class MyClass<T>{
  public List<T> save(Iterable<T> entities);
}

class OtherClass extends MyClass<MyType>{
  public List<MyType> save(Iterable<MyType> entities);
}

編輯:

如果您無法控制基類(似乎您沒有),那么您將被public <S extends MyType> List<S> save(Iterable<S> structures)簽名卡住。 這是因為覆蓋的方法是泛化的,因此覆蓋的方法也必須是

取決於您如何定義,以下工作

public class TestGenerics2<T> {
    public <S extends T> List<S> save(Iterable<S> entities) {
        return new ArrayList<S>();
    }
}

public class TestGenerics3 extends TestGenerics2<Number> {
    @Override
    public <S extends Number> List<S> save(Iterable<S> entities) {
        return super.save(entities);
    }
}

這是一個編譯示例並展示了如何使用它:

abstract class A<T> {
    abstract public <S extends T> List<S> save(Iterable<S> entities); 
}

class B extends A<List<Integer>> {

    @Override
    public <S extends List<Integer>> List<S> save(Iterable<S> entities) {
        return null;
    }
}

class C {
    public void useIt() {
        B b = new B();
        Iterable<ArrayList<Integer>> it = new ArrayList<ArrayList<Integer>>();
        b.save(it);
    }
}

A定義與原始簽名的方法。 B類實現它並為類型參數T選擇List<Integer> 最后,類C將此方法與Iterable whore 泛型類型一起使用,它是List<Integer>的子類。

自從

public <S extends T> List<S> save(Iterable<S> entities)

給出,您的覆蓋必須用於

public <S extends MyType> List<S> save(Iterable<S> structures)

並且您的實現必須尊重 S 可能是 MyType 的真正子類型。

你的方法

public List<MyType> save(Iterable<MyType> structures)

不是正確的覆蓋:

  • 由於 Java >=1.5 允許協變返回類型,並且List<MyType>List<S extends MyType>的子類型,所以沒問題,但是
  • Java 只允許不變的參數類型,但Iterable<MyType>Iterable<S extends MyType>的子Iterable<S extends MyType> ,因此您的編譯器錯誤消息。

我的解決方案是根本不覆蓋它,而是創建一個執行所需邏輯並保持存儲庫不變的服務類。

暫無
暫無

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

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