Java:如何覆盖这个通用方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13049420/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java:How to override this generic method?
提问by beginner_
public <S extends T> List<S> save(Iterable<S> entities) {
//...
}
If I use following method to override
如果我使用以下方法来覆盖
@Override
public List<MyType> save(Iterable<MyType> structures) {
List<MyType> result = new ArrayList<>();
//...
return result;
}
I get following error:
我收到以下错误:
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
How can I solve this? I don't need the method to be generic and in fact it should not be. What I mean is that
我该如何解决这个问题?我不需要该方法是通用的,事实上它不应该是通用的。我的意思是
@Override
public <S extends MyType> List<S> save(Iterable<S> structures) {
List<S> result = new ArrayList<>();
//...
return result;
}
Will not work as the method can create a new Object of MyType which is not "compatible" to List.
将不起作用,因为该方法可以创建与 List 不“兼容”的 MyType 的新对象。
How can I make this work?
我怎样才能使这项工作?
EDIT:
编辑:
For clarification. I'm trying to override the different save() methods of Spring data SimpleJpaRepository (which is extented by QuerydslJpaRepository)
为了澄清。我正在尝试覆盖 Spring 数据 SimpleJpaRepository 的不同 save() 方法(由 QuerydslJpaRepository 扩展)
Class defintions:
类定义:
public class MyTypeRepositoryImpl
extends QueryDslJpaRepository<MyType, Long>
implements MyTypeRepository
@NoRepositoryBean
public interface MyTypeRepository
extends JpaRepository<MyType, Long>,
QueryDslPredicateExecutor<MyType>
And this (from Spring Data)
这(来自 Spring Data)
public class QueryDslJpaRepository<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID>
implements QueryDslPredicateExecutor<T>
EDIT 2:
编辑2:
The method calls save(MyType entity) for each element and that method contains following logic:
该方法为每个元素调用 save(MyType entity) ,该方法包含以下逻辑:
- entity has a field which is unique
- get that fields value and check if entity with that value already exists
- if yes, use that entity (call to entityManager.merge) -> does not work returns MyType not S
- if no create a new one -> here new object is created. Does not work with generic type
- 实体有一个唯一的字段
- 获取该字段值并检查具有该值的实体是否已存在
- 如果是,请使用该实体(调用 entityManager.merge)-> 不起作用返回 MyType 而不是 S
- 如果没有创建一个新的 -> 这里创建了新的对象。不适用于泛型类型
For 4. I can just set id = null and use the passed in object. That does not work for 3.
对于 4. 我可以设置 id = null 并使用传入的对象。这对 3 不起作用。
So I'm very puzzled why this method has this signature. It makes it unusable for me and i don't get why I would save a subclass of T using Ts DAO. the save methods are the only ones with . All others just use T. I could just cast to S to make it compile but that seems ugly too...as any other type than T would lead to an exception.
所以我很疑惑为什么这个方法有这个签名。它使我无法使用它,我不明白为什么要使用 Ts DAO 保存 T 的子类。save 方法是唯一带有 . 所有其他人都只使用 T。我可以将其强制转换为 S 以使其编译,但这看起来也很丑陋……因为除 T 之外的任何其他类型都会导致异常。
采纳答案by beginner_
My solution was to not override this at all but to create a service class that does the needed logic and leave repository untouched.
我的解决方案是根本不覆盖它,而是创建一个服务类来执行所需的逻辑并保持存储库不变。
回答by John B
For one method to override another it must apply to at least all valid parameters of the overridden method. Your base method is generic public <S extends T> List<S> save(Iterable<S> entities)
. So it will accept any type S
that extends T
. However your override is more restrictive because it will only accept collections of MyType
, therefore it is not a valid override.
一个方法要覆盖另一个方法,它必须至少适用于被覆盖方法的所有有效参数。您的基本方法是通用的public <S extends T> List<S> save(Iterable<S> entities)
。所以它会接受任何S
扩展的类型T
。但是,您的覆盖更具限制性,因为它只接受 的集合MyType
,因此它不是有效的覆盖。
If you had your base class defined with T
, and the method accepted just T
, and the derived class locked down T
to MyType
you should be OK.
如果你用 定义了你的基类T
,并且方法只接受T
,并且派生类锁定T
给MyType
你应该没问题。
To give a better answer we need to see the class declarations for the two classes. I would suggest the following:
为了给出更好的答案,我们需要查看两个类的类声明。我建议如下:
class MyClass<T>{
public List<T> save(Iterable<T> entities);
}
class OtherClass extends MyClass<MyType>{
public List<MyType> save(Iterable<MyType> entities);
}
EDIT:
编辑:
If you don't have control over the base class (which it seems that you don't), you are stuck with the public <S extends MyType> List<S> save(Iterable<S> structures)
signature. This is because the overridden method is genericized and so the overridding method must also be
如果您无法控制基类(您似乎没有控制权),那么您就会被public <S extends MyType> List<S> save(Iterable<S> structures)
签名所困扰。这是因为覆盖的方法是泛化的,所以覆盖的方法也必须是
回答by Walter Laan
Depends on how you have defined , the following works
取决于您如何定义,以下工作
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);
}
}
回答by Andreas Dolk
Here's an example that compiles and that shows how to use it:
这是一个编译示例并展示了如何使用它:
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);
}
}
Class A
defines the method with the original signature. class B
implements it and chooses List<Integer>
for type parameter T
. And finally, class C
uses this method with an Iterable
whore generic type is a subclass of List<Integer>
.
类A
定义具有原始签名的方法。类B
实现它并选择List<Integer>
类型参数T
。最后, classC
使用此方法与一个Iterable
妓女泛型类型是List<Integer>
.
回答by DaveFar
Since
自从
public <S extends T> List<S> save(Iterable<S> entities)
is given, your override must be for
给出,您的覆盖必须用于
public <S extends MyType> List<S> save(Iterable<S> structures)
and your implementation must respect that S might be a real subtype of MyType.
并且您的实现必须尊重 S 可能是 MyType 的真正子类型。
Your approach
你的方法
public List<MyType> save(Iterable<MyType> structures)
is not a correct override:
不是正确的覆盖:
- since Java >=1.5 allows covariantreturn types and
List<MyType>
is a subtype ofList<S extends MyType>
, this is ok, but - Java only allows invariant parameter types, but
Iterable<MyType>
is a subtype ofIterable<S extends MyType>
, hence your compiler error message.
- 由于 Java >=1.5 允许协变返回类型并且
List<MyType>
是 的子类型List<S extends MyType>
,因此可以,但是 - Java 只允许不变的参数类型,但它
Iterable<MyType>
是 的子类型Iterable<S extends MyType>
,因此您的编译器错误消息。