堆栈跟踪中的神秘线

Jas*_*n C 10 java generics exception stack-trace language-lawyer

在撰写另一个答案时调查堆栈跟踪差异时,我遇到了一个我不理解的行为.考虑以下测试程序(这是我可以缩小它的范围):

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

第11行和第13行标记在上面的代码段中,它可以在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)
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么第二个和第三个测试用例的第11行在堆栈中跟踪?三个测试用例之间的区别在于声明的类型ab.

第11行(类声明行)仅在以下条件下出现:

  1. 如果Test实现了一个接口,和
  2. 如果从接口方法抛出异常,和
  3. 如果接口采用类型参数,和
  4. 如果类声明的类型参数包含extends Test<T>(如果声明为class Test<T>,则不包括第11行),和
  5. 如果在TestInterface类型而不是Test类型上调用该方法.

注意到:

  • 绝对是我抛出的异常(消息和堆栈跟踪).
  • 如果我不扔我的话,不会抛出其他例外.
  • 我在Windows上使用Oracle JDK 1.7和1.8以及Ideone上的1.8重现了这一点.但是,1.7包含第1行的堆栈跟踪元素而不是11(这是双重奇怪的).

这里发生了什么?该行如何在堆栈跟踪中结束,为什么如果两个对象都被声明为不出现Test

这是提示这个的原始程序,java.lang.Enum如果a声明为声明为Comparable但在声明为时不存在,则存在第55行Enum.第55行是EnumJDK源中的声明,第180行是显式抛出的ClassCastException.

use*_*ica 15

你正在看桥梁方法的效果!

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.