当investigating a stack trace discrepancy撰写另一个答案时,我遇到了一个我不理解的行为。考虑以下测试程序(这是我可以缩小它的范围):
interface TestInterface <U> {
void test (U u);
}
static class Test <T extends Test<T>> implements TestInterface<T> { // line 11
@Override public void test (T t) {
throw new RuntimeException("My exception"); // line 13
}
}
static class TestA extends Test<TestA> { }
static class TestB extends Test<TestB> { }
public static void main (String[] args) throws Exception {
try {
Test a = new TestA();
Test b = new TestB();
a.test(b);
} catch (Exception x) {
x.printStackTrace(System.out);
}
try {
TestInterface a = new TestA();
Test b = new TestB();
a.test(b);
} catch (Exception x) {
x.printStackTrace(System.out);
}
try {
TestInterface a = new TestA();
TestInterface b = new TestB();
a.test(b);
} catch (Exception x) {
x.printStackTrace(System.out);
}
}
第11行和第13行标在上面的代码段中,可以是run on ideone。该计划的输出是:
java.lang.RuntimeException: My exception
at Ideone$Test.test(Main.java:13)
at Ideone.main(Main.java:25)
java.lang.RuntimeException: My exception
at Ideone$Test.test(Main.java:13)
at Ideone$Test.test(Main.java:11)
at Ideone.main(Main.java:33)
java.lang.RuntimeException: My exception
at Ideone$Test.test(Main.java:13)
at Ideone$Test.test(Main.java:11)
at Ideone.main(Main.java:41)
我的问题是:为什么第二个和第三个测试用例的第11行在堆栈跟踪中?三个测试用例之间的区别在于a
和b
的声明类型。
第11行(类声明行)仅在以下条件下出现:
Test
实现了界面,extends Test<T>
(如果声明为class Test<T>
,则不包括第11行),并且TestInterface
类型而不是Test
类型上调用该方法。注意到:
这里发生了什么?该行如何在堆栈跟踪中结束?如果两个对象都声明为Test
,为什么不出现?
Here is the original program that prompted this,如果java.lang.Enum
声明为a
,则Comparable
的第55行出现,但声明为Enum
时不存在。第55行是JDK源中Enum
的声明,第180行是显式抛出的ClassCastException
。
答案 0 :(得分:13)
您正在查看bridge method的效果!
test
中声明的TestInterface
方法已删除test(Object)
,但test
中声明的Test
方法已删除test(Test)
。查找test(Object)
方法的方法将找不到test(Test)
方法,因此Java实际上在test(Object)
的字节码中放置了单独的test(Test)
和Test
方法。
您的第一次试用使用test(Test)
方法,该方法的行为符合您的预期。您的其他试验使用test(Object)
方法,这是一种只调用test(Test)
方法的合成桥接方法。这种桥接方法实际上没有行号,因此它在堆栈跟踪中显示相当任意的行号11。