circular generics : interface IFoo <T extends IFoo <T>>
这是Java中一个众所周知的习惯用法。例如,参见此SO讨论。因此,基本上定义一个接口,实现该接口的类需要一种方法来与您的类的对象进行比较:
1 2 3 | public interface IComparable<T extends IComparable< T >> { public int compare(T item); } |
(注意:这显然是解决特定用例的不必要复杂的方法-请参阅此文章-但我正在询问如何解释递归语法,请不要介意特定的应用程序)。
简而言之,这是一个递归定义,在递归中没有明显的结尾,我看不到编译器/类型系统如何实现此目的。
此外,尝试输入文字(" IComparable是一个其实例可以与实现IComparable接口的类的对象进行比较的类"),这会产生一个不合逻辑的循环定义,该定义在Philosophy中是不可能的,逻辑/数学,但显然在编译器设计中是可行的(!)。
此外,如果原始成语语法可以接受,那么似乎也可以这样说:
1 2 3 | public interface IComparable<T extends IComparable<T extends IComparable< T >>> { public int compare(T item); } |
...但是编译器对此表示不满,显然只允许一个级别的
有人可以帮我弄清楚这种递归泛型定义吗?
更新
基于公认的答案(BartoszKP),我现在想知道的是以下内容:
"递归"定义不应被理解为(代表"定义取决于"关系的箭头):
1 | [ IComparable< T > ] -------> [ IComparable< T > ] |
...这是不合逻辑的(圆形),而是:
1 2 3 4 | [ IComparable< T > ] ----------> [ list of methods (parameterized by T) ] \\ ^ \\ | \\-------> [ type bound on T ]-------/ |
...这不是不合逻辑的,因此可以在编译器中使用。因此,换句话说,
This is a well-known idiom in Java.
不。它没有用,因此不应使用。除了
类型变量的泛型边界的目的是建立关系,以便泛型类或泛型方法中的代码可以使用该保证来执行某些操作而无需强制转换,这可能是不安全的。泛型边界应尽可能不受限制,同时仍可防止代码中的强制转换。
因此,绑定
我已经看到了这种模式的许多用法,在99%的情况下,他们不需要执行上述操作。相反,在99%的时间中,人们想要做的是以某种方式表示
在大多数情况下,人们使用此模式时,会在内部执行
因此,如果您看到过该代码,几乎可以肯定会对它的功能有误解,并且应该几乎总是将其更改为:
1 2 3 | public interface IComparable< T > { public int compare(T item); } |
作为练习,我挑战您找到一个片段,其中
实际上-您不需要递归定义。
1 2 3 4 5 6 7 8 9 10 | public interface IComparable< T > { public int compare(T item); } public class Foo implements IComparable<Foo> { @Override public int compare(Foo o) { return 0; } } |
足够定义您要尝试的内容。
递归定义的常见地方是使用
作为@NPE在引用的讨论中的帖子的叙述:
1 2 3 4 5 | public interface ResultItem<T extends ResultItem< T >> { public int getConfidence(); public boolean equals(T item); public T cloneWithConfidence(int newConfidence); } |
这里发生的是,您不是在按照特定的通用类
首先,对于您对复发的怀疑:
这是某种形式的重复(因为X是由与X相关的东西定义的),但是即使是这样,它也只是一个级别。想象一下,编译器具有一个
1)
为此,需要内部
2)
这将解析源文件,以获取
3)创建通用约束,以保护
的所有方法
4)继续执行步骤1)-解析源文件,以获取
实际上这可能更复杂,但这有助于看到不需要重复进行解释。因此,与具有接受
1 2 3 4 5 6 7 8 9 10 11 | class X; class Y { private: X* x; }; class X { }; |
接下来,关于它的可用性。从评论和相关主题中收集信息,我声明该机制用于表达实现给定接口的类的意图,并使该接口更加有用和方便。本主题对此进行了详细说明:如何使接口实例方法仅接受同一类的参数?。
在第二种情况下,实现该接口的类没有任何方便之处:
1 2 3 | public interface IComparable<T extends IComparable< T >> { public int compare(T item); } |
但是,可以将其解释为表示以下事实:
在这里有更多详细信息:如何使接口实例方法只接受同一类的参数呢?
有关此习语用法的更多详细信息:http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106。