冗余通用参数

时间:2012-03-13 12:47:17

标签: java generics

我有两个接口和类:

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>"
}

6 个答案:

答案 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>> {

通过这个我们可以做你想做的事。