Java 堆栈跟踪中的神秘位置
Mysterious Location in Java stack trace
就像下面的例子,当我运行测试用例testSortArrayNull()
在测试class中命名为ComparatorAbstractTestCase
时,一个RuntimeException 被抛出,生成的堆栈跟踪如下,
这是堆栈跟踪的结果,
testSortArrayNull(org.apache.commons.io.comparator.CompositeFileComparatorTest) Time elapsed: 0.016 sec <<< ERROR!
java.lang.RuntimeException: null
at org.apache.commons.io.comparator.AbstractFileComparator.sort(AbstractFileComparator.java:48)
at org.apache.commons.io.comparator.CompositeFileComparator.sort(CompositeFileComparator.java:45)
at org.apache.commons.io.comparator.ComparatorAbstractTestCase.testSortArrayNull(ComparatorAbstractTestCase.java:96)
...
这里是测试的部分代码class ComparatorAbstractTestCase
,
public abstract class ComparatorAbstractTestCase extends FileBasedTestCase {
/** comparator instance */
protected CompositeFileComparator comparator;
...
@Test
public void testSortArrayNull() {
assertNull(comparator.sort((File[])null)); /** LINE 96 */
}
...
}
这里是classCompositeFileComparator
的部分代码,用classAbstractFileComparator
.
扩展
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CompositeFileComparator extends AbstractFileComparator implements Serializable { /** LINE 45 */
... // no sort() method
}
这里是 class AbstractFileComparator
的部分代码,其中有 sort()
方法。
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
abstract class AbstractFileComparator implements Comparator<File> {
public File[] sort(final File... files) {
if (files != null) {
Arrays.sort(files, this);
}
if (files == null) {
throw new RuntimeException(); /** LINE 48 */
}
return null;
}
...
}
从上面3个代码片段可以看出,classCompositeFileComparator
中的第45行是class声明的位置,为什么stack trace会定位到这个神秘的位置呢?第 45 行出现在堆栈跟踪中是否有意义?感谢大家的热心帮助:)
这是因为您的 class AbstractFileComparator
具有仅限包的访问权限。即使里面的sort
方法是public
,也不能从包外引用。
为了让其他代码通过publicsubclassCompositeFileComparator
访问sort
方法,方法sort
被编译里面重新声明CompositeFileComparator
。这是您的源文件中不存在的合成 Java 代码,因此编译器必须为其选择一个行号。
您使用的编译器选择了 class 声明的行号。其他编译器(例如我特定版本的 Eclipse 中的编译器)选择行号 1。由于该方法在您的源代码中并不真正存在,因此行号没有意义。
编译器生成的方法只会调用该方法的超级class版本。
如果您不希望这种情况发生,您可以将 AbstractFileComparator
设置为 public
class。
就像下面的例子,当我运行测试用例testSortArrayNull()
在测试class中命名为ComparatorAbstractTestCase
时,一个RuntimeException 被抛出,生成的堆栈跟踪如下,
这是堆栈跟踪的结果,
testSortArrayNull(org.apache.commons.io.comparator.CompositeFileComparatorTest) Time elapsed: 0.016 sec <<< ERROR!
java.lang.RuntimeException: null
at org.apache.commons.io.comparator.AbstractFileComparator.sort(AbstractFileComparator.java:48)
at org.apache.commons.io.comparator.CompositeFileComparator.sort(CompositeFileComparator.java:45)
at org.apache.commons.io.comparator.ComparatorAbstractTestCase.testSortArrayNull(ComparatorAbstractTestCase.java:96)
...
这里是测试的部分代码class ComparatorAbstractTestCase
,
public abstract class ComparatorAbstractTestCase extends FileBasedTestCase {
/** comparator instance */
protected CompositeFileComparator comparator;
...
@Test
public void testSortArrayNull() {
assertNull(comparator.sort((File[])null)); /** LINE 96 */
}
...
}
这里是classCompositeFileComparator
的部分代码,用classAbstractFileComparator
.
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CompositeFileComparator extends AbstractFileComparator implements Serializable { /** LINE 45 */
... // no sort() method
}
这里是 class AbstractFileComparator
的部分代码,其中有 sort()
方法。
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
abstract class AbstractFileComparator implements Comparator<File> {
public File[] sort(final File... files) {
if (files != null) {
Arrays.sort(files, this);
}
if (files == null) {
throw new RuntimeException(); /** LINE 48 */
}
return null;
}
...
}
从上面3个代码片段可以看出,classCompositeFileComparator
中的第45行是class声明的位置,为什么stack trace会定位到这个神秘的位置呢?第 45 行出现在堆栈跟踪中是否有意义?感谢大家的热心帮助:)
这是因为您的 class AbstractFileComparator
具有仅限包的访问权限。即使里面的sort
方法是public
,也不能从包外引用。
为了让其他代码通过publicsubclassCompositeFileComparator
访问sort
方法,方法sort
被编译里面重新声明CompositeFileComparator
。这是您的源文件中不存在的合成 Java 代码,因此编译器必须为其选择一个行号。
您使用的编译器选择了 class 声明的行号。其他编译器(例如我特定版本的 Eclipse 中的编译器)选择行号 1。由于该方法在您的源代码中并不真正存在,因此行号没有意义。
编译器生成的方法只会调用该方法的超级class版本。
如果您不希望这种情况发生,您可以将 AbstractFileComparator
设置为 public
class。