【问题标题】:How to avoid generic compiler warning for interface如何避免接口的通用编译器警告
【发布时间】:2013-05-30 10:53:58
【问题描述】:

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

/** 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。

有什么想法吗?

【问题讨论】:

  • 你能告诉我们Element扩展和实现了什么吗?
  • 嗨 vikingsteve - 不确定这是否有很大帮助:Element 是我用 getEditState、getHeight 之类的东西编写的抽象类,我认为它与泛型问题无关。不过感谢您的关注!

标签: java generics interface class-hierarchy


【解决方案1】:

这里发生的情况是您使用的是原始类型,它“选择退出”泛型类型检查。当这种情况发生时,TerasedElement。来自The Java Tutorials

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

至于如何让您的代码在没有警告的情况下编译,您当前的设计可能无法实现。使用instanceof 和强制转换处理普通的Elements 与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。我能想出的最接近的不使用原始类型的解决方案是一个重大的 hack,并且只适用于某些编译器。 OP 最终使用了原始类型。

我给你的建议是避免自我输入,而是考虑实现这样的东西:

interface ElementSplitter<T extends Element> {

    T splitOff(T element, double at);

    void append(T element, T appendedElement);
}

如果实现的splitOffappend 功能需要访问给定Element 派生的私有成员,解决方法是将其设为嵌套类,例如:

class SubClassEl extends Element {

    ...

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

我注意到你写的Splittablejavadoc:

技术说明:这种通用绑定称为 F 绑定,其中 T 类是 Splittable 的“工作类”,即实现类。

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

【讨论】:

  • Paul,非常感谢您的全面解释和建议。我已经看到了许多与泛型相关的静态方法,现在我更好地理解了为什么会这样,以及为什么编译器会抱怨 .splitOff.append 链。正如您可能想象的那样,它不会真正改变任何东西,但我想我会重新编写该部分,看看我是否可以在没有警告的情况下强制执行类型检查,如果只是为了理解的话。
猜你喜欢
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多