在类Test中实例化一个类Test的成员递归吗?

这是递归吗?

public class Test { Test test = new Test(); public static void main(String[] args) { new Test(); } } 

使用实例初始化器的版本怎么样?

 public class Test { { Test test = new Test(); } public static void main(String[] args) { new Test(); } } 

我问,因为我更新了我的旧答案 ,它显示了如何在没有递归的情况下制作StackOverflowError ,但现在我不能100%确定上面的代码是否是递归。

我的观点是它是递归。 但我无法找到赞成或反对它的好消息来源。 所以我试图将已知递归函数的汇编代码与OP中生成的java代码汇编代码进行比较。 两个汇编代码非常相似,在调用自身的方法(构造函数)时会出现问题。

我的测试代码:

 public class Test3 { void printMe() { printMe(); } public static void main(String[] args) { Test3 test = new Test3(); test.printMe(); } } 

使用以下命令打印程序集: java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -server -cp . Test3 java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -server -cp . Test3

相关汇编代码序列,显示函数调用自身:

 Decoding compiled method 0x00007f2e2910ac90: Code: [Entry Point] [Constants] # {method} {0x00007f2e27121230} 'printMe' '()V' in 'com/vs/soutils/Test3' # [sp+0x40] (sp of caller) 0x00007f2e2910ae00: mov 0x8(%rsi),%r10d 0x00007f2e2910ae04: shl $0x3,%r10 0x00007f2e2910ae08: cmp %rax,%r10 0x00007f2e2910ae0b: jne 0x00007f2e29045b60 ; {runtime_call} 0x00007f2e2910ae11: nopw 0x0(%rax,%rax,1) 0x00007f2e2910ae1c: xchg %ax,%ax [Verified Entry Point] 0x00007f2e2910ae20: mov %eax,-0x14000(%rsp) 0x00007f2e2910ae27: push %rbp 0x00007f2e2910ae28: sub $0x30,%rsp 0x00007f2e2910ae2c: mov $0x7f2e271213f8,%rdi ; {metadata(method data for {method} {0x00007f2e27121230} 'printMe' '()V' in 'com/vs/soutils/Test3')} 0x00007f2e2910ae36: mov 0x64(%rdi),%ebx 0x00007f2e2910ae39: add $0x8,%ebx 0x00007f2e2910ae3c: mov %ebx,0x64(%rdi) 0x00007f2e2910ae3f: mov $0x7f2e27121230,%rdi ; {metadata({method} {0x00007f2e27121230} 'printMe' '()V' in 'com/vs/soutils/Test3')} 0x00007f2e2910ae49: and $0x1ff8,%ebx 0x00007f2e2910ae4f: cmp $0x0,%ebx 0x00007f2e2910ae52: je 0x00007f2e2910aec0 ;*aload_0 ; - com.vs.soutils.Test3::printMe@0 (line 6) 0x00007f2e2910ae58: mov %rsi,%rdi 0x00007f2e2910ae5b: mov $0x7f2e271213f8,%rbx ; {metadata(method data for {method} {0x00007f2e27121230} 'printMe' '()V' in 'com/vs/soutils/Test3')} 0x00007f2e2910ae65: addq $0x1,0xa0(%rbx) 0x00007f2e2910ae6d: mov $0x7f2e271213f8,%rdi ; {metadata(method data for {method} {0x00007f2e27121230} 'printMe' '()V' in 'com/vs/soutils/Test3')} 0x00007f2e2910ae77: mov 0x64(%rdi),%ebx 0x00007f2e2910ae7a: add $0x8,%ebx 0x00007f2e2910ae7d: mov %ebx,0x64(%rdi) 0x00007f2e2910ae80: mov $0x7f2e27121230,%rdi ; {metadata({method} {0x00007f2e27121230} 'printMe' '()V' in 'com/vs/soutils/Test3')} 0x00007f2e2910ae8a: and $0x7ffff8,%ebx 0x00007f2e2910ae90: cmp $0x0,%ebx 0x00007f2e2910ae93: je 0x00007f2e2910aed4 0x00007f2e2910ae99: mov %rsi,%rdi 0x00007f2e2910ae9c: mov $0x7f2e271213f8,%rbx ; {metadata(method data for {method} {0x00007f2e27121230} 'printMe' '()V' in 'com/vs/soutils/Test3')} 0x00007f2e2910aea6: addq $0x1,0xa0(%rbx) 0x00007f2e2910aeae: nop 0x00007f2e2910aeaf: callq 0x00007f2e29045d60 ; OopMap{off=180} ;*invokevirtual printMe ; - com.vs.soutils.Test3::printMe@1 (line 6) ; - com.vs.soutils.Test3::printMe@1 (line 6) ; {optimized virtual_call} 0x00007f2e2910aeb4: add $0x30,%rsp 0x00007f2e2910aeb8: pop %rbp 0x00007f2e2910aeb9: test %eax,0x16461241(%rip) # 0x00007f2e3f56c100 ; {poll_return} 0x00007f2e2910aebf: retq 0x00007f2e2910aec0: mov %rdi,0x8(%rsp) 0x00007f2e2910aec5: movq $0xffffffffffffffff,(%rsp) 0x00007f2e2910aecd: callq 0x00007f2e290fdde0 ; OopMap{rsi=Oop off=210} ;*synchronization entry ; - com.vs.soutils.Test3::printMe@-1 (line 6) ; {runtime_call} 0x00007f2e2910aed2: jmp 0x00007f2e2910ae58 0x00007f2e2910aed4: mov %rdi,0x8(%rsp) 0x00007f2e2910aed9: movq $0xffffffffffffffff,(%rsp) 0x00007f2e2910aee1: callq 0x00007f2e290fdde0 ; OopMap{rsi=Oop off=230} ;*synchronization entry ; - com.vs.soutils.Test3::printMe@-1 (line 6) ; - com.vs.soutils.Test3::printMe@1 (line 6) ; {runtime_call} 0x00007f2e2910aee6: jmp 0x00007f2e2910ae99 0x00007f2e2910aee8: nop 0x00007f2e2910aee9: nop 0x00007f2e2910aeea: mov 0x288(%r15),%rax 0x00007f2e2910aef1: mov $0x0,%r10 0x00007f2e2910aefb: mov %r10,0x288(%r15) 0x00007f2e2910af02: mov $0x0,%r10 0x00007f2e2910af0c: mov %r10,0x290(%r15) 0x00007f2e2910af13: add $0x30,%rsp 0x00007f2e2910af17: pop %rbp 0x00007f2e2910af18: jmpq 0x00007f2e2906be20 ; {runtime_call} 

