堆栈跟踪中的神秘线路 [英] Mysterious line in stack trace

查看:125
本文介绍了堆栈跟踪中的神秘线路的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然在撰写另一个答案时调查堆栈跟踪差异,我遇到了一个我不明白的行为。考虑下面的测试程序(这可以尽量缩小它):

  interface TestInterface< U> {
void test(U u);
}

static class Test< T extends Test< T>>实现TestInterface< T> {//第11行
@Override public void test(T t){
throw new RuntimeException(My exception); //第13行
}
}

静态类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);
}

尝试{
TestInterface a = new TestA();
Test b = new TestB();
a.test(b);
} catch(Exception x){
x.printStackTrace(System.out);
}

尝试{
TestInterface a = new TestA();
TestInterface b = new TestB();
a.test(b);
} catch(Exception x){
x.printStackTrace(System.out);
}

}

第11行和第13行标记为上面的代码片段,它可以在ideone上运行。该程序的输出是:

  java.lang.RuntimeException:我的异常
在Ideone $ Test.test( Main.java:13)
在Ideone.main(Main.java:25)
java.lang.RuntimeException:我的异常
在Ideone $ Test.test(Main.java:13)
在Ideone $ Test.test(Main.java:11)​​
在Ideone.main(Main.java:33)
java.lang.RuntimeException:我的异常
在Ideone $ Test.test(Main.java:13)
在Ideone $ Test.test(Main.java:11)​​
在Ideone.main(Main.java:41)

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



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


  1. 如果 Test 实现一个接口,并且

  2. 如果从接口方法抛出异常,并且

  3. If如果类声明的类型参数包含 extends Test< T> (不包含第11行)如果它被声明为 class Test< T> ),并且

  4. 如果在 TestInterface 类型而不是 Test 类型。

注意到:


  • 这肯定是我抛出的异常(消息和堆栈跟踪)。

  • 如果我不抛出其他异常,则抛出它。

  • 我已经使用Oracle JDK 1.7重现了这一点,在Windows上是1.8,在Ideone上是1.8。但是,1.7在第1行中包含堆栈跟踪元素,而不是11(这很奇怪)。这条线如何在堆栈跟踪中结束,以及为什么当两个对象都声明为 Test



    这是提示的原始程序,其中 java.lang的第55行如果 a 被声明为 Comparable ,但在声明时不存在,则Enum 存在作为 Enum 。第55行是JDK源代码中 Enum 的声明,第180行是一个明确抛出的 ClassCastException

    解决方案

    您正在查看 bridge method



    test TestInterface 中声明的方法已经擦除 test(Object),但是 test Test 中声明的$ c>方法已经擦除 test(Test)。方法查找 test(Object)方法不会找到 test(Test)方法,所以Java实际上在 Test 中放入单独的 test(Object) test(Test)

    你的第一个试验使用 test(Test)方法,它的行为和你一样预期。您的其他试验使用 test(Object)方法,该方法是一种仅调用 test(Test)的合成桥接方法>方法。这个桥接方法并没有真正的行号,所以它在堆栈跟踪中显示出相当任意的行数11。


    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. 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? The difference between the three test cases there are the declared types of a and b.

    Line 11 (the class declaration line) is only present under the following conditions:

    1. If Test implements an interface, and
    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
    5. If the method is called on the TestInterface type rather than the Test type.

    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. However, 1.7 includes a stack trace element on line 1 instead of 11 (which is doubly weird).

    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?

    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. Line 55 is the declaration of Enum in the JDK source, line 180 is an explicitly thrown 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). 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.

    Your first trial uses the test(Test) method, which behaves as you expected. Your other trials use the test(Object) method, which is a synthetic bridge method that just calls the test(Test) method. 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.

    这篇关于堆栈跟踪中的神秘线路的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