简体   繁体   English

堆栈跟踪中的神秘线

[英]Mysterious line in stack trace

While investigating a stack trace discrepancy when composing another answer, I came across a behavior I do not understand. 在撰写另一个答案时调查堆栈跟踪差异时,我遇到了一个我不理解的行为。 Consider the following test program (this is as far down as I could narrow it): 考虑以下测试程序(这是我可以缩小它的范围):

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

}

Lines 11 and 13 are labelled in the above snippet and it can be run on ideone . 第11行和第13行标记在上面的代码段中,它可以在ideone运行 The output of that program is: 该计划的输出是:

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)

My question is: Why is line 11 in the stack trace for the second and third test cases? 我的问题是:为什么第二个和第三个测试用例的第11行在堆栈中跟踪? The difference between the three test cases there are the declared types of a and b . 三个测试用例之间的区别是声明的ab类型。

Line 11 (the class declaration line) is only present under the following conditions: 第11行(类声明行)仅在以下条件下出现:

  1. If Test implements an interface, and 如果Test实现了一个接口,那么
  2. If the exception is thrown from the interface method, and 如果从接口方法抛出异常,和
  3. If the interface takes a type parameter, and 如果接口采用类型参数,和
  4. If the class declaration's type parameter contains extends Test<T> (line 11 is not included if it is declared as class Test<T> ), and 如果类声明的类型参数包含extends Test<T> (如果声明为class Test<T> ,则不包括第11行),并且
  5. If the method is called on the TestInterface type rather than the Test type. 如果在TestInterface类型而不是Test类型上调用该方法。

Noting that: 注意到:

  • It is definitely my exception being thrown (message and stack trace). 绝对是我抛出的异常(消息和堆栈跟踪)。
  • No other exceptions are thrown if I do not throw mine. 如果我不扔我的话,不会抛出其他例外。
  • I have reproduced this with the Oracle JDK 1.7, and 1.8 on Windows, and 1.8 on Ideone. 我在Windows上使用Oracle JDK 1.7和1.8以及Ideone上的1.8重现了这一点。 However, 1.7 includes a stack trace element on line 1 instead of 11 (which is doubly weird). 但是,1.7包含第1行的堆栈跟踪元素而不是11(这是双重奇怪的)。

What is happening here? 这里发生了什么? How is that line ending up in the stack trace and why does it not appear if both objects are declared as Test ? 该行如何在堆栈跟踪中结束?如果两个对象都声明为Test ,为什么它不会出现?

Here is the original program that prompted this , where line 55 of java.lang.Enum is present if a is declared as Comparable but not present when it is declared as Enum . 这是提示这个的原始程序,如果a声明为Comparable但在声明为Enum时不存在,则存在java.lang.Enum第55行。 Line 55 is the declaration of Enum in the JDK source, line 180 is an explicitly thrown ClassCastException . 第55行是JDK源代码中的Enum声明,第180行是显式抛出的ClassCastException

You're looking at the effects of a bridge method ! 你正在看桥梁方法的效果!

The test method declared in TestInterface has erasure test(Object) , but the test method declared in Test has erasure test(Test) . TestInterface中声明的test方法具有擦除test(Object) ,但在Test中声明的test方法具有擦除test(Test) A method lookup for the test(Object) method won't find the test(Test) method, so Java actually puts separate test(Object) and test(Test) methods in Test 's bytecode. test(Object)方法的方法查找将找不到test(Test)方法,因此Java实际上在Test的字节码中放置了单独的test(Object)test(Test)方法。

Your first trial uses the test(Test) method, which behaves as you expected. 您的第一个试用版使用test(Test)方法,该方法的行为与您预期的一样。 Your other trials use the test(Object) method, which is a synthetic bridge method that just calls the test(Test) method. 您的其他试验使用test(Object)方法,该方法是一种合成桥接方法,只调用test(Test)方法。 This bridge method doesn't really have a line number, so it shows up in the stack trace with the fairly arbitrary line number of 11. 这种桥接方法实际上没有行号,因此它在堆栈跟踪中显示相当任意的行号11。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM