为什么Eclipse Java编译器会抱怨内部派生类型的未经检查的强制转换?

时间:2016-07-28 07:11:39

标签: java generics compiler-warnings

考虑以下具有非静态内部类的泛型类Base<ID>

public class Base<ID> {
  ID id;

  public Base(ID id) {
    this.id = id;
  }

  public ID getId() {
    return id;
  }

  protected class BaseInner {
    String text = "Inner";
  }

  protected void method(BaseInner o) {
    o.text = "Foo";
  }
}

方法Base.method采用BaseInner类型的参数。现在考虑以下派生类。

public class Sub<ID> extends Base<ID> {
  public Sub(ID id) {
    super(id);
  }

  @Override
  protected void method(BaseInner o) {

    if (o instanceof Sub.SubInner) {
      SubInner sub = (SubInner) o; // Why does this cast emit an "unchecked cast" warning

      sub.text = "Bar";
      sub.value = 1337;
    }
  }

  protected class SubInner extends BaseInner {
    Number value = 42;
  }
}

Sub派生自Base,内部类SubInner派生自内部类BaseInnerID的泛型类型参数Sub作为类型参数传递给基类Base

我的问题:为什么编译器会抱怨BaseInnerSubInner methodSubmethod的演员表?

要了解警告,我尝试构建一个用例,其中Sub<A>的{​​{1}}被调用,其中一些Sub<B>.SubInner证明了警告的合理性。但是,如果类型不兼容,我能想到的任何内容(包括? extends? super)都会在方法调用上发出编译器错误。

所以我猜我没有理由在method中对未经检查的演员表示警告。我错过了什么吗?

由于方法覆盖发生在Sub<ID>实现中,编译器能够将SubInner的泛型类型推断为Sub<ID>.SubInner。所以质疑这是重复!

Eclipse编译器警告是

  

类型安全:取消选中从Base&lt; ID&gt; .BaseInner到Sub&lt; ID&gt; .SubInner

的强制转换

如果我使用Base<ID>.BaseInner作为方法参数,或者在演员表达式中使用Sub<ID>.SubInner,那么waring也不会改变。

2 个答案:

答案 0 :(得分:1)

这接缝是Eclipse编译器问题。

Oracle编译器(javac)不会在此处省略任何警告。

答案 1 :(得分:0)

在这种情况下,未经检查的强制转换意味着您正在从非限定类型转换为泛型类型。

Set<String> set = new HashSet();

此行也会生成未经检查的分配警告。

出现此警告是因为如果编译时编译器是安全的,编译器无法扣除。

SubInner实例具有对Sub实例的引用。您正在从Base.BaseInner进行强制转换,因此您也从Base转换为Sub&lt; ID&gt;。因此,您正在收到此警告。

修改

解决方案是使用通用参数。

public class Base<ID> {
    ID id;

    public Base(ID id) {
        this.id = id;
    }

    public ID getId() {
        return id;
    }

    protected class BaseInner {
        String text = "Inner";
    }

    protected void method(Base<ID>.BaseInner o) {
        o.text = "Foo";
    }
}


public class Sub<ID> extends Base<ID> {
    public Sub(ID id) {
        super(id);
    }

    @Override
    protected void method(Base<ID>.BaseInner o) {
        SubInner sub = (SubInner) o; 
        sub.text = "Bar";
        sub.value = 1337;
    }

    protected class SubInner extends BaseInner {
        Number value = 42;
    }
}