首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >"<T扩展Comparable<T>>“和"<T扩展Comparable<Comparable<T>>>”的区别?

"<T扩展Comparable<T>>“和"<T扩展Comparable<Comparable<T>>>”的区别?
EN

Stack Overflow用户
提问于 2011-08-05 07:21:22
回答 5查看 5.1K关注 0票数 2

在签名中的表达式<T extends Comparable<T>>中,例如

代码语言:javascript
复制
public static <T extends Comparable<T>> foo(T x) { ... }

T的描述递归地依赖于Comparable<T>

如果T扩展了Comparable<T>Comparable<T>扩展了Comparable<Comparable<T>>,那么T不就是扩展了Comparable<Comparable<T>>

那么,extends关系是可传递的吗?

如果是这样,为什么不是

代码语言:javascript
复制
public static <T extends Comparable<Comparable<T>>> int compare(T x, T y) {
    return x.compareTo(y);
}

等同于

代码语言:javascript
复制
public static <T extends Comparable<T>> int compare(T x, T y) {
    return x.compareTo(y);
}

?实际上,最后一个定义可以编译,而它上面的定义则无法编译,错误如下

代码语言:javascript
复制
comp.java:7: compareTo(java.lang.Comparable<T>) in 
java.lang.Comparable<java.lang.Comparable<T>> cannot be applied to (T)
            return x.compareTo(y);

谢谢!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-08-05 08:06:44

要记住的基本问题是Java泛型是由编译单元和编译时限定范围的。这只是语法上的糖!(有多少次我忘记了这一点,最后完全按照您所做的方式进行推理,就好像Java泛型实际上暗示了运行时的泛型类型系统一样。)

来自the spec

代码语言:javascript
复制
The scope of a class' type parameter is the entire declaration of the class 
including the type parameter section itself. 

Therefore, type parameters can appear as parts of their own bounds, or as 
bounds of other type parameters declared in the same section.

没有递归,也没有定义新的类型。

也就是说:

代码语言:javascript
复制
package so_6949760;

import java.util.HashMap;

public class SweetCompilingGenerics {

    @SuppressWarnings("serial")
    public static class Sweet<X> extends HashMap<X, Sweet<X>> {}

    public static void main(String[] args) {
        Sweet<String> sweetStr = new Sweet<String>();
        Sweet<Sweet<Integer>> whatever = new Sweet<SweetCompilingGenerics.Sweet<Integer>>();

        assert sweetStr.getClass().equals(whatever.getClass()) : "who made generics a runtime mechanism?";
        assert sweetStr.getClass() == whatever.getClass() : "who made generics a runtime mechanism?";

        System.out.format("Is %s a Sweet<String> ?\n", sweetStr.getClass().getCanonicalName());
        System.out.format("Is %s a Sweet<Sweet<Integer>> ?\n", whatever.getClass().getCanonicalName());
    }
}

将输出甜蜜的秘密:

代码语言:javascript
复制
Is so_6949760.SweetCompilingGenerics.Sweet a Sweet<String> ? 
Is so_6949760.SweetCompilingGenerics.Sweet a Sweet<Sweet<Integer>> ?

我可以如此期待地给另一位极客朋友提个建议吗?请务必阅读规范。

post accept edit:刚找到这个highly informative article by IBM。这基本上解决了OP的所有问题。(推荐)。

票数 1
EN

Stack Overflow用户

发布于 2011-08-05 07:34:02

我认为你在这里做了一个不正确的逻辑跳跃。

代码语言:javascript
复制
T extends Comparable<T>

不是在暗示

代码语言:javascript
复制
Comparable<T> extends Comparable<Comparable<T>>

短类比

假设碎石机是任何可以粉碎岩石的材料,而岩石恰好能够自我破碎。因此,rock是一个碎石机。这是否意味着岩石可以粉碎任何可以粉碎岩石的物质?显然不是:钢可能也是一种碎石机,而石头可能不会压碎钢。

Long (基于代码)类比

假设我有一个接口Additive<T>,它可以用来描述任何类型,您可以在T对象上对这些类型执行add操作,然后返回一个T

现在假设我有一些方法,其签名如下所示:

代码语言:javascript
复制
public static <T extends Additive<T>> add(T x, T y) { ... }

因为x必须是我可以添加T的类型,所以这个方法可以按如下方式实现:

代码语言:javascript
复制
return x.add(y);

讲得通?好的,很好;但现在让我们假设您在问题中所做的假设:Additive<T>必须扩展Additive<Additive<T>>;如果是这样的话,我可以假设我可以向x添加一个实现Additive<T>的任何类型的实例。

这就是假设被打破的地方。我可能有一种类型,比如说...

代码语言:javascript
复制
// A 32-bit integral number supporting addition
public class Int32 implements Additive<Int32> { ... }

这是有道理的,对吧?我也可以有这样的东西:

代码语言:javascript
复制
// A list of 32-bit integral numbers supporting appending
public class Int32List implements Additive<Int32> { ... }

现在,如果T extends Additive<T>暗示Additive<T> extends Additive<Additive<T>>,那么我应该能够这样做:

代码语言:javascript
复制
Additive<Int32> x = new Int32(5);
Additive<Int32> y = x.add(new Int32List());

这有什么意义吗?

票数 4
EN

Stack Overflow用户

发布于 2011-08-05 07:29:35

没有什么特别之处

代码语言:javascript
复制
<T extends Comparable<T>>

考虑一下

代码语言:javascript
复制
public class Foo implements Comparable<Foo>{
     int compareTo(Foo x);
}

我甚至不认为我们可以说它是递归定义的,它只是自引用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6949760

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档