小编典典
这是一个普遍的问题,可以理解的是。请看一下泛型FAQ的这一部分,以获得答案(实际上,您可以随意阅读整个文档,它做得很好而且内容丰富)。
简短的答案是,它迫使该类对其自身进行参数化。这是超类使用通用参数定义与子类透明(如果需要的话,是“本地”)工作的方法所必需的。
编辑:作为一个(非)示例,请考虑上的clone()方法Object。当前,它被定义为返回type的值Object。由于协变返回类型,特定的子类可以(并且经常)定义它们返回更特定的类,但这不能强制执行,因此不能为任意类推断。
现在,如果Object的定义类似于Enum,Object>则必须将所有的类定义为public class MyFoo。因此,clone()可以声明其返回的类型,T并且可以确保在编译时返回的值始终与对象本身完全是同一类(即使子类也不匹配参数)。
现在,在这种情况下,Object并没有像这样被参数化,因为当99%的类根本不会使用它时,在所有类上都放这个行李会非常令人讨厌。但是对于某些类层次结构来说,它可能非常有用-我本人之前曾使用过类似的技术来处理具有多个实现的抽象,递归表达式解析器的类型。这种结构使得编写“明显的”代码而不用到处强制转换或复制和粘贴只是为了更改具体的类定义成为可能。
编辑2(实际上要回答您的问题!):
如果将Enum定义为Enum,那么正如您正确地说的,某人可以将一个类定义为A extends Enum。这违反了泛型构造的观点,即确保泛型参数始终是所讨论类的确切类型。举一个具体的例子,枚举将其compareTo方法声明为
public final int compareTo(E o)
在这种情况下,由于您定义A了extend Enum,A因此只能将的实例与的实例B(无论B是什么)进行比较,这几乎肯定不是很有用。 使用附加的构造,您知道扩展Enum的任何类都只能与其自身进行比较。因此,您可以在超类中提供在所有子类中仍然有用且特定的方法实现。
(没有这种递归泛型技巧,唯一的选择是将compareTo定义为public final int compareTo(Enum o)。这并不是完全一样的事情,因为这样就可以将ajava.math.RoundingMode与a进行比较,java.lang.Thread.State而不会引起编译器的抱怨,这也不是很有用。)
好的,让我们远离Enum它,因为我们似乎已经挂在上面了。相反,这是一个抽象类:
public abstract class Manipulator>
{
/**
* This method actually does the work, whatever that is
*/
public abstract void manipulate(DomainObject o);
/**
* This creates a child that can be used for divide and conquer-y stuff
*/
public T createChild()
{
// Some really useful implementation here based on
// state contained in this class
}
}
我们将对此进行一些具体的实现-SaveToDatabaseManipulator,SpellCheckingManipulator等。另外,我们还希望让人们定义自己的类,因为这是一个超级有用的类。;-)
现在-您将注意到我们正在使用递归泛型定义,然后T从该createChild方法返回。这意味着:
1)我们知道并且编译器知道如果我调用:
SpellCheckingManipulator obj = ...; // We have a reference somehow
return obj.createChild();
那么返回的值肯定是a SpellCheckingManipulator,即使它使用的是超类的定义。这里的递归泛型使编译器知道对我们显而易见的内容,因此您不必继续强制转换返回值(例如,您经常需要使用clone(),例如)。
2)请注意,我没有将方法声明为final,因为也许某些特定的子类会希望使用更适合自己的版本来覆盖它。泛型定义意味着无论是由谁创建新类或如何定义新类,我们仍然可以断言from的返回BrandNewSloppilyCodedManipulator.createChild()仍然是的实例BrandNewSloppilyCodedManipulator。如果粗心的开发人员试图将其定义为只返回just Manipulator,则编译器将不允许它们。而且,如果他们尝试将类定义为BrandNewSloppilyCodedManipulator,那么也不会允许他们。
基本上,结论是,当您想在超类中提供某些功能(以某种方式在子类中变得更加具体)时,此技巧很有用。通过这样声明超类,您可以将任何子类的通用参数锁定为子类本身。这就是为什么您可以在超类中编写泛型compareTo或createChild方法并防止在处理特定子类时它变得过于模糊的原因。
2020-11-04