While 调查堆栈跟踪差异 https://stackoverflow.com/questions/42462750/why-java-enum-need-to-check-class-and-declaringclass-in-compareto-method/42462851?noredirect=1#comment72068430_42462851在撰写另一个答案时,我遇到了一种我不理解的行为。考虑以下测试程序(这是我能缩小的范围):
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 行在上面的代码片段中被标记,并且可以在ideone上运行 http://ideone.com/y0THxm。该程序的输出是:
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
and b
.
第 11 行(类声明行)仅在以下条件下出现:
- If
Test
实现一个接口,并且
- 如果异常是从接口方法抛出的,并且
- 如果接口采用类型参数,并且
- 如果类声明的类型参数包含
extends Test<T>
(如果第 11 行声明为class Test<T>
), and
- 如果该方法被调用
TestInterface
类型而不是Test
type.
注意到:
- 这绝对是我抛出的异常(消息和堆栈跟踪)。
- 如果我不抛出我的异常,则不会抛出其他异常。
- 我已使用 Oracle JDK 1.7、Windows 上的 1.8 以及 Ideone 上的 1.8 重现了此内容。然而,1.7 在第 1 行而不是第 11 行包含一个堆栈跟踪元素(这非常奇怪)。
这里发生了什么?该行如何在堆栈跟踪中结束?如果两个对象都声明为,为什么它不会出现Test
?
这是提示此问题的原始程序 http://ideone.com/5xmBHW,其中第 55 行java.lang.Enum
存在如果a
被声明为Comparable
但当它被声明为时不存在Enum
。第 55 行是声明Enum
在 JDK 源代码中,第 180 行是显式抛出的ClassCastException
.
您正在查看的效果桥接法 https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html!
The test
中声明的方法TestInterface
有擦除test(Object)
,但是test
中声明的方法Test
有擦除test(Test)
。方法查找test(Object)
方法找不到test(Test)
方法,所以Java实际上把test(Object)
and test(Test)
中的方法Test
的字节码。
您的第一次试用使用test(Test)
方法,其行为如您所料。您的其他试验使用test(Object)
方法,这是一个合成桥方法,只调用test(Test)
方法。这个桥接方法实际上没有行号,因此它在堆栈跟踪中显示为相当任意的行号 11。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)