Java中的泛型并不总是很明显。我遇到过一种我并不完全理解的情况 - 也许有人可以帮助我。考虑以下三个类,每个类包含一个内部类:
public class DoesStuff<E extends DoesStuff.Element> {
ArrayList<E> elements;
public void MethodA(ArrayList<E> moreElements) {}
public void MethodB(ArrayList<E> moreElements) {}
public static class Element {}
}
public class DoesMoreStuff<E extends DoesMoreStuff.ElementA> extends DoesStuff<DoesMoreStuff.ElementA> {
ArrayList<DoesMoreStuff.ElementA> otherElements;
@Override
public void MethodA(ArrayList<DoesMoreStuff.ElementA> moreElements) {}
public static class ElementA extends DoesStuff.Element {}
}
public class DoesEvenMoreStuff extends DoesMoreStuff<DoesEvenMoreStuff.ElementB> {
ArrayList<DoesEvenMoreStuff.ElementB> stillOtherElements;
@Override
public void MethodB(ArrayList<*****> moreElements) {}
public static class ElementB extends DoesMoreStuff.ElementA {}
}
在我们进入第三节课之前,让我们先看看第二节课中的MethodA。 ArrayList的类型参数是“DoesMoreStuff.ElementA”,它扩展了“DoesStuff.Element”。这显然有效。
现在,在第三节课中,我们想要覆盖MethodB。在本课程中,我们打算使用ElementB的实例。但是,我们在类层次结构中是另一个级别,并且正确指定类型参数(显示为“ * ”)结果很难。
以下是一些可能性,所有这些都是有意义的,但没有一个可行:
&LT; DoesEvenMoreStuff.ElementB&GT;看起来这应该有效,因为ElementB扩展了ElementA,它本身扩展了Element
&LT; DoesStuff.Element&GT;在最坏的情况下,将所有内容都视为元素,但这也不起作用。
&LT ;? extends DoesStuff.Element&gt;无奈之下,说我们不关心班级是什么,只要它是元素的子类型;只要只读取ArrayList,就可以了,但它也不起作用。
事实上,唯一的可能性似乎是:
任何人都可以清楚地解释这种情况吗?
-----编辑-----
第二个类的所需行为是能够使用类型参数“DoesEvenMoreStuff.ElementB”。下面接受的答案解释了这个问题:第二个类通过将其设置为“DoesMoreStuff.ElementA”显式地指定了最顶层类的泛型参数。如下更改第二个类可以解决问题:
public class DoesMoreStuff<E extends DoesMoreStuff.ElementA> extends DoesStuff<E> {
ArrayList<E> otherElements;
@Override
public void MethodA(ArrayList<E> moreElements) {}
public static class ElementA extends DoesStuff.Element {}
}
美中不足的一个: 在第二个类中,MethodA的声明不是很正确:这应该是“MethodA(ArrayList&lt; DoesMoreStuff。 ElementA&gt;“,因为ArrayList将精确地包含内部类的元素。但是,编译器不再接受它。
P.S。对于任何对这种复杂类结构的应用感兴趣的人:最上层的类为数据库应用程序的离线模式提供通用数据缓存功能。第二类为大多数数据类提供数据缓存。第三类为需要特殊内容的特定类提供缓存。内部类是缓存数据元素。
答案 0 :(得分:1)
让我先举例说明:
List<DoesStuff> a = new LinkedList<DoesStuff>;
LinkedList<DoesStuff> b = new LinkedList<DoesMoreStuff>; //doesn't work.
在第二个示例中,如果它是合法的,您可以将DoesStuff
个对象添加到DoesMoreStuff
列表中。
诀窍在于DoesMoreStuff
你有没有使用的类型参数E
,你已经明确设置了类型参数并使用了这些方法:
public void MethodA(ArrayList<DoesMoreStuff.ElementA> moreElements) {}
public void MethodB(ArrayList<DoesMoreStuff.ElementA> moreElements) {}
你不能像上面的例子中描述的那样覆盖它们
@Override
public void MethodA(ArrayList<E> moreElements) {} // as described in the example above
现在进入第三节课:
public class DoesEvenMoreStuff extends DoesMoreStuff<DoesEvenMoreStuff.ElementB>
在超类中键入参数DoesEvenMoreStuff.ElementB
set E
类型参数,但未使用。
超级类有这些方法,您可以覆盖这些方法,而无需更改类型参数,如开头的示例所示。
public void MethodA(ArrayList<DoesMoreStuff.ElementA> moreElements) {}
public void MethodB(ArrayList<DoesMoreStuff.ElementA> moreElements) {}
希望这有助于澄清事情。
答案 1 :(得分:0)
当DoesMoreStuff从DoesStuff&lt; DoesMoreStuff.ElementA&gt;扩展时,你会继承你的继承树。而不是来自DoesStuff&lt; E&gt;用E扩展DoesMoreStuff.ElementB。
如果您希望继承树成功,那么您需要
public class DoesMoreStuff<E extends DoesMoreStuff.ElementA> extends DoesStuff<E> {
ArrayList<DoesMoreStuff.ElementA> otherElements;
@Override
public void MethodA(ArrayList<E> moreElements) {}
public static class ElementA extends DoesStuff.Element {}
}
然后
public class DoesEvenMoreStuff extends DoesMoreStuff<DoesEvenMoreStuff.ElementB> {
ArrayList<DoesEvenMoreStuff.ElementB> stillOtherElements;
@Override
public void MethodB(ArrayList<DoesEvenMoreStuff.ElementB> moreElements) {}
public static class ElementB extends DoesMoreStuff.ElementA {}
}
编译。
您不能同时破坏并继承泛型的继承树。