2012-03-13 82 views
9

我有这样两个接口和类:冗余泛型参数

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

回答

7

我不认为你可以省略它。用T extends Identifiable<K>你想说的泛型类型参数必须是Identifiable。由于Identifiable是一个泛型类,所以您也需要提及它的泛型类型参数(如果您想按照规则进行操作 - 如果您忽略它,由于向后兼容性规则,您将失去GenericRepository的所有泛型类型安全性)。还请注意K实际上被用作GenericRepository.get的参数类型。由于该类型可能与T不同,因此您需要通过将其声明为另一个通用类型参数GenericRepository来满足编译器的要求。否则,编译器无法知道K是什么。

+0

谢谢,但我不同意。请看我的编辑。 – sinuhepop 2012-03-13 14:43:08

+3

@sinuhepop,编译器当然可以检查'K'的实际类型与'Identifiable '中的类型参数的类型匹配。不过,你需要*声明* K是一个泛型类型参数(因此,在实例化时传递它的实际值)。这就是语言的工作原理。你是对的,这个知识*理论上可以由编译器推断出来,但现在还不是,现在也不是这样,并且多年以前......如果有的话(不幸的是,Java的发展只是向这个方向发展很慢。 ..)。 – 2012-03-13 14:52:02

3

从GenericRepository类的角度来看,它不是多余的。当它有像T get(K id)这样的方法时,它不能知道它可以接受哪种类型的id参数。你可以写:

interface GenericRepository<T extends Identifiable<?>> { 
    T get(Object id); 
} 

现在你不必写Long作为一个类型参数,但你失去了检查的可能性,如果在编译时正确使用的方法get。所以这个类型变量用于特定的目的。

至于字段声明,当你有一个泛型类型时,你必须指定它使用的所有类型变量。当然,如果语言能理解一个参数值可以从另一个参数值推断出来,那么你可以争辩说它会很整洁,但这是值得商榷的。

+0

请看我的版本。看起来编译器可以以某种方式推断该类型。 – sinuhepop 2012-03-13 14:47:27

+0

@sinuhepop,不,它并不推断任何类型,只比较两个具体定义的类型参数的相等性。 (一个简单的例子)类型推断是[this](http://docs.oracle.com/javase/tutorial/java/generics/gentypeinference.html)(用Java 7实现)。 – 2012-03-13 15:08:21

0

如果我没有弄错泛型将全部编译好像它们只是Object。现在,语法被检查(很难),以确保你不会把苹果当成橘子,因为泛型是在Java的最初设计之后添加的。这就是为什么泛型这样的限制...

-1

为什么你不能删除从第二个K,

public interface GenericRepository<T extends Identifiable<K>, K> { 

因此而不是它上面的,我们可以把它作为

public interface GenericRepository<T extends Identifiable<K>> { 

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

+0

是的,但不幸的是编译器说“K不能解析为类型”。 – sinuhepop 2012-03-13 13:00:50

0

它可以使用(即,编译)

public interface GenericRepository<T extends Identifiable> { 
    T get(T id); 
} 

但它说虽然Identifiable是一个原始类型,它应该参数化。

希望它有帮助。

+0

这不完全相同 - 你声明'get'作为'T'类型的参数而不是'K'。可以说,这就是问题的症结所在,如何在构建过程中拥有“K”引用,而无需在构建时声明它,所以回避它有点厚颜无耻。 :) – 2012-03-13 13:06:47

+0

我想说,在构建时不需要声明它就不可能在类中有K引用。唯一可以想到的其他事情是公共接口GenericRepository > T get(T id); } – aretai 2012-03-13 13:09:06

+1

是的,这就是问题:“**是否有可能?如果没有,为什么不?” – 2012-03-13 13:09:43

1

没有什么可以做,除了引进,只是提炼GenericRepository

public interface LongKeyedRepository<T extends Identifiable<Long>> 
     extends GenericRepository<T, Long> { { 
    //No new methods need to be defined 
    } 

然后一个接口,你可以有

private LongKeyedRepository<MyEntity> myEntityRepository; 

+0

谢谢。目前我正在做类似的事情(我简化了我的结构)。但我不喜欢它太多,我不明白为什么需要。 – sinuhepop 2012-03-13 14:46:23