我有两个接口和类:
public interface Identifiable<T> {
T getId();
}
public interface GenericRepository<T extends Identifiable<K>, K> {
T get(K id);
}
public class MyEntity implements Identifiable<Long> {
private Long id;
public Long getId() {
return id;
}
}
public class MyService {
private GenericRepository<MyEntity, Long> myEntityRepository;
}
一切都按预期工作。但在我看来,GenericRepository(K)中的第二个泛型参数是多余的。因为我知道MyEntity是一个可识别的,我认为如果我最终能像这样使用它会很棒:
public class MyService {
private GenericRepository<MyEntity> myEntityRepository;
}
但我没有成功就尝试了不同的事情。可能吗?如果没有,为什么不呢?
更新:回答一些回复。我认为编译器知道MyEntity中哪种类型是通用的。例如:
public class MyEntityGenericRepository implements GenericRepository<MyEntity, Long> {
// compiles...
}
public class MyEntityGenericRepository implements GenericRepository<MyEntity, String> {
// compiler says: "Bound mismatch: The type MyEntity is not a valid substitute for the bounded parameter <T extends Identifiable<K>> of the type GenericRepository<T,K>"
}
答案 0 :(得分:7)
我认为你不能省略它。使用T extends Identifiable<K>
时,您要说泛型类型参数必须是Identifiable
。由于Identifiable
是一个泛型类,因此您也需要提及它的泛型类型参数(如果您想按照规则进行播放 - 如果省略它,则会失去GenericRepository
的所有泛型类型安全性,由于向后兼容规则)。另请注意,K
实际上用作GenericRepository.get
的参数类型。由于该类型可能与T
不同,因此您需要通过将其声明为GenericRepository
的另一个泛型类型参数来满足编译器。否则,编译器无法知道K
是什么。
答案 1 :(得分:3)
从GenericRepository类的角度来看,这并不是多余的。当它有像T get(K id)
这样的方法时,它无法知道它可以接受哪种类型的id
参数。您可以写下以下内容:
interface GenericRepository<T extends Identifiable<?>> {
T get(Object id);
}
现在您不必将Long
写为类型参数,但是您无法检查在编译时是否正确使用get
方法。因此类型变量有特定用途。
至于字段声明,当你有泛型类型时,你必须指定它使用的所有类型变量。当然,如果语言能够理解其中一个参数值可以从另一个参数值中推断出来,那么你可以说它会很整洁,但这是值得商榷的。
答案 2 :(得分:1)
除了引入只改进GenericRepository
的接口之外,你无能为力 public interface LongKeyedRepository<T extends Identifiable<Long>>
extends GenericRepository<T, Long> { {
//No new methods need to be defined
}
然后你可以
private LongKeyedRepository<MyEntity> myEntityRepository;
等
答案 3 :(得分:0)
如果我没有弄错,仿制品将被编译为好像只是Object
。现在语法被(硬)检查以确保你没有使用带有橙子的苹果,因为在Java的初始设计之后添加了泛型。这就是为什么泛型如此受限制......
答案 4 :(得分:0)
它适用于(即编译)
public interface GenericRepository<T extends Identifiable> {
T get(T id);
}
但它仍然说可识别是一种原始类型,它应该是参数化的。
希望它有所帮助。
答案 5 :(得分:-1)
为什么你不能删除第二个K,
public interface GenericRepository<T extends Identifiable<K>, K> {
因此,我们可以将其作为
而不是如上所述public interface GenericRepository<T extends Identifiable<K>> {
通过这个我们可以做你想做的事。