11
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 的子类。保存方法是唯一带有 . 所有其他人都只使用 T。我可以将其转换为 S 以使其编译,但这看起来也很丑陋……因为除 T 之外的任何其他类型都会导致异常。

4

5 回答 5

12

对于一种方法来覆盖另一种方法,它必须至少应用于被覆盖方法的所有有效参数。您的基本方法是通用的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);
}

编辑:

如果您无法控制基类(您似乎没有),那么您将被public <S extends MyType> List<S> save(Iterable<S> structures)签名卡住。这是因为被覆盖的方法是泛型的,所以覆盖的方法也必须是

于 2012-10-24T12:56:00.960 回答
3

取决于您如何定义,以下工作

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);
    }
}
于 2012-10-24T13:05:23.150 回答
2

这是一个编译的例子,它展示了如何使用它:

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实现它并选择List<Integer>类型参数T。最后,classC使用这个方法,Iterable泛型类型是List<Integer>.

于 2012-10-24T13:03:25.763 回答
1

自从

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>,因此您的编译器错误消息。
于 2012-10-24T13:00:55.853 回答
0

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

于 2012-12-10T09:28:43.063 回答