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 的实例。但是,我们在类层次结构中处于另一个层次,并且正确指定类型参数(显示为“ * ”)变得很困难。
以下是一些可能性,所有这些都有意义,但都不起作用:
<DoesEvenMoreStuff.ElementB> 似乎这应该有效,因为 ElementB 扩展了 ElementA,它本身扩展了 Element
<DoesStuff.Element> 在最坏的情况下,将所有内容都视为 Element,但这也行不通。
<? extends DoesStuff.Element> 无奈之下,说我们不在乎这个类是什么,只要它是Element的子类型;只要 ArrayList 只会被读取,就可以了,但它也不起作用。
事实上,唯一的可能似乎是:
- <DoesMoreStuff.ElementA> 这行得通,大概是因为 ElementA 直接扩展了 Element,因此匹配顶级类中的原始声明。但是,这似乎不合逻辑,至少对我来说不是。
任何人都可以对这种情况提供明确的解释吗?
- - - 编辑 - - -
第二类的期望行为是能够使用类型参数“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<DoesMoreStuff.ElementA>”,因为 ArrayList 将包含内部类的元素。这个但是,编译器不再接受。
PS 对于任何对这种复杂类结构的应用感到好奇的人:最上面的类为数据库应用程序的离线模式提供通用数据缓存能力。第二类为大多数数据类提供数据缓存。第三个类为需要特殊的特定类提供缓存。内部类是缓存数据元素。