Java 如何避免接口的泛型编译器警告

Java 如何避免接口的泛型编译器警告,java,generics,interface,class-hierarchy,Java,Generics,Interface,Class Hierarchy,以前可能有人以某种形式问过这个问题,但我仍然无法解决,所以我想我应该问一下这里的集体智慧。我有一个这样的界面-我留下了一些评论,因为它们可能会有所帮助 /** 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 <

以前可能有人以某种形式问过这个问题,但我仍然无法解决,所以我想我应该问一下这里的集体智慧。我有一个这样的界面-我留下了一些评论,因为它们可能会有所帮助

/** 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);
}
这就是我得到一个编译器警告-取消选中的调用,作为原始类型Splittable的成员调用appendT

在元素子类中,我尝试了这两种方法

SubClassEl extends Element implements Splittable

但是编译器没有意识到splitOff应该返回一个Splittable,只返回一个元素


有什么想法吗?

这里发生的事情是,您使用的是原始类型,它选择退出泛型类型检查。当这种情况发生时,T是元素。发件人:

当使用多重绑定时,绑定中提到的第一个类型将用作类型变量的擦除

至于如何在没有警告的情况下编译代码,您当前的设计可能无法做到这一点。使用instanceof和cast处理普通元素不会与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
}
如果实现的拆分和追加功能需要访问给定元素派生的私有成员,解决方法是将其设为嵌套类,例如:

class SubClassEl extends Element {

    ...

    static class Splitter implements ElementSplitter<SubClassEl> {
        ...
    }
}
我注意到您在Splittable javadoc中写道:

技术说明:这种泛型绑定称为F-bound,其中T类是Splittable的“工作类”,即实现类


您应该知道,Java不支持真正的自类型化—您拥有的是一个递归绑定的类型参数,它应该是自类型,但不一定是自类型。有关此模式及其缺陷的更多详细信息,请参见我的答案。

这里发生的情况是,您使用的是原始类型,它选择退出泛型类型检查。当这种情况发生时,T是元素。发件人:

当使用多重绑定时,绑定中提到的第一个类型将用作类型变量的擦除

至于如何在没有警告的情况下编译代码,您当前的设计可能无法做到这一点。使用instanceof和cast处理普通元素不会与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
}
如果实现的拆分和追加功能需要访问给定元素派生的私有成员,解决方法是将其设为嵌套类,例如:

class SubClassEl extends Element {

    ...

    static class Splitter implements ElementSplitter<SubClassEl> {
        ...
    }
}
我注意到您在Splittable javadoc中写道:

技术说明:这种泛型绑定称为F-bound,其中T类是Splittable的“工作类”,即实现类


您应该知道,Java不支持真正的自类型化—您拥有的是一个递归绑定的类型参数,它应该是自类型,但不一定是自类型。有关此模式及其缺陷的更多详细信息,请参阅我的答案。

您能告诉我们元素扩展和实现了什么吗?嗨,vikingsteve-我不确定这会有多大帮助:元素是我编写的抽象类,使用了getEditState、getHeight之类的东西,我认为它们与泛型问题无关。谢谢你的关注!你能告诉我们元素扩展和实现了什么吗?嗨,vikingsteve-我不确定这会有多大帮助:元素是我用getEditState、getHeight之类的东西编写的抽象类,我认为它们与泛型问题无关。谢谢你的关注!保罗,非常感谢你的全面解释和建议。我见过许多与泛型相关的静态方法,现在我更好地理解了为什么会这样,以及编译器为什么抱怨.splitOff.append-chain。正如您可能想象的那样,它不会真正改变任何东西,但我想我会修改该部分,看看我是否可以在没有警告的情况下执行类型检查,如果仅仅是为了理解的话。Paul,非常感谢您的全面解释和建议。我见过许多与泛型相关的静态方法,现在我更好地理解了为什么会这样,以及编译器为什么抱怨.splitOff.append-chain。正如您可能想象的那样,它不会真正改变任何东西,但我想我会修改该部分,看看我是否可以在没有警告的情况下强制执行类型检查,如果仅仅是为了理解的话。
interface ElementSplitter<T extends Element> {

    T splitOff(T element, double at);

    void append(T element, T appendedElement);
}
class SubClassEl extends Element {

    ...

    static class Splitter implements ElementSplitter<SubClassEl> {
        ...
    }
}