雖然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
類型上調用該方法。
注意到:
- 它肯定是被拋出異常我(消息和堆棧跟蹤)。
- 如果我不拋棄我的話,不會拋出其他異常。
- 我已經在Windows上使用了Oracle JDK 1.7和1.8以及Ideone上的1.8。但是,1.7在第1行中包含堆棧跟蹤元素,而不是11(這是非常奇怪的)。
這裏發生了什麼?這條線如何在堆棧跟蹤中結束,以及爲什麼在兩個對象都聲明爲Test
時不會出現?
Here is the original program that prompted this,其中的java.lang.Enum
線55是本如果a
聲明爲Comparable
但是當它被聲明爲Enum
不存在。第55行是JDK源中的Enum
的聲明,第180行是明確拋出的ClassCastException
。