NutzCN Logo
问答 jdk1.7下 运行时仅多了一个try-catch对就会抛异常
发布于 3045天前 作者 feiyan35488 2379 次浏览 复制 上一个帖子 下一个帖子
标签:

Environment: jdk1.7

javax.servlet-api-3.0.1.jar is needed for this test.

Reproduce steps:

  1. javac Test1.java -cp javax.servlet-api-3.0.1.jar build Test1.java with javax.servlet-api-3.0.1.jar

  2. javac Test2.java -cp javax.servlet-api-3.0.1.jar build Test2.java with javax.servlet-api-3.0.1.jar

  3. javac Test3.java build Test3.java

  4. But when this command java Test3 run, Exception is thrown. The result at the end of this post.
    Test1.hello()运行正常,而Test2.hello()运行失败

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

output of the final step. Test2.hello("world2") throw an exception:

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

I am very confused with the Exception. Because I didn't use any code in the Class ServletOutputStream. And the difference of the Test1 and Test2 is only a try blocked.

10 回复

我应该用中文回答还是英文? Chinese or Engish ???

得看看字节码. 但上述两段代码都不可行吧, 一般来说resp.getOutputStream()只能调用一次.

Test1类的反编译结果:

javap -c Test1.class

Compiled from "Test1.java"
public class net.wendal.nutzbook.Test1 {
  public net.wendal.nutzbook.Test1();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public void getRequest(javax.servlet.http.HttpServletResponse) throws java.io.IOException;
    Code:
       0: aload_1
       1: invokeinterface #19,  1           // InterfaceMethod javax/servlet/http/HttpServletResponse.getOutputStream:()Ljavax/servlet/ServletOutputStream;
       6: astore_2
       7: aload_1
       8: invokeinterface #19,  1           // InterfaceMethod javax/servlet/http/HttpServletResponse.getOutputStream:()Ljavax/servlet/ServletOutputStream;
      13: invokevirtual #25                 // Method javax/servlet/ServletOutputStream.close:()V
      16: return

  public void hello(java.lang.String);
    Code:
       0: getstatic     #37                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new           #43                 // class java/lang/StringBuilder
       6: dup
       7: ldc           #45                 // String hello
       9: invokespecial #47                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      12: aload_1
      13: invokevirtual #49                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: invokevirtual #53                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      19: invokevirtual #57                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: return
}

Test2的反编译结果

Compiled from "Test2.java"
public class net.wendal.nutzbook.Test2 {
  public net.wendal.nutzbook.Test2();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public void getRequest(javax.servlet.http.HttpServletResponse) throws java.io.IOException;
    Code:
       0: aload_1
       1: invokeinterface #19,  1           // InterfaceMethod javax/servlet/http/HttpServletResponse.getOutputStream:()Ljavax/servlet/ServletOutputStream;
       6: astore_2
       7: aload_1
       8: invokeinterface #19,  1           // InterfaceMethod javax/servlet/http/HttpServletResponse.getOutputStream:()Ljavax/servlet/ServletOutputStream;
      13: invokevirtual #25                 // Method javax/servlet/ServletOutputStream.close:()V
      16: goto          20
      19: astore_3
      20: return
    Exception table:
       from    to  target type
           7    16    19   Class java/lang/Exception

  public void hello(java.lang.String);
    Code:
       0: getstatic     #42                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new           #48                 // class java/lang/StringBuilder
       6: dup
       7: ldc           #50                 // String hello
       9: invokespecial #52                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      12: aload_1
      13: invokevirtual #54                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: invokevirtual #58                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      19: invokevirtual #62                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: return
}

diif

      16: goto          20
      19: astore_3
      20: return
    Exception table:
       from    to  target type
           7    16    19   Class java/lang/Exception

@wendal 还是不明白为什么Test2会报错
异常是 loadClass时抛出的,那么跟调用getOutputStream()次数是没关系的。
Test1和Test2的字节码对比,我也做过。但还是不清楚为什么会报错?

@feiyan35488 但,你的运行场景是不带那个类???

来自炫酷的 NutzCN

是这样的, jar1里包含 Test1 , 我在项目中依赖jar1, 调用Test2.hello()里报错了,按说我只有在调用Test1.getRequest()里才会报 NoClass这类异常

@wendal 是这样的, jar1里包含 Test2 , 我在项目中依赖jar1, 调用Test2.hello()里报错了,按说我只有在调用Test2.getRequest()里才会报 NoClass这类异常

@feiyan35488 每句话前都打个 log , 尤其是 getRequest 函数里,看看调用的过程咯

来自美丽的 NutzCN

@zozoh 我并没有调用getRequest方法,应该是在Test2的 initial-class阶段就出错了,so也没办法看到调用过程

添加回复
请先登陆
回到顶部