4

我只是对一个 java 编译场景感到困惑,它对给定的问题表现得很奇怪。

下面的代码将给出编译错误(不能转换类型),因为 A 和 B 是不同的类,它们之间没有关系。

        A a = new A();
        B b = new B();

        B b1 = (B)a;
        A a1 = (A)b;

同样,如果我将 List 和 Map 相互转换,它应该给我编译错误。但它没有给出任何这样的错误,当然我在运行时得到 ClassCastException。

        List<String> listObj = new ArrayList<String>();
        Map<Integer,Float> mapObj = new HashMap<Integer,Float>();

        Map newMapObj = (Map) listObj;
        List newListObj = (List) mapObj;

这次调整的原因是什么...

4

1 回答 1

7

那是因为MapList是接口,您可以拥有一个实现两者的类。这对类无效,因为在 Java 中不可能进行多重继承。


即使这样的用例使编译器看起来很笨(很明显,在这种情况下强制转换永远不会成功),深入研究初始化代码也没有多大意义,因为这需要跟踪所有可能的分配参考:

List<String> someOtherList = getSomeOtherList();
List<String> listObj = someOtherList != null ? someOtherList : new ArrayList<String>();

这将使编译器无法说出List这一listObj行之后的类型。

即使使用您的简单示例,编译器也需要在您的初始声明listObj和强制转换尝试之间跟踪该变量没有其他分配(以便它可以确定肯定listObj是 a ArrayList)。一旦在分配和演员表之间放置了其他代码行,这种跟踪就会变得痛苦甚至不可能。


但我确实同意这样的编译器限制可能令人沮丧。我有时会发现以下内容无法编译的事实很烦人:

final int i;
try {
    i = Integer.parseInt("someString");
} catch (NumberFormatException e) {
    i = -1;
}

...因为“变量'i'可能已经被分配给”,这显然是不可能的。但是编译器实际上并不关心我的try块中的内容,它假设aNumberFormatException可以在赋值之后被某行代码抛出;所以i不能声明final

于 2013-02-05T08:19:10.477 回答