同时 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
实现一个接口(interface),并且 - 如果异常是从接口(interface)方法抛出的,并且
- 如果接口(interface)采用类型参数,并且
- 如果类声明的类型参数包含
extends Test<T>
(如果声明为class Test<T>
则不包含第 11 行),并且 - 如果在
TestInterface
上调用该方法输入而不是Test
类型。
注意到:
- 这绝对是我抛出的异常(消息和堆栈跟踪)。
- 如果我不抛出我的,则不会抛出其他异常。
- 我用 Oracle JDK 1.7 和 1.8 在 Windows 上以及在 Ideone 上用 1.8 重现了这个。但是,1.7 在第 1 行而不是第 11 行包含一个堆栈跟踪元素(这很奇怪)。
这里发生了什么?该行如何在堆栈跟踪中结束,如果两个对象都声明为 Test
,为什么它不出现? ?
Here is the original program that prompted this ,其中 java.lang.Enum
的第 55 行如果 a
存在声明为 Comparable
但在声明为 Enum
时不存在.第55行是Enum
的声明在 JDK 源代码中,第 180 行是明确抛出的 ClassCastException
.
最佳答案
您正在查看 bridge method 的效果!
在TestInterface
中声明的test
方法有删除test(Object)
,但是在test
中声明的方法Test
有删除test(Test)
。 test(Object)
方法的方法查找不会找到 test(Test)
方法,因此 Java 实际上将单独的 test(Object)
和 test(Test)
方法在 Test
的字节码中。
您的第一次试用使用了 test(Test)
方法,它的行为符合您的预期。您的其他试验使用 test(Object)
方法,这是一种合成桥接方法,仅调用 test(Test)
方法。这个桥接方法实际上没有行号,所以它在堆栈跟踪中显示的行号相当随意,为 11。
关于java - 堆栈跟踪中的神秘行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42464475/