Java:如何覆盖这种通用方法?

beg*_*er_ 10 java generics overriding type-erasure

public <S extends T> List<S> save(Iterable<S> entities) {
        //...
}
Run Code Online (Sandbox Code Playgroud)

如果我使用以下方法来覆盖

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

我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

我怎么解决这个问题?我不需要该方法是通用的,事实上它不应该是.我的意思是

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

无法工作,因为该方法可以创建一个新的MyType对象,它与List不兼容.

我怎样才能做到这一点?

编辑:

为了澄清.我正在尝试覆盖Spring数据SimpleJpaRepository的不同save()方法(由QuerydslJpaRepository扩展)

课程定义:

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

@NoRepositoryBean
public interface MyTypeRepository
    extends JpaRepository<MyType, Long>,
    QueryDslPredicateExecutor<MyType> 
Run Code Online (Sandbox Code Playgroud)

而这(来自Spring Data)

public class QueryDslJpaRepository<T, ID extends Serializable> 
extends SimpleJpaRepository<T, ID> 
implements QueryDslPredicateExecutor<T>
Run Code Online (Sandbox Code Playgroud)

编辑2:

该方法为每个元素调用save(MyType实体),该方法包含以下逻辑:

  1. entity有一个独特的字段
  2. 获取该字段值并检查具有该值的实体是否已存在
  3. 如果是,使用该实体(调用entityManager.merge) - >不起作用返回MyType而不是S.
  4. 如果没有创建新的 - >这里创建了新对象.不适用于泛型类型

对于4.我可以设置id = null并使用传入的对象.这不适用于3.

所以我很困惑为什么这个方法有这个签名.它使我无法使用它,我不知道为什么我会使用Ts DAO保存T的子类.保存方法是唯一的.所有其他人只使用T.我可以直接转换为S使其编译,但这看起来也很难看......因为除了T之外的任何其他类型都会导致异常.

Joh*_*n B 10

对于覆盖另一个方法的一种方法,它必须至少应用于重写方法的所有有效参数.您的基本方法是通用的public <S extends T> List<S> save(Iterable<S> entities).所以它会接受任何S扩展的类型T.但是,您的覆盖更具限制性,因为它只接受集合MyType,因此它不是有效的覆盖.

如果您已经定义了基类T,并且只接受了方法T,并且派生类被锁定TMyType您应该没问题.

为了给出更好的答案,我们需要查看两个类的类声明.我建议如下:

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

class OtherClass extends MyClass<MyType>{
  public List<MyType> save(Iterable<MyType> entities);
}
Run Code Online (Sandbox Code Playgroud)

编辑:

如果您无法控制基类(您似乎没有),那么您将无法使用public <S extends MyType> List<S> save(Iterable<S> structures)签名.这是因为重写的方法是通用的,因此重写方法也必须如此


beg*_*er_ 0

我的解决方案是根本不覆盖它,而是创建一个服务类来执行所需的逻辑并保持存储库不变。

  • 无意冒犯,但这不是您在问题中所述问题的解决方案,因此也不是“最佳”答案。你最终所做的是解决问题 (2认同)