无限递归的构造器和javap使用指南

无限递归的构造器和javap使用指南

public class ConstructorRecursion {

      ConstructorRecursion rc;

      {

            rc = newConstructorRecursion();

      }

      public ConstructorRecursion(){

            System.out.println("noparameter constructor");

      }

      public static void main(String[] args){

            ConstructorRecursion rc = new ConstructorRecursion();

      }

}

Exceptionin thread "main" java.lang.StackOverflowError

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

      at ConstructorRecursion.<init>(ConstructorRecursion.java:5)

表面上看,上面程序没有任何问题,ConstructorRecursion类的构造器中没有任何代码,只是单纯一句输出。但不要忘记了,不管是定义实例变量时指定的初始值,还是在非静态初始化块中执行的初始化操作,最终都将提取到构造器中执行。因为上面代码递归调用了ConstructorRecursion类的狗仔去哦,所以抛出了StackOverflowError错误。

这个程序给出的教训是:无论如何不要导致构造器产生递归调用。也就是说,应该:

尽量不要在定义实例变量时指定实例变量的值为当前类的实例;

尽量不要初始化块中创建当前类的实例;

尽量不要在构造器内调用本构造器创建Java对象;

C:\Documents andSettings\mz50947\workspace\TestProject\src>javap ConstructorRe

ursion

Compiled from"ConstructorRecursion.java"

public classConstructorRecursion extends java.lang.Object{

    ConstructorRecursion rc;

    public ConstructorRecursion();

    public static voidmain(java.lang.String[]);

}

使用JAVAP可以查看java编译器生成的字节码,通过比较字节码和源代码,可以发现很多的问题。

C:\Documents andSettings\mz50947\workspace\TestProject\src>javac -g Constructor

Recursion.java

08/08/2013  02:50 PM               645 ConstructorRecursion.class

08/08/2013  02:34 PM               304 ConstructorRecursion.java

不带参数的javap将打印类的public信息,包括成员和方法。

C:\Documents andSettings\mz50947\workspace\TestProject\src>javap -c Constructor

Recursion

Compiled from"ConstructorRecursion.java"

public classConstructorRecursion extends java.lang.Object{

ConstructorRecursionrc;

 

publicConstructorRecursion();

  Code:

   0:  aload_0

   1:  invokespecial   #1; //Methodjava/lang/Object."<init>":()V

   4:  aload_0

   5:  new     #2; //classConstructorRecursion

   8:  dup

   9:  invokespecial   #3; //Method"<init>":()V

   12: putfield        #4; //Fieldrc:LConstructorRecursion;

   15: getstatic       #5; //Fieldjava/lang/System.out:Ljava/io/PrintStream;

   18: ldc     #6; //String no parameterconstructor

   20: invokevirtual   #7; //Methodjava/io/PrintStream.println:(Ljava/lang/Str

ing;)V

   23: return

 

public static voidmain(java.lang.String[]);

  Code:

   0:  new     #2; //classConstructorRecursion

   3:  dup

   4:   invokespecial  #3; //Method "<init>":()V

   7:  astore_1

   8:  return

 

}

 

C:\Documents andSettings\mz50947\workspace\TestProject\src>javap -l Constructor

Recursion

Compiled from"ConstructorRecursion.java"

public classConstructorRecursion extends java.lang.Object{

ConstructorRecursionrc;

 

publicConstructorRecursion();

  LineNumberTable:

   line 7: 0

   line 5: 4

   line 8: 15

   line 9: 23

  LocalVariableTable:

   Start Length  Slot  Name  Signature

   0     24      0    this      LConstructorRecursion;

 

public static voidmain(java.lang.String[]);

  LineNumberTable:

   line 11: 0

   line 12: 8

  LocalVariableTable:

   Start Length  Slot  Name  Signature

   0     9      0    args      [Ljava/lang/String;

   8     1      1    rc      LConstructorRecursion;

 

}

C:\Documents andSettings\mz50947\workspace\TestProject\src>javap -c Constructor

Recursion

Compiled from"ConstructorRecursion.java"

public classConstructorRecursion extends java.lang.Object{

ConstructorRecursionrc;

 

public ConstructorRecursion();

  Code:

   0:  aload_0

   1:  invokespecial   #1; //Methodjava/lang/Object."<init>":()V

   4:  aload_0

   5:  new     #2; //classConstructorRecursion

   8:  dup

   9:  invokespecial   #3; //Method"<init>":()V

   12: putfield        #4; //Fieldrc:LConstructorRecursion;

   15: getstatic       #5; //Fieldjava/lang/System.out:Ljava/io/PrintStream;

   18: ldc     #6; //String no parameterconstructor

   20: invokevirtual   #7; //Methodjava/io/PrintStream.println:(Ljava/lang/Str

ing;)V

   23: return

 

public static voidmain(java.lang.String[]);

  Code:

   0:  new     #2; //classConstructorRecursion

   3:  dup

   4:  invokespecial   #3; //Method"<init>":()V

   7:  astore_1

   8:  return

 

}

The javap command iscalled the Java “disassembler”because it takes apart class files andtells you what’s inside them. You won’t use this command often, but using it tofind out how a particular Java statement works is fun, sometimes. You can alsouse it to find out what methods are available for a class if you don’t have thesource code that was used to create the class.

Here is the general format:

javapfilename [options]

The following is typical of the information you getwhen you run the javap command:

C:\java\samples>javapHelloApp

Compiledfrom "HelloApp.java"

publicclass HelloApp extends java.lang.Object{

    public HelloApp();

    public static voidmain(java.lang.String[]);

}

As you can see, the javap command indicates that the HelloApp class was compiled from the HelloApp.java file and that it consists of a HelloApppublic class and a mainpublic method.

You may want to use two options with the javap command. If you use the -c option, the javap command displays the actual Java bytecodes createdby the compiler for the class. (Java bytecode is the executable programcompiled from your Java source file.)

And if you use the -verbose option, the bytecodes — plus a ton of otherfascinating information about the innards of the class — are displayed. Here’sthe -c output for aclass named HelloApp:

C:\java\samples>javapHelloApp -c

Compiledfrom "HelloApp.java"

publicclass HelloApp extends java.lang.Object{

publicHelloApp();

  Code:

   0:  aload_0

   1:  invokespecial   #1; //Method

  java/lang/Object."<init>":()V

   4:  return

publicstatic void main(java.lang.String[]);

  Code:

   0:  getstatic       #2; //Field

   java/lang/System.out:Ljava/io/PrintStream;

   3:  ldc     #3; //String Hello, World!

   5:  invokevirtual   #4; //Method

   java/io/PrintStream.println:(Ljava/lang/String;)V

   8:  return

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值