为什么Java中的桥接方法不能防止这种情况并抛出异常?

问题描述 投票:2回答:1

为什么下面的泛型代码不会在运行时抛出异常?

public static void main(String[] args) {
        ((List)new ListString()).add(3);
    }


    static class ListString extends ArrayList<String>{

    }

我知道这不是应该如何使用泛型但我认为the bridge methods会通过添加以下方法来解决这个问题,这将抛出一个ClassCastException.

public boolean add(Object o){
      return add((E)o);
}

注意:如果按照以下方法修改ListString类,这确实会引发ClassCastException:

static class ListString extends ArrayList<String>{
        @Override
        public boolean add(String o){
            return super.add(o);
        }
    }
java generics
1个回答
4
投票

除非您实际编写方法,否则不会创建桥(合成方法),就像您在后续测试中所做的那样,您在代码中放置了public boolean add(String o){return super.add(o);}

当你在.get(someInt)类型的表达式上调用StringList时,编译器可以看到你的StringList类型,即使它是ArrayList<String>的子类型,也没有任何带有签名String get(int)的方法。因此,它在字节码中生成对Object get()方法的调用,此外(如果需要)生成一个强制类型,并且在java方面,它就像在StringList上的get方法返回String一样。即使在字节码级别它也没有。

如果然后出现一个String get(int)方法,例如通过继承StringList,或者通过编辑源并重新编译该文件,那么只有这样才能生成桥接方法。因为java是动态调度,所以总是使用该桥。桥梁施放和调用(或调用和施放,取决于桥梁是否覆盖返回类型的恶作剧或参数恶作剧)。

你可以使用javap -v来验证所有这些:我强烈推荐所有发现这个有趣的人,并且想要确切地知道这是如何有效地探索这个之间的输出差异:

import java.util.*;

public class Test extends ArrayList<String> {
    public static void main(String[] args) {
        List raw = new Test();
        raw.add(3);
    }
}

还有这个:

import java.util.*;

public class Test extends ArrayList<String> {
    public static void main(String[] args) {
        List raw = new Test();
        raw.add(3);
    }
    public boolean add(String o) {
        return super.add(o);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.