我们假设我们要描述Category
Description
和Items
列表。每个Item
也有一个Category
:
public interface Description
{
}
这个界面非常简单。用通用边界描述Category
变得更加复杂,但它不是火箭工程。
interface Category<D extends Description,
C extends Category<D,C,I>,
I extends Item<D,C,I>>
{
public List<I> getItems();
public void setItems(List<I> items);
public D getDescription();
public void setDescription(D description);
}
interface Item<D extends Description,
C extends Category<D,C,I>,
I extends Item<D,C,I>>
{
public C getCategory();
public void setCategory(C category);
}
现在我想定义一个接口来对一个对象进行类转换
(SecretDescription
是Description
)的实现:
SecretDescription sd = new SecretDescription();
Description d = (SecretDescription)sd;
这当然有效,但现在问题是:
如何在没有警告的情况下使用Category
?
Category c;
这给了我警告:
Category is a raw type. References to generic type Category<D,C,I>
should be parameterized
好的,但我怎样才能参数化呢?
Category<Description,Category,Item> c;
这给了我编译错误:
Bound mismatch: The type Category is not a valid substitute for the
bounded parameter <C extends Category<D,C,I>> of the type Category<D,C,I>
答案 0 :(得分:2)
SecretDescription sd = new SecretDescription();
Description d = (SecretDescription)sd;
请不要在第二行进行不必要的演员表。
Category<Description,Category,Item> c;
C
参数有一个约束:它必须至少为Category< D, C, I >
。原始类型Category
不符合该约束,因此就是消息。
当你使用这样的自有边界类型时,你必须创建至少一个在泛型参数中引用自身的子类或子接口,以终止看似无限的回归。
interface ExampleCategory extends Category< Description, ExampleCategory, ExampleItem >{}
interface ExampleItem extends Item< Description, ExampleCategory, ExampleItem > {}
请注意,一旦将参数设置为某个值,擦除意味着您无法将其重置为层次结构中更深层次的其他内容:
// causes a compile error
interface BetterExampleCategory
extends ExampleCategory, Category< Description, BetterExampleCategory, ExampleItem > {}
即使我在@ rgettman的回答中发表评论,你最好还是保留这些参数,直到你有一个具体的类,如
interface ExampleCategory< C extends ExampleCategory< C, I >, I extends ExampleItem< C, I > > extends Category< Description, C, I > {}
interface BetterExampleCategory< C extends BetterExampleCategory< C, I >, I extends ExampleItem< C, I > > extends ExampleCategory< C, I > {}
这会导致一些非常棘手的代码。 (如果你需要它来保证类型安全,那就去做吧。有时Java没有更好的答案。)
答案 1 :(得分:0)
您不能直接将接口Category
和Item
称为Category
的类型参数,因为类型参数本身需要参数化,这会导致无限的泛型规范:
Category<Description, Category<Description, Category<Description, ...
您需要在类定义中指定接口类型参数的类型。
class SecretCategory
implements Category<SecretDescription, SecretCategory, SecretItem>
{ ... }
和
class SecretItem
implements Item<SecretDescription, SecretCategory, SecretItem>
{ ... }
然后至少你可以说
Category<SecretDescription, SecretCategory, SecretItem> c =
new SecretCategory();
甚至
Category<? extends Description, ? extends Category, ? extends Item> c2 =
new SecretCategory();
答案 2 :(得分:0)
你为什么要使用泛型?看起来好像你想要完成的一切都可以使用普通的旧对象作为成员变量并利用继承:
public interface Description
{
}
interface Category
{
public List<? extends Item> getItems();
public void setItems(List<? extends Item> items);
public Description getDescription();
public void setDescription(Description description);
}
interface Item
{
public Category getCategory();
public void setCategory(Category category);
}
SecretDescription
仍然可以设置为Category
的说明,因为它扩展了Description