【问题标题】:Mysterious line in stack trace堆栈跟踪中的神秘行
【发布时间】:2017-07-16 19:27:10
【问题描述】:

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

}

上面的sn-p中标记了第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 行?三个测试用例的区别在于ab的声明类型。

第 11 行(类声明行)仅在以下情况下出现:

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

注意:

  • 肯定是我的异常被抛出(消息和堆栈跟踪)。
  • 如果我不抛出我的,则不会抛出其他异常。
  • 我已经在 Oracle JDK 1.7 和 Windows 上的 1.8 和 Ideone 上的 1.8 上复制了这个。但是,1.7 在第 1 行而不是第 11 行包含堆栈跟踪元素(这很奇怪)。

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

Here is the original program that prompted this,如果a 被声明为Comparable,则java.lang.Enum 的第55 行存在,但在它被声明为Enum 时不存在。第55行是JDK源码中Enum的声明,第180行是显式抛出的ClassCastException

【问题讨论】:

    标签: java generics exception language-lawyer stack-trace


    【解决方案1】:

    您正在查看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 显示。

    【讨论】:

      猜你喜欢
      • 2019-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-15
      • 1970-01-01
      • 2011-05-25
      相关资源
      最近更新 更多