java - 堆栈跟踪中的神秘行

标签 java generics exception language-lawyer stack-trace

同时 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 行(类声明行)仅在以下情况下出现:

  1. 如果Test实现一个接口(interface),并且
  2. 如果异常是从接口(interface)方法抛出的,并且
  3. 如果接口(interface)采用类型参数,并且
  4. 如果类声明的类型参数包含extends Test<T> (如果声明为 class Test<T> 则不包含第 11 行),并且
  5. 如果在 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/

相关文章:

macos - 核心数据抛出 NSInternalInconsistencyException "The context is still dirty after 100 attempts."

c# - C# 中的 3 个 catch block 变体( 'Catch' 、 'Catch (Exception)' 和 'Catch(Exception e)' )有什么区别?

java - DataJPATest Junit 方法命名和 NullPointerExceptions

java - 当多个线程想要访问 ReentrantReadWriteLock 时会发生什么?

java - 从单个数组 Java 中添加和减去值

c - C中的通用二叉搜索树

java - GWT 按键过滤器

typescript - 如何创建每个值的类型取决于键的查找?

Java 静态方法、通配符/通用返回类型

c++ - 向我介绍 boost::exception