乍一看,cookiemonster.eat需要返回一个负长度的String。仔细看,有两个单独的要求:第一次调用eat时,它需要返回一个空String;第二次,它需要返回一个负值length()。
诀窍是,泛型方法的返回类型可能会有所不同,具体取决于使用它的类型上下文。为了证明这一点,让我们来看一个示例java.util.Collections: <T> List <T> emptyList() 。在方法签名中,<t>表示方法上有类型变量t,list<t>是返回类型。您可以将其用作List<String> strings = Collections.emptyList();。这是因为类型推断确保返回类型(list<t>)中的t调整为它被分配给的变量类型(list<string>)。如果没有上下文(未分配任何内容),则推断的类型将是 Object(T的隐式上界)。在Collections.emptyList().size()中,例如emptyList()返回一个List<Object>。
回到我们的CookieMonster,我们可以让eat返回上下文期望它返回的任何内容:static<c>ceat(string cookie)。就像一块神奇的饼干。如果你认为是“巧克力”并把它放进嘴里,那它就是巧克力饼干。在count中,它被分配给一个String,它会变成一个Stringcookie(我不想知道那是什么味道)。这是一个开始,但是在cookiemonster.eat(nocookie).length()中,没有上下文,所以它变成了没有length()方法的Object ,并且无法编译。
我们通过在C上设置一个bound来修复这个问题。要编译两个eat调用,bound必须是String的超类,并且有一个length()方法。有一种类型:charsequence。因此,我们将类型变量<c>替换为<c extends charsequence>。在第一次调用中,eat(“cookie”)必须返回空值String,在第二次调用中,eat(“”)必须返回长度为负的charsequence:
<b>package</b> monster; <b>public</b> <b>class</b> CookieMonster { <b>public</b> <b>static</b> <C <b>extends</b> CharSequence> C eat(String cookie) { <b>return</b> (C) (cookie.length() > 0 ? <font>""</font><font> : <b>new</b> CharSequence() { <b>public</b> <b>int</b> length() { <b>return</b> -1; } <b>public</b> <b>char</b> <b>char</b>At(<b>int</b> index) { <b>throw</b> <b>new</b> UnsupportedOperationException(); } <b>public</b> CharSequence subSequence(<b>int</b> start, <b>int</b> end) { <b>throw</b> <b>new</b> UnsupportedOperationException(); } }); } } </font>