一个泛型类中的嵌套泛型

14

我希望在我的API中提供类似于这样的东西:

class Foobar extends AbstractThing<Double>

class EventThing<Foobar> {    
            public Foobar getSource();
            public Double getValue();
}

所以我写了这个:
class EventThing<T extends AbstractThing<U>> {    
        public T getSource();
        public U getValue();
}

但是Java无法解决U问题。

使用EventThing<T extends AbstractThing<U>,U>可以解决,但第二个U实际上是多余的,因为AbstractThing已经定义了类型。所以我希望摆脱它。

1个回答

33

您不能将其删除。第二个U不是多余的。您希望编译器将第一个U解释为类型参数,但它没有这样做。您也可以这样写:

class EventThing<T extends AbstractThing<Double>>

请注意,这里的Double是一个具体的类,而不是类型参数。与之对比的是下面的示例:
class EventThing<T extends AbstractThing<U>>

请注意,这与上面的第一行代码具有完全相同的形式。编译器应该如何知道在第一种情况下,Double 是一个具体类,而在第二种情况下,U 是一个类型参数?
编译器无法知道这一点,并像第一行中的 Double 一样将 U 视为具体类。让编译器知道 U 是一个类型参数的唯一方法是将其指定为此类参数:
class EventThing<T extends AbstractThing<U>, U>

1
对我来说更像是编译器缺失的功能。编辑: 但我明白你的意思,感谢你的回答。 太糟糕了。我想我会把整个功能都去掉。 - Marcel Jaeschke
4
@Marcel: 我认为这个答案已经很清楚地解释了编译器为什么不能(也不应该)试图猜测U是实际类型还是泛型类型参数。Java 要求每个泛型类型参数都要明确声明,这是有充分理由的。无论你觉得怎样,这并不是编译器的“缺失特性”。 - ColinD
1
@ColinD:我同意Marcel的观点,这似乎是一个缺失的功能,他的例子中U似乎是多余的。显然,编译器必须知道U是一个类型参数,我们可以有类似这样的东西:class EventThing<T extends AbstractThing<%U>>,基本上是说:U是一个变量类型参数,现在去推断它(字符%仅用于讨论目的,我同意它很丑)。这样一来,在调用代码中就不会重复了。 - Gilead
@Gilead:我真的不认为引入一个特殊字符来标记这样的东西有任何价值。无论你选择什么,它都会很丑陋,并且会使语言语法和编译过程变得复杂。而且它只能节省2个字符?你甚至没有考虑U类型可能被限制(“U extends Foo”)并且可能在两个或更多其他类型参数的边界中使用的情况。你和Marcel建议的不仅奇怪而且自相矛盾,而且根本行不通。 - ColinD
2
@ColinD 只是为了明确:我从未建议使用特殊字符。这是Gilead的想法,不是我的!除此之外,我仍然认为我的原始想法是一种缺失的功能。唯一的问题是编译器无法处理它,因为它不希望在此位置有新的类型参数。我不认为它会破坏任何东西或者不一致。就像jre7中的钻石思想一样。该功能并非必需,但至少对于某些人来说似乎很有用。顺便说一句:我仍然更喜欢Lists.newXyzList()而不是new XyzList<>()。 - Marcel Jaeschke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接