现在将它与原始代码的汇编代码进行比较:

  Decoding compiled method 0x00007fea24ef0dd0: Code: [Entry Point] [Constants] # {method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test' # [sp+0x80] (sp of caller) 0x00007fea24ef0f60: mov 0x8(%rsi),%r10d 0x00007fea24ef0f64: shl $0x3,%r10 0x00007fea24ef0f68: cmp %rax,%r10 0x00007fea24ef0f6b: jne 0x00007fea24e29b60 ; {runtime_call} 0x00007fea24ef0f71: nopw 0x0(%rax,%rax,1) 0x00007fea24ef0f7c: xchg %ax,%ax [Verified Entry Point] 0x00007fea24ef0f80: mov %eax,-0x14000(%rsp) 0x00007fea24ef0f87: push %rbp 0x00007fea24ef0f88: sub $0x70,%rsp 0x00007fea24ef0f8c: mov $0x7fea22943350,%rdx ; {metadata(method data for {method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef0f96: mov 0x64(%rdx),%edi 0x00007fea24ef0f99: add $0x8,%edi 0x00007fea24ef0f9c: mov %edi,0x64(%rdx) 0x00007fea24ef0f9f: mov $0x7fea229431b0,%rdx ; {metadata({method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef0fa9: and $0x1ff8,%edi 0x00007fea24ef0faf: cmp $0x0,%edi 0x00007fea24ef0fb2: je 0x00007fea24ef1172 ;*aload_0 ; - com.vs.soutils.Test::@0 (line 3) 0x00007fea24ef0fb8: mov %rsi,%rdx 0x00007fea24ef0fbb: mov $0x7fea22943350,%rdi ; {metadata(method data for {method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef0fc5: addq $0x1,0x90(%rdi) 0x00007fea24ef0fcd: mov $0x7fea226a1f10,%rdx ; {metadata(method data for {method} {0x00007fea22543488} '' '()V' in 'java/lang/Object')} 0x00007fea24ef0fd7: mov 0x64(%rdx),%edi 0x00007fea24ef0fda: add $0x8,%edi 0x00007fea24ef0fdd: mov %edi,0x64(%rdx) 0x00007fea24ef0fe0: mov $0x7fea22543488,%rdx ; {metadata({method} {0x00007fea22543488} '' '()V' in 'java/lang/Object')} 0x00007fea24ef0fea: and $0x7ffff8,%edi 0x00007fea24ef0ff0: cmp $0x0,%edi 0x00007fea24ef0ff3: je 0x00007fea24ef1189 0x00007fea24ef0ff9: mov $0x7c0060028,%rdx ; {metadata('com/vs/soutils/Test')} 0x00007fea24ef1003: mov %rsi,0x58(%rsp) 0x00007fea24ef1008: mov 0x60(%r15),%rax 0x00007fea24ef100c: lea 0x10(%rax),%rdi 0x00007fea24ef1010: cmp 0x70(%r15),%rdi 0x00007fea24ef1014: ja 0x00007fea24ef11a0 0x00007fea24ef101a: mov %rdi,0x60(%r15) 0x00007fea24ef101e: mov 0xa8(%rdx),%rcx 0x00007fea24ef1025: mov %rcx,(%rax) 0x00007fea24ef1028: mov %rdx,%rcx 0x00007fea24ef102b: shr $0x3,%rcx 0x00007fea24ef102f: mov %ecx,0x8(%rax) 0x00007fea24ef1032: xor %rcx,%rcx 0x00007fea24ef1035: mov %ecx,0xc(%rax) 0x00007fea24ef1038: xor %rcx,%rcx ;*new ; - com.vs.soutils.Test::@5 (line 5) 0x00007fea24ef103b: mov %rax,%rdx 0x00007fea24ef103e: mov $0x7fea22943350,%rsi ; {metadata(method data for {method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef1048: addq $0x1,0xa0(%rsi) 0x00007fea24ef1050: mov $0x7fea22943350,%rdx ; {metadata(method data for {method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef105a: mov 0x64(%rdx),%esi 0x00007fea24ef105d: add $0x8,%esi 0x00007fea24ef1060: mov %esi,0x64(%rdx) 0x00007fea24ef1063: mov $0x7fea229431b0,%rdx ; {metadata({method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef106d: and $0x7ffff8,%esi 0x00007fea24ef1073: cmp $0x0,%esi 0x00007fea24ef1076: je 0x00007fea24ef11ad 0x00007fea24ef107c: mov %rax,%rdx 0x00007fea24ef107f: mov $0x7fea22943350,%rsi ; {metadata(method data for {method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef1089: addq $0x1,0x90(%rsi) 0x00007fea24ef1091: mov $0x7fea226a1f10,%rdx ; {metadata(method data for {method} {0x00007fea22543488} '' '()V' in 'java/lang/Object')} 0x00007fea24ef109b: mov 0x64(%rdx),%esi 0x00007fea24ef109e: add $0x8,%esi 0x00007fea24ef10a1: mov %esi,0x64(%rdx) 0x00007fea24ef10a4: mov $0x7fea22543488,%rdx ; {metadata({method} {0x00007fea22543488} '' '()V' in 'java/lang/Object')} 0x00007fea24ef10ae: and $0x7ffff8,%esi 0x00007fea24ef10b4: cmp $0x0,%esi 0x00007fea24ef10b7: je 0x00007fea24ef11c4 0x00007fea24ef10bd: mov $0x7c0060028,%rdx ; {metadata('com/vs/soutils/Test')} 0x00007fea24ef10c7: mov %rax,0x50(%rsp) 0x00007fea24ef10cc: mov 0x60(%r15),%rax 0x00007fea24ef10d0: lea 0x10(%rax),%rdi 0x00007fea24ef10d4: cmp 0x70(%r15),%rdi 0x00007fea24ef10d8: ja 0x00007fea24ef11db 0x00007fea24ef10de: mov %rdi,0x60(%r15) 0x00007fea24ef10e2: mov 0xa8(%rdx),%rcx 0x00007fea24ef10e9: mov %rcx,(%rax) 0x00007fea24ef10ec: mov %rdx,%rcx 0x00007fea24ef10ef: shr $0x3,%rcx 0x00007fea24ef10f3: mov %ecx,0x8(%rax) 0x00007fea24ef10f6: xor %rcx,%rcx 0x00007fea24ef10f9: mov %ecx,0xc(%rax) 0x00007fea24ef10fc: xor %rcx,%rcx ;*new ; - com.vs.soutils.Test::@5 (line 5) ; - com.vs.soutils.Test::@9 (line 5) 0x00007fea24ef10ff: mov %rax,%rsi 0x00007fea24ef1102: mov $0x7fea22943350,%rdi ; {metadata(method data for {method} {0x00007fea229431b0} '' '()V' in 'com/vs/soutils/Test')} 0x00007fea24ef110c: addq $0x1,0xa0(%rdi) 0x00007fea24ef1114: mov %rax,%rsi ;*invokespecial  ; - com.vs.soutils.Test::@9 (line 5) ; - com.vs.soutils.Test::@9 (line 5) 0x00007fea24ef1117: mov %rax,0x48(%rsp) 0x00007fea24ef111c: nop 0x00007fea24ef111d: nop 0x00007fea24ef111e: nop 0x00007fea24ef111f: callq 0x00007fea24e29d60 ; OopMap{[72]=Oop [80]=Oop [88]=Oop off=452} ;*invokespecial  ; - com.vs.soutils.Test::@9 (line 5) ; - com.vs.soutils.Test::@9 (line 5) ; {optimized virtual_call} 0x00007fea24ef1124: mov 0x48(%rsp),%rsi 0x00007fea24ef1129: mov 0x50(%rsp),%rax 0x00007fea24ef112e: mov %rsi,%r10 0x00007fea24ef1131: shr $0x3,%r10 0x00007fea24ef1135: mov %r10d,0xc(%rax) 0x00007fea24ef1139: mov %rax,%rsi 0x00007fea24ef113c: shr $0x9,%rsi 0x00007fea24ef1140: mov $0x7fea20c23000,%rdi 0x00007fea24ef114a: movb $0x0,(%rsi,%rdi,1) ;*putfield test ; - com.vs.soutils.Test::@12 (line 5) ; - com.vs.soutils.Test::@9 (line 5) 0x00007fea24ef114e: mov 0x58(%rsp),%rsi 0x00007fea24ef1153: mov %rax,%r10 0x00007fea24ef1156: shr $0x3,%r10 0x00007fea24ef115a: mov %r10d,0xc(%rsi) 0x00007fea24ef115e: shr $0x9,%rsi 0x00007fea24ef1162: movb $0x0,(%rsi,%rdi,1) ;*putfield test ; - com.vs.soutils.Test::@12 (line 5) 0x00007fea24ef1166: add $0x70,%rsp 0x00007fea24ef116a: pop %rbp 0x00007fea24ef116b: test %eax,0x15e21f8f(%rip) # 0x00007fea3ad13100 ; {poll_return} 0x00007fea24ef1171: retq 0x00007fea24ef1172: mov %rdx,0x8(%rsp) 0x00007fea24ef1177: movq $0xffffffffffffffff,(%rsp) 0x00007fea24ef117f: callq 0x00007fea24ee1d20 ; OopMap{rsi=Oop off=548} ;*synchronization entry ; - com.vs.soutils.Test::@-1 (line 3) ; {runtime_call} 0x00007fea24ef1184: jmpq 0x00007fea24ef0fb8 0x00007fea24ef1189: mov %rdx,0x8(%rsp) 0x00007fea24ef118e: movq $0xffffffffffffffff,(%rsp) 0x00007fea24ef1196: callq 0x00007fea24ee1d20 ; OopMap{rsi=Oop off=571} ;*synchronization entry ; - java.lang.Object::@-1 (line 37) ; - com.vs.soutils.Test::@1 (line 3) ; {runtime_call} 0x00007fea24ef119b: jmpq 0x00007fea24ef0ff9 0x00007fea24ef11a0: mov %rdx,%rdx 0x00007fea24ef11a3: callq 0x00007fea24edda60 ; OopMap{[88]=Oop off=584} ;*new ; - com.vs.soutils.Test::@5 (line 5) ; {runtime_call} 0x00007fea24ef11a8: jmpq 0x00007fea24ef103b 0x00007fea24ef11ad: mov %rdx,0x8(%rsp) 0x00007fea24ef11b2: movq $0xffffffffffffffff,(%rsp) 0x00007fea24ef11ba: callq 0x00007fea24ee1d20 ; OopMap{[88]=Oop rax=Oop off=607} ;*synchronization entry ; - com.vs.soutils.Test::@-1 (line 3) ; - com.vs.soutils.Test::@9 (line 5) ; {runtime_call} 0x00007fea24ef11bf: jmpq 0x00007fea24ef107c 0x00007fea24ef11c4: mov %rdx,0x8(%rsp) 0x00007fea24ef11c9: movq $0xffffffffffffffff,(%rsp) 0x00007fea24ef11d1: callq 0x00007fea24ee1d20 ; OopMap{[88]=Oop rax=Oop off=630} ;*synchronization entry ; - java.lang.Object::@-1 (line 37) ; - com.vs.soutils.Test::@1 (line 3) ; - com.vs.soutils.Test::@9 (line 5) ; {runtime_call} 0x00007fea24ef11d6: jmpq 0x00007fea24ef10bd 0x00007fea24ef11db: mov %rdx,%rdx 0x00007fea24ef11de: callq 0x00007fea24edda60 ; OopMap{[88]=Oop [80]=Oop off=643} ;*new ; - com.vs.soutils.Test::@5 (line 5) ; - com.vs.soutils.Test::@9 (line 5) ; {runtime_call} 0x00007fea24ef11e3: jmpq 0x00007fea24ef10ff 0x00007fea24ef11e8: nop 0x00007fea24ef11e9: nop 0x00007fea24ef11ea: mov 0x288(%r15),%rax 0x00007fea24ef11f1: mov $0x0,%r10 0x00007fea24ef11fb: mov %r10,0x288(%r15) 0x00007fea24ef1202: mov $0x0,%r10 0x00007fea24ef120c: mov %r10,0x290(%r15) 0x00007fea24ef1213: add $0x70,%rsp 0x00007fea24ef1217: pop %rbp 0x00007fea24ef1218: jmpq 0x00007fea24edcce0 ; {runtime_call} 0x00007fea24ef121d: hlt 

