这个泛型类声明可能意味着什么?

时间:2011-09-24 07:17:21

标签: java generics generic-programming

我知道这不是一个很好的问题,我可能会受到诅咒但是我找不到任何地方可以帮助解决这个问题

下面是我的面试问题中出现的一个通用课程(我已经失败了)。问题是告诉这个类声明正在做什么以及在什么情况下可以使用它?

我对通用编程的理解非常有限,但我理解'T'是Type,'extends'在这里意味着Type应该继承'SimpleGenericClass',但我不理解'?'最后以及在什么情况下该类可能被用于

public abstract class SimpleGenericClass<T extends SimpleGenericClass<?>> {

}

5 个答案:

答案 0 :(得分:4)

首先,因为类SimpleGenericClass abstract ,所以它应该是子类。

其次,它是一个泛型类,这意味着在类的某个地方,你几乎肯定会使用泛型参数T作为字段的类型。

public abstract class SimpleGenericClass<T...> {
    T x;
}

现在第一个有趣的事情是T 有界。因为它被声明为T extends SimpleGenericClass<?>,所以它只能是SimpleGenericClass<?>SimpleGenericClass<?>的某个子类。您还询问了thr ?。这被称为通配符,在the Java Tutorial on Wildcards有一个非常好的解释。在你的情况下,我们会说这是一个“未知的SimpleGenericClass”。在Java中需要它,因为SimpleGenericClass<Object>不是SimpleGenericClass<String>的超类,例如。

第二个有趣的是,由于T是某种类型的SimpleGenericClass,因此您的类很可能定义递归结构 。我想到的是树(想到表达式树),其中SimpleGenericClass是(抽象)节点类型,设计为使用各种专用节点类型进行子类化。

更新 This SO question on self-bounded generics可能会对您有所帮助。

更新2

我继续编写了一些代码,说明了如何使用它。该应用程序不执行任何操作,但它会进行编译,它会向您显示通用边界如何提供一些可能有意义的约束。

public abstract class Node<T extends Node<?>> {
    public abstract T[] getChildren();
}

class NumberNode extends Node {
    int data;
    public Node[] getChildren() {return new Node[]{};}
}

class IdentifierNode extends Node {
    int data;
    public Node[] getChildren() {return new Node[]{};}
}

class PlusNode extends Node {
    NumberNode left;
    NumberNode right;
    public NumberNode[] getChildren() {return new NumberNode[]{};}
}

这里的好处是NumberNode[]PlusNode.getChildren的有效返回类型!在实践中这有关系吗?不知道,但很酷。 :)

这不是最好的例子,但问题是相当开放的(“这样的东西可能用于什么?”)。当然,还有其他方法可以定义树。

答案 1 :(得分:0)

这实际上只意味着您允许类SimpleGenericClass的用户参数化类型为T的类的实例。但是,T不能是任何类型,但必须是SampleGenericClass(或SampleGenericClass本身)的子类型。

在SimpleGenericClass类的其余代码中,您可以在方法签名中使用类型T.

让我们假设SimpleGenericClass不是抽象的。使用它时,您可以写:

new SimpleGenericClass<SampleGenericClass<String>>();

即。使用SampleGenericClass和带有String的SampleGenericClass对SimpleGenericClass进行参数化。

答案 2 :(得分:0)

根据定义,它表示SimpleGenericClass可以处理类型<T>,它是SimpleGenericClass的子类。

所以我假设会有一些可以在<T>上运行的操作。

现在看看为什么要定义这样的模板 - (我真的不能想到),可能是SimpleGenericClass是一个抽象类的场景(刚才意识到它是按照OP:P )并期望它可以适用于任何具体的类?

伙计们你觉得怎么样?

答案 3 :(得分:0)

这基本上是sais:在这个类中你有一个名为T的Type占位符,以及对该占位符的限制,它必须是SimpleGenericClass类型或扩展它的东西。一旦遵守该规则,您就可以创建类的实例并为T提供实际类型,稍后可以在该类的方法中使用,如下所示:

public class C <T extends Number>{

    public void doSomething(T t) {

    }

    public static void main(String... args) {
        //works:
        C<Number> c = new C<Number>();
        c.doSomething(new Number() {
            //Aonimous implementation of number

        });

        //won't work
        //C<Object> c = new C<Object>();

        C<Integer> c2 = new C<Integer>();       
        c2.doSomething(new Integer(1));
        //won't work
        //c2.doSomething(new Number() {

            //Aonimous implementation of number
        //});
    }
}

此时SimpleGenericClass<?>非常多余。如果此类需要其他泛型类型,则可以有多个(SimpleGenericClass<T extends SimpleGenericClass, T2 extends Whatever>

答案 4 :(得分:0)

我猜你已经以这种形式提出了问题(T而不是?):

public abstract class SimpleGenericClass<T extends SimpleGenericClass<T>>

看看这段代码:

abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>
{
    /** subclasses are forced to return themselves from this method */
    public abstract SubClassOfFoo subclassAwareDeepCopy();
}

class Bar extends Foo<Bar> {
    public Bar subclassAwareDeepCopy() {
        Bar b = new Bar();
        // ...
        return b;
    }
}

Bar b = new Bar();
Foo<Bar> f = b;
Bar b2 = b.subclassAwareDeepCopy();
Bar b3 = f.subclassAwareDeepCopy(); // no need to cast, return type is Bar

Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>的诀窍是:

  • Foo的任何子类都必须为Foo提供类型参数。
  • 该类型参数实际上必须是Foo的子类。
  • Foo的子类(如Bar)遵循该类型的习语 他们提供给Foo的论据就是他们自己。

  • Foo有一个返回SubClassOfFoo的方法。综合 用上面的成语,这允许Foo制定合同 说“我的任何子类都必须实现subclassAwareDeepCopy()和 他们必须声明它返回实际的子类“。

换句话说:这个习惯用法允许超类(例如抽象工厂)定义其参数类型和返回类型是根据子类类型而不是超类类型的方法。

诀窍是在Enum JDK类:

中完成的
public abstract class Enum<E extends Enum<E>>

有关详细信息,请参阅here