“类A <t extended =”“ someclass <t =”“ >>”与类B <t extend =“” someinterface <t =“” >>的工作方式不同? (是)

时间:2019-02-23 19:32:07

标签: java generics

虽然定义涉及接口Comparable

class B <T extends Comparable<T>>

是众所周知的且可实例化的,在扩展类而不是接口时,相同的用法不能以相同的方式起作用。这是一个例子

class G <T extends Box<T>> {
    T val;
    G(T val) {
        this.val = val;
    }
}

上面的类可以编译,但是我找不到实例化G的方法。它似乎需要Box的无限嵌套。

G<Box<Box<..>>>

这是我对Box类的定义

class Box <T> {
    T val;
    Box(T val) {
        this.val = val;
    }
}

为帮助讨论,以下是一些类似的示例。我测试了所有代码。

以下课程的含义对我很清楚

class D <T extends Box<String>> {
    T val;
    D(T val) {
        this.val = val;
    }
}

我们可以使用实例化

    D<Box<String>> d = new D<>( new Box<String> ("hello") );

我们可以对此进行概括,以便Box可以包含任何内容

class F <S, T extends Box<S>> {
    T val;
    F(T val) {
        this.val = val;
    }
}

我们可以使用实例化

    F<String,Box<String>> f = new F<>( new Box<String> ("hello") );

回到原始问题,以下是什么意思,以及如何/可以将其实例化?

class G <T extends Box<T>> {
    T val;
    G(T val) {
        this.val = val;
    }
}

此类G是我对上述类D的一般化的首次尝试,以便Box可以容纳任何类型,而不仅仅是String。后来我想到了F类作为解决问题的方法,但我想知道G的含义是什么,为什么它与T extends SomeInterface<T>时的含义不同。

3 个答案:

答案 0 :(得分:2)

如果Box类没有带有T的构造函数,则可以创建扩展Box的类。例如:

class NewBox extends Box<NewBox> {
    ...
}

然后,您可以像这样实例化G

G<NewBox> g = new G<>(new NewBox());

但是在您的情况下,Box具有构造函数Box(T val){...},然后NewBox需要与super匹配的构造函数,例如:

class NewBox extends Box<NewBox> {
    NewBox(NewBox val) {
        super(val);
    }
}

要实例化它,您应该以null结尾,否则将导致无限嵌套:

G<NewBox> g = new G<>(new NewBox(new NewBox(new NewBox(null))));

更新:回答您的原始问题:G <T extends Box<T>>意味着T的类型必须为BoxBox的任何后代。正如您正确提到的那样,它将导致无限嵌套。但是您仍然可以使用WildcardNewBox作为类{{1的构造函数的参数)实例化此而不创建额外的类(与null相同) }},例如:

G

答案 1 :(得分:2)

如果您担心绑定的类型T extends Box<T>意味着只能指定为type参数的类型必须扩展Box

此技术用于指定您可以对类型进行的其他操作(例如众所周知的Comparable<T>),因此使用类而不是接口实际上并不常见。

让我给你举个例子。说我们有以下操作

interface Op1<T>{
    void doOp1(t: T): T
}

interface Op2<T> {
   void doOp2(t: T): T
}

class MyClass implements Op1<MyClass>, Op2<MyClass>{
    //By implementing Op1 and Op2 you
    //specify that operations doOp1 and doOp2
    // can be applied to variable of typr MyClass
}

现在您要实现一个通用容器,该容器可以接受Op1Op2类型的元素

class MyContainer<T extends Op1<T> & Op2<T>>{
   //you can apply doOp1 and doOp2 to any variable of the type T
}

MyContainer<MyClass> t = //... Ok
MyContainer<Integer> t = //... Not ok

在函数式编程中,类似(但不完全相同)的东西称为类型类

答案 2 :(得分:0)

答案概要

@Ruslan@Some Name的答案以及对该问题的评论中得出,这是两者之间差异的提要

class G <T extends SomeClass<T>>
class B <T extends SomeInterface<T>>  
class Enum<E extends Enum<E>>   

我发现编写经过测试的示例会有所帮助。

1。 class G <T extends SomeClass<T>>

G要求将类型T定义为

class T extends SomeClass<T> {}

以下是类似T的类的示例

class RussianBox extends Box<RussianBox> {
    RussianBox(RussianBox box) {
        super(box);
    }
}

其中类Box被定义为

class Box <T> {
    T value; 
    Box(T value) {
        this.value = value;
    }
    public String toString() {
        return this.getClass().getSimpleName()+" containing {"+this.value+"}";
    }
}

以下是类似G的类的示例

class RussianBoxContainer <T extends Box<T>>   {
    T value; 
    RussianBoxContainer(T value) {
        this.value = value;
    }
    public String toString() {
        return this.getClass().getSimpleName()+" containing {"+this.value+"}";
    }
}

以下代码实例化了这三个类

    Box<String> box = new Box<>("Gold");
    out.println("box = " + box );

    RussianBox russianBox = new RussianBox( new RussianBox(null) );
    out.println("russianBox = " + russianBox );

    RussianBoxContainer<RussianBox> containerForARussianBox = new RussianBoxContainer<>(russianBox);
    out.println("containerForARussianBox = " + containerForARussianBox );

并产生以下输出

box = Box containing {Gold}
russianBox = RussianBox containing {RussianBox containing {null}}
containerForARussianBox = RussianBoxContainer containing {RussianBox containing {RussianBox containing {null}}}

2。 class B <T extends SomeInterface<T>>

B要求将类型T定义为

class T extends SomeClass implements SomeInterface<T> {}

java.lang.Integer类是类似T的类的示例

class Integer extends Number implements Comparable<Integer>

因此,在引用接口而不是类时,此模式的行为会大不相同。

3。 class Enum<E extends Enum<E>>

现在创建类 like Enum的类。这是一个例子

class RussianBoxContainer2 <T extends RussianBoxContainer2<T>>   {
    RussianBoxContainer2<T> value; 
    RussianBoxContainer2(RussianBoxContainer2<T> box) {
        this.value = box;
    }
    public String toString() {
        return this.getClass().getSimpleName()+" containing {"+this.value+"}";
    }
}

就像Enum一样,我们需要先继承RussianBoxContainer2的子类,然后才能使用RussianBoxContainer2。这是一个子类的示例

class RussianBox2 extends RussianBoxContainer2<RussianBox2> {
    RussianBox2(RussianBox2 box) {
        super(box);
    }
}

以下代码实例化了这两个类

RussianBox2 russianBox2 = new RussianBox2(new RussianBox2(null));
out.println("russianBox2 = " + russianBox2 );

RussianBoxContainer2<RussianBox2> containerForARussianBox2 = new RussianBoxContainer2<>(russianBox2);
out.println("containerForARussianBox2 = " + containerForARussianBox2 );

并产生以下输出

russianBox2 = RussianBox2 containing {RussianBox2 containing {null}}
containerForARussianBox2 = RussianBoxContainer2 containing {RussianBox2 containing {RussianBox2 containing {null}}}