环境:jdk1.7
此测试需要 javax.servlet-api-3.0.1.jar
。
重现步骤:
javac Test1.java -cp javax.servlet-api-3.0.1.jar
使用javax.servlet-api-3.0.1.jar构建Test1.java
javac Test2.java -cp javax.servlet-api-3.0.1.jar
使用javax.servlet-api-3.0.1.jar构建Test2.java
javac Test3.java
构建Test3.java
java -classpath .:javax.servlet-api-3.0.1.jar Test3
依赖运行Test3。以下是输出。好在这里。
hello world1
hello world2
但是当此命令java Test3
运行时,抛出异常。这篇文章结尾的结果。奇怪的是"你好世界1"可以打印出来,但不是打印出来" hello world2"抛出异常。
Test1.java
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
public class Test1 {
public void getRequest(HttpServletResponse resp) throws IOException {
OutputStream os = resp.getOutputStream();
resp.getOutputStream().close();
}
public void hello(String world) {
System.out.println("hello " + world);
}
}
Test2.java
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
public class Test2 {
public void getRequest(HttpServletResponse resp) throws IOException {
OutputStream os = resp.getOutputStream();
try {
resp.getOutputStream().close();
} catch (Exception e) {
}
}
public void hello(String world) {
System.out.println("hello " + world);
}
}
Test3.java
public class Test3 {
public static void main(String[] args) {
new Test1().hello("world1");
new Test2().hello("world2");
}
}
最后一步的输出。 Test2.hello(" world2")抛出异常:
hello world1
Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/ServletOutputStream
at cn.test.abc1.Test3.main(Test3.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletOutputStream
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 6 more
我对异常非常困惑。因为我没有在Class ServletOutputStream中使用任何代码。并且Test1和Test2的差异只有try
被阻止。
这个问题不是重复的问题,因为它标记了。因为当try
块涉及时,JVM不应抛出异常。
答案 0 :(得分:2)
比较javap -v -c Test?
的输出后,我得到答案
javac
try/catch
块的Test2.java
创建microsoft codedui test属性。
如果在类加载时发现StackMapTable
,JVM将执行字节码验证并检查引用的类。这就是它抛出java.lang.NoClassDefFoundError
的原因。
StackMapTable描述了有关StackMapTable
的详细信息。
我编译Test1.java并对其进行反编译,源代码变为:
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletOutputStream;
public class Test1 {
public void getRequest(HttpServletResponse resp) throws IOException {
ServletOutputStream os = resp.getOutputStream();
resp.getOutputStream().close();
}
public void hello(String world) {
System.out.println("hello " + world);
}
}
由于 resp.getOutputStream()
的返回对象为javax.servlet.ServletOutputStream
。在运行时,JVM仍然必须验证此类是java.io.OutputStream
的子类,因此它尝试加载ServletOutputStream.class
。但是JVM无法找到它并抛出ClassNotFoundException
。
答案 1 :(得分:0)
对我来说很有意义。 Test3引用了Test2和Test1,并且在运行时都需要类路径上的javax.servlet-api-3.0.1.jar
。