以前可能已经以某种形式或其他形式提出这个问题,但我仍然无法解决它,所以我想我会在这里问集体智慧。我有一个这样的界面 - 我留下了一些评论,因为它们可能有所帮助。
/** Technical note: this generic binding is known as F-bound where class
* T is 'the worked-on class' by Splittable i.e. the implementing class.
*/
interface Splittable <T extends Element & Splittable<T>> {
/** Returns an object of the same class which has been split off at
* the point given.
*/
public T splitOff(double at);
/** Appends the object provided, which must be of the same class, to
* this object.
*/
public void append(T el);
}
那么我正在研究一个我在编译时不知道的元素:
if (el instanceof Splittable) {
if (nextEl.getClass == el.getClass) {
// same class so join them
((Splittable)el).append(nextEl);
}
}
这就是我得到编译器警告的地方 - 未选中调用append(T)作为原始类型Splittable的成员。
在Element子类中,我尝试了两种
SubClassEl extends Element implements Splittable
和
SubClassEl extends Element implements Splittable<SubClassEl>
警告没有区别。
此外,在调用append()时,我尝试了
((Splittable)el).splitOff(x).append(nextElement)
但编译器无法识别splitOff应返回Splittable,只返回Element。
有什么想法吗?
答案 0 :(得分:4)
这里发生的是你正在使用原始类型,它们“选择退出”泛型类型检查。发生这种情况时,T
为erased到Element
。来自The Java Tutorials:
当使用多重绑定时,绑定中提到的第一种类型用作类型变量的擦除。
至于如何在没有警告的情况下编译代码,您可能无法使用当前的设计。使用Element
处理普通instanceof
和强制转换不能与Splittable
上声明的递归绑定类型参数混合使用。
避免原始类型,我能得到的最接近的是:
static <T extends Element & Splittable<T>> void maybeAppend(T el1, Element el2) {
if (el1.getClass() == el2.getClass()) {
@SuppressWarnings("unchecked") // arguments' runtime types are equal
final T el2WithNarrowedType = (T)el2;
el1.append(el2WithNarrowedType);
}
}
...
if (el instanceof Splittable<?>) {
maybeAppend(el, nextEl); //compiler error
}
这仍然无法编译,因为如果没有类型参数,就无法表达el
是自己类型的Element
和Splittable
。
我在这里回答了类似的问题:Passing a runtime resolved parameter to a method which has multiple bound type, compilation error。最接近我不能使用的原始类型的解决方案是一个主要的黑客,只适用于某些编译器。 OP最终使用原始类型。
我对你的建议是避免自我键入,并考虑实现类似的东西:
interface ElementSplitter<T extends Element> {
T splitOff(T element, double at);
void append(T element, T appendedElement);
}
如果实现的splitOff
和append
功能需要访问给定Element
派生的私有成员,则解决方法是使其成为嵌套类,例如:
class SubClassEl extends Element {
...
static class Splitter implements ElementSplitter<SubClassEl> {
...
}
}
我注意到你写的Splittable
javadoc:
技术说明:这种通用绑定称为F-bound,其中类
T
是Splittable
的“工作级别”,即实现类。
你应该知道Java不支持真正的自我输入 - 你所拥有的是一个递归绑定的类型参数,它是所谓的,但不一定是自我类型。有关此模式及其缺陷的更多详细信息,请参阅我的回答here。