2
class car{
    Salon s ;
}
class Salon{
     Radio musicsystem ;
}
class Radio{
    Button play ;
}
class Button{
     String s ;
}

void main(){
    car mustang = new car( new Salon( new Radio(new Button ("fight club song"))))
}

I can easily imagine there is lots new(new (new(new ....) )). How deep can you go? I "intuitively" feel it can be bad for the compiler/jvm/system to have too many levels of objects...

Does java have restriction on depth?

ERJAN
  • 23,696
  • 23
  • 72
  • 146

5 Answers5

6

A satisfactory answer should be, You can go much deeper than you'll ever want to see actually happen in your code.

If you want to entertain the limits just for the fun of it, I believe that the first limit you will in fact hit is the limit on the length of the bytecode of a single method, which is set at a very low 64K.

The only way to truly worry about hitting the limit is when you have recursive constructor calls, such as you might have when constructing an immutable linked list or a similar structure.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Wouldn't this apply? http://stackoverflow.com/questions/4734108/what-is-the-maximum-depth-of-the-java-call-stack – Jason Sperske Feb 25 '14 at 19:13
  • @JasonSperske No, the call stack for all these `news` is still just one (unless they themselves call methods inside their constructors). – Thorn G Feb 25 '14 at 19:13
  • 1
    @TomG But, in a slightly different scenario, such as I mention, `new` will be called from *within* the constructor, and then it does apply. – Marko Topolnik Feb 25 '14 at 19:14
  • @MarkoTopolnik Correct, that's what I mean by saying unless those constructors continue to invoke methods. But providing an **argument** via method call will not increase the call stack, because the method that provides the argument already returned once the constructor is invoked. – Thorn G Feb 25 '14 at 19:16
  • So it isn't the `new`s that you would worry about but the recursive method arguments? – Jason Sperske Feb 25 '14 at 19:17
  • @JasonSperske Since the heap is enormous compared to the stack, I would assume I don't have to worry about it. – Marko Topolnik Feb 25 '14 at 19:20
2

The compiler has a limitation of 64 KB for a single method. This is born from the fact that a jump can only go to an absolution byte code position and uses a 16-bit unsigned value. The limitation applies even if you don't have a such a jump.

This has a some surprising consequences. While you might not want to have thousands of nested objects defined this way, you might have a generated class with say thousands of ENUM values. These values are created in one static initialiser method and this also has the same limitation, so you can only have about 3K enum values.

A more likely limitation is large arrays. When you define an array, it actually generates code to set each and every cell. This is pretty inefficient, but general. It also means you can't define an array in Java, with initialised values, with say 10K hard coded values. Again, this is really only a problem for generated code.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    So one could theoretically get away with a method of any size, provided there are no jumps in it? Array and enum filling do seem like exactly such a case. I have also heard that `javac` could be enhanced to automatically generate a call chain of methods, each properly sized. – Marko Topolnik Feb 25 '14 at 19:28
  • @MarkoTopolnik A chain of method makes more sense as methods large than 8K are never JITted by default. What would make even more sense is for the JVM to lift the limitation in the byte code. ;) – Peter Lawrey Feb 25 '14 at 19:32
  • But that would require a complete redesign of bytecode---probably not worth the trouble given the number of use cases which are truly stopped dead due to this. – Marko Topolnik Feb 25 '14 at 19:40
  • @MarkoTopolnik You just need another branch instruction which uses a 32-bit (even a 24-bit) location. You wouldn't need to change existing instructions. There is a plenty of unused byte code combinations. – Peter Lawrey Feb 25 '14 at 19:42
  • 1
    There is other stuff like `start_pc` and `end_pc` attributes, which also accept 16-bit array indices. But I don't think that's the primary point---the point is not touching bytecode at all without a very serious reason, such as `invokedynamic`---which may be the *only* instruction ever introduced since Java 1.0. – Marko Topolnik Feb 25 '14 at 19:45
  • 1
    @MarkoTopolnik true, there might need to be a few changes, but I think widening the type for a new class version format is a relatively simple change. Getting any change into the JVM is the challenge. – Peter Lawrey Feb 25 '14 at 19:48
2

No, this is no problem at all, especially not at human readable levels like yours.

Let's look at the limits, though. Code like this:

public class Foo {
  public Foo(Foo f) {}
  public static void main(String[] args) {
    new Foo(new Foo(new Foo(new Foo(null))));
  }
}

compiles into:

public static void main(java.lang.String[]);
Code:
   0: new           #2                  // class Foo
   3: dup           
   4: new           #2                  // class Foo
   7: dup           
   8: new           #2                  // class Foo
  11: dup           
  12: new           #2                  // class Foo
  15: dup           
  16: aconst_null   
  17: invokespecial #3                  // Method "<init>":(LFoo;)V
  20: invokespecial #3                  // Method "<init>":(LFoo;)V
  23: invokespecial #3                  // Method "<init>":(LFoo;)V
  26: invokespecial #3                  // Method "<init>":(LFoo;)V
  29: pop           
  30: return     

i.e. for each nesting, it just uses two or more elements on the operand stack: the class to instantiate, the nested object, and any other variables passed along with it.

The maximum size of the operand stack is implementation specific, but any JVM will certainly be able to hold several thousand variables and operate on them with efficiency. For comparison, javac crashes after just 1000 nesting.

So no, your four level deep nesting is absolutely no problem for the JVM.

that other guy
  • 116,971
  • 11
  • 170
  • 194
1

Size of your heap memory.When the memory gets full or GC cannot collect objects,it throws java.lang.OutOfMemoryError

So as long as you have memory,it is not an issue

Kumar Abhinav
  • 6,565
  • 2
  • 24
  • 35
1

Really, this is no different than writing:

Button button = new Button ("fight club song");
Radio radio = new Radio(button);
Salon salon = new Salon(radio);
car mustang = new car(salon);

The only difference is you're not assigning a variable to each reference, so you can't refer to them later. So, the answer is, as long as you have enough memory to instantiate these objects, you can create as many as you wish.

This isn't really an issue of nesting, or levels deep, as the compiler calls each constructor, initializes the object, then returns a reference to the initialized object. There's no recursion happening here, nor is the stack growing with each level.

Mike Christensen
  • 88,082
  • 50
  • 208
  • 326