虽然定义涉及接口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>
时的含义不同。
答案 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
的类型必须为Box
或Box
的任何后代。正如您正确提到的那样,它将导致无限嵌套。但是您仍然可以使用Wildcard和NewBox
作为类{{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
}
现在您要实现一个通用容器,该容器可以接受Op1
和Op2
类型的元素
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>>
我发现编写经过测试的示例会有所帮助。
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}}}
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>
因此,在引用接口而不是类时,此模式的行为会大不相同。
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}}}