我们看到一遍又一遍地调用构造函数。 这解释了堆栈溢出,并且似乎是递归的。

是的。 您在无限循环中创建对象,最终得到StackOverflow

“递归是一种可以在Java中使用的基本编程技术,其中一个方法调用自身来解决一些问题。使用这种技术的方法是递归的。许多编程问题只能通过递归来解决,还有一些问题可以解决其他技术可以通过递归更好地解决。“ – 链接

dictionary.reference.com – “通过重复应用算法来定义函数或计算数字的过程。” – 链接

根据递归的这个定义,这不是递归。 原因是你没有调用自身的方法,在这种情况下全局对象被自动实例化,因为它在全局范围内,并且该对象在其实例化的全局范围内有一个对象……

如果你注意到这个定义也提到“解决一些问题”在这种情况下,你没有解决问题。

dictionary.reference.com定义说“重复应用算法”(即方法),因此它也暗示这不是递归。

你的情况是一个方法不是自己调用每次创建一个新实例,即。 一个新的默认构造函数,它是一个不同的方法,它不属于一个单独的对象/实例。

这是递归调用,如下所述

  1. 主方法线程执行new Test();
  2. 在默认构造函数调用类之前,将初始化实例变量。
  3. 实例变量初始值设定项将再次调用默认构造函数。
  4. 它在调用默认构造函数之前再次调用实例变量初始化。
  5. 这就是它重复这个过程的方式(转到第3步)

以下示例显示实例变量初始化在默认构造函数调用之前运行

  public class Test { private A a = new A(); public Test() { System.out.println("Default constructor called"); } public static void main(String[] args) { new Test(); } class A { A() { System.out.println("A's Constructor called"); } } } 

输出:

 A's Constructor called Default constructor called