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

3
考虑以下具有非静态内部类的泛型类 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继承自内部类BaseInner。泛型类型参数ID作为类型参数传递给基类Base我的问题:为什么编译器在Sub的覆盖方法中从BaseInnerSubInner的强制转换会报错?
为了理解警告,我尝试构建一个使用情况,在其中调用Sub<A>method与一些Sub<B>.SubInner,以证明该警告的必要性。但是,如果类型不兼容,我所能想到的任何事情(包括? extends? super)都会在方法调用时产生编译器错误。
所以我想,没有理由在method中进行未检查的强制类型转换的警告。我错过了什么吗?
由于方法重写发生在Sub<ID>实现中,编译器能够推断出SubInner的泛型类型为Sub<ID>.SubInner。因此,这个问题不是重复的!
Eclipse编译器警告如下:

类型安全性: 从Base<ID>.BaseInner到Sub<ID>.SubInner的未检查转换

如果我在方法参数中使用Base<ID>.BaseInner,或者在强制转换表达式中使用Sub<ID>.SubInner,则警告不会改变。

2
只是猜测,但由于您在if语句中使用了o instanceof Sub.SubInner,那么在下面的语句中您也应该使用Sub.SubInner,对吗? - nbro
我已经尝试过这种方法,还使用了 Sub<ID>.SubInner 进行转换,但是它总是产生相同的警告。 - niks
1
你使用的编译器是什么?我用javac 8没有收到任何警告。 - assylias
好的,我猜这是一个Eclipse编译器问题!如果Javac没有任何抱怨!我可以像预期的那样转换为SubInner!(不需要额外限定泛型类型,如Sub<ID>.SubInner - niks
@Andy Tuner:这不是重复的问题。javac编译器对我的代码没有发出任何警告!请重新打开问题,以便我们可以添加正确的答案。 - niks
2个回答

1
这似乎是Eclipse编译器的问题。 Oracle编译器(javac)在此处不会省略任何警告。

0
在这种情况下,未经检查的转换意味着您正在从不合格的类型向泛型类型进行转换。
Set<String> set = new HashSet();

这行代码也会产生未经检查的赋值警告。

出现此警告是因为编译器无法推断强制转换在编译时是否安全。

SubInner 实例引用了 Sub 实例。您正在从 Base.BaseInner 进行强制转换,因此还从 Base 转换为 Sub<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(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;
    }
}

这行代码也会产生未经检查的转换警告。不,它会产生原始类型警告。那里没有转换。 - Andy Turner
我已经尝试将通用类型参数添加到SubInner和该方法中,但没有成功。 - niks
添加SubInner类型参数并不能解决问题,因为SubInner引用了一个泛型的Sub对象。因此,你从中转换的Base类也应该是泛型的。否则,你将会从非限定类型向泛型类型进行转换。 - Ugur Hicyilmam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接