我想将内部类作为参数的泛型外部类。我期待,我将从基类派生出来,或者使用它的内部,或者从内部派生出来。在每个级别,我都希望从当前的派生级别开始限制内部类别的使用。
不幸的是,我在使用模式时会遇到各种错误和警告,以至于我无法想象,如何使用它。
package tests.java;
public class Try_GenericInnerRecursion {
// base class, consisting of outer and inner parts
public static class Outer1<E extends Outer1<E>.Inner1> {
public class Inner1 {
}
public void addElement(E e) {
System.out.println("Added " + e.toString());
}
}
// extending outer, but not inner
public static class Outer2<E extends Outer1<E>.Inner1> extends Outer1<E>{
}
// extending both outer and inner
public static class Outer3<E extends Outer3<E>.Inner3> extends Outer1<E>{
public class Inner3 extends Inner1 {
}
}
// extending both outer and inner and stopping extension
public static class Outer4 extends Outer1<Outer4.Inner4> {
public class Inner4 extends Outer1<Inner4>.Inner1 {
}
}
// instantiating
public static void main(String[] args) {
Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type
a1 = new Outer1<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type
Outer1<?> a2; // OK
a2 = new Outer1<?>(); // ERROR: Cannot instantiate the type Outer1<?>
Outer1<Outer1<?>.Inner1> a3; // ERROR: Bound mismatch: The type Outer1<?>.Inner1 is not a valid substitute for the bounded parameter <E extends Outer1<E>.Inner1> of the type Outer1<E>
Outer1<? extends Outer1<?>.Inner1> a4; // OK
a4 = new Outer1<Outer1.Inner1>(); // ERROR: Type mismatch
Outer2<Outer1.Inner1> b1; // WARNING: Outer1.Inner1 is a raw type
b1 = new Outer2<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type
// and so on
}
}
如何正确使用此模式?
答案 0 :(得分:3)
我相信你可以做到
DerivedCorpus1<?>
在通配符捕获期间,它变为
DerivedCorpus1<x> where x extends Corpus<x>.Element
这是正确的限制。
在你的例子中
DerivedCorpus1<? extends Corpus<?>.Element>
在通配符捕获期间,它变为
DerivedCorpus1<x> where x extends Corpus<x>.Element
and x extends Corpus<?>.Element
显然,extends Corpus<?>.Element
子句是多余的。
答案 1 :(得分:3)
Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type
实际上,我得到“类型参数Outer1.Inner1不在类型变量E`的范围内。”
Outer1.Inner1
是原始类型,因为Outer1
是原始类型。要使用非原始类型,您需要编写Outer1<something>.Inner1
。但是,something
也必须依次延长Outer1<something>.Inner1
。为了像这样进行递归,你需要一个命名的递归类型。不幸的是,由于Inner1
是一个非静态内部类,它有一个对Outer1
实例的隐式引用,因此扩展它的任何类都需要有一个{{1的实例}}。 Outer1
和Outer4
基本上就是这样做的。
Inner4
Outer4 a1 = new Outer4(); // compiles fine
你永远不能a2 = new Outer1<?>(); // ERROR: Cannot instantiate the type Outer1<?>
。
new something<?>()
这是事实。 Outer1<Outer1<?>.Inner1> a3; // ERROR: Bound mismatch: The type Outer1<?>.Inner1 is not a valid substitute for the bounded parameter <E extends Outer1<E>.Inner1> of the type Outer1<E>
不是Outer1<?>.Inner1
的子类型 - 反之亦然 - Outer1<E>.Inner1
是Outer1<E>.Inner1
的子类型。这就像Outer1<?>.Inner1
不是ArrayList<?>
的子类型一样;反过来了。
ArrayList<String>
这没关系,因为你在顶层有一个通配符,你的通配符的边界与类型参数Outer1<? extends Outer1<?>.Inner1> a4; // OK
的绑定相交。实际上,任何满足E
原始边界的东西都必须满足这个边界,所以这个边界是无用的,这与上面的E
相同。
Outer1<?> a2;
由于a4 = new Outer1<Outer1.Inner1>(); // ERROR: Type mismatch
不起作用的相同原因(a1
不满足Outer1.Inner1
的限制),因此不起作用。它还不满足你的约束(E
)。
Outer1<?>.Inner1
由于同样的原因,这实际上会产生与Outer2<Outer1.Inner1> b1; // WARNING: Outer1.Inner1 is a raw type
相同的错误
答案 2 :(得分:1)
通用规范
在我继续讨论实例化问题之前,我修改了你的通用定义:
Outer1<E extends Outer1<E>.Inner1>
Outer1基本上应该包含Inner1类型的元素或者它的任何子类。因此,Outer1对象的类型不相关,可以用以下代码替换:
Outer1<E extends Outer1<?>.Innter1>
使用上面提到的扩展类也稍作修改。
<强>实例化强>
对于对象的实例化,您说明了以下内容:
Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type a1 = new Outer1<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type
正如newacct已经提到的那样,虽然在实例化对象时没有指定任何类型,但Outer1
被声明为泛型类型。因此,代码应更改为以下代码:
Outer1<Outer1<?>.Innter1> a1; // or simply Outer1<?> a1;
a1 = new Outer1<Outer1<?>.Innter1>(); // or simply a1 = new Outer1<>();
类似于分配将基类扩展为该基类类型的类。
使用泛型类型定义指定实例将包含的元素类型。
像
这样的宣言Outer1<Outer1<?>.Innter1> test;
将接受任何扩展Outer1
且与通用类型匹配的实例。这意味着您只能分配
test = new Outer1<Outer1<?>.Inner1>();
test = new Outer2<Outer2<?>.Inner1>();
,但不是Outer3
甚至Outer4
!
即使您进一步修改代码以添加f.e.
public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{
public class Inner5 extends Inner1 {
}
}
你只能添加
test = new Outer5<Outer5<?>.Inner1>();
但不是
test = new Outer5<Outer5<?>.Inner5>(); // FAILS!
将Inner1
定义为类型参数。
然而,这个问题实际上是一个非常简单的解决方案。如果你定义这样的对象:
Outer1<? extends Outer1<?>.Inner1> test2;
你实际上可以做以下事情:
test2 = new Outer1<Outer1<?>.Inner1>();
test2 = new Outer2<Outer2<?>.Inner1>();
test2 = new Outer3<Outer3<?>.Inner3>();
test2 = new Outer4();
test2 = new Outer5<Outer1<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner5>();
正如您现在明确告诉编译器允许Inner1
类型本身或其任何扩展名。
<强>代码强>
我已更新您的代码并添加了一些新的分配,以验证所做的更改实际上不会产生任何编译错误或警告,除了redundant type arguments in new expression
由于显式指定类型参数而不是使用钻石运算符<>
:
public class GenericInnerRecursion
{
// base class, consisting of outer and inner parts
public static class Outer1<E extends Outer1<?>.Inner1> {
public class Inner1 {
}
public void addElement(E e) {
System.out.println("Added " + e.toString());
}
}
// extending outer, but not inner
public static class Outer2<E extends Outer1<?>.Inner1> extends Outer1<E>{
}
// extending both outer and inner
public static class Outer3<E extends Outer3<?>.Inner3> extends Outer1<E>{
public class Inner3 extends Inner1 {
}
}
// extending both outer and inner and stopping extension
public static class Outer4 extends Outer1<Outer4.Inner4> {
public class Inner4 extends Outer1<Inner4>.Inner1 {
}
}
public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{
public class Inner5 extends Inner1 {
}
}
// instantiating
public static void main(String[] args) {
Outer1<Outer1<?>.Inner1> a1;
a1 = new Outer1<Outer1<?>.Inner1>();
Outer1<?> a2;
a2 = new Outer1<>();
Outer1<Outer1<?>.Inner1> a3;
Outer1<? extends Outer1<?>.Inner1> a4;
a4 = new Outer1<Outer1<?>.Inner1>();
Outer2<Outer1<?>.Inner1> b1;
b1 = new Outer2<Outer1<?>.Inner1>();
// and so on
// assigning extension-classes to the parent-class
Outer1<Outer1<?>.Inner1> c1;
c1 = new Outer2<Outer2<?>.Inner1>();
// assigning inner-extension-classes to parent-class
Outer1<Outer3<?>.Inner3> c2;
c2 = new Outer3<Outer3<?>.Inner3>();
// assigning extension class without specified generics to parent class
Outer1<Outer4.Inner4> c3;
c3 = new Outer4();
Outer1<Outer1<?>.Inner1> test;
test = new Outer1<>();
test = new Outer2<>();
test = new Outer5<Outer5<?>.Inner1>();
Outer1<? extends Outer1<?>.Inner1> test2;
test2 = new Outer1<Outer1<?>.Inner1>();
test2 = new Outer2<Outer2<?>.Inner1>();
test2 = new Outer3<Outer3<?>.Inner3>();
// new Outer3<Outer3<?>.Inner1>(); not possible as generic type extends Outer3<?>.Inner3 and not Outer1<?>.Inner1!
test2 = new Outer4();
test2 = new Outer5<Outer1<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner5>();
}
}