Saturn
Saturn

Reputation: 18139

Is there a difference in setting fields inside or outside the constructor?

public class Test {
    int value = 100;
    public Test() {

    }
}

And

public class Test {
    int value;
    public Test() {
        value = 100;
    }
}

Are equivalent, right? Is there a reason why I'd prefer to do one over the other? Obviously if the constructor takes parameters that are later given to the fields is a reason:

public class Test {
    int value;
    public Test(int value) {
        this.value = value;
    }
}

Or perhaps I need to do some special calculation.

But if I don't do that, is there another good reason?

Upvotes: 7

Views: 1509

Answers (8)

indika
indika

Reputation: 923

public class Test {
   int value = 100;
   public Test() {

   }
}

This works well when the initialization value is available and you may declare and initialize field on one line. However, this form of initialization has limitations because of its simplicity. If initialization requires some logic (for example, error handling or a validation or condition), simple assignment is inadequate. When you are using constructor initialization, you may do error handling or other logic. To provide the same capability for class variables, the Java programming language includes static initialization blocks. There are also another two ways to initialize instance variables:

  1. initializer blocks

    { // initialization }

  2. final methods

    class Foo{
       int age=initAge();
    
       protected int initAge(){
         //initialization code
       } 
     }
    

Upvotes: 1

Amir Pashazadeh
Amir Pashazadeh

Reputation: 7282

I'm not talking about bytecode, but they can differ semantically (if you have multiple constructors),

The field will be always initialized to 100 if you define it as below, no matter which constructor is called:

int field = 100;

but otherwise you shall initialize the field in each constructor.

Your class may have just a single constructor, but just think, will there be any other constructor in future releases of your class?

Upvotes: 0

Vikas V
Vikas V

Reputation: 3186

Currently in your example, there is just one field and you are deciding which way of initializing is better than the other.

But, if you increase the complexity by initializing a lot of fields (say 30 or 40), then it does make a lot of difference.

In this situation, consider what Joshua Bloch has to say on initializing through constructors.

Below is the summary,

  1. The telescoping constructor pattern works, but it is hard to write client code when there are many parameters, and harder still to read it.
  2. The solution is a form of Builder pattern where instead of making the desired object directly, the client calls a constructor (or static factory) with all of the required parameters and gets a builder object.

Upvotes: 0

Sanchit
Sanchit

Reputation: 2260

Well it all really depends on how you plan on using this. I'm going to assume that you don't plan to make value static but it's just there for internal purposes.

Firstly lets look at the bytecode.

D:\eclipse\workspace\asdf\bin>javap -c A.class
Compiled from "A.java"
public class A {
  int value;

  public A();
    Code:
       0: aload_0
       1: invokespecial #10                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: bipush        100
       7: putfield      #12                 // Field value:I
      10: return
}

D:\eclipse\workspace\asdf\bin>javap -c B.class
Compiled from "B.java"
public class B {
  int value;

  public B();
    Code:
       0: aload_0
       1: invokespecial #10                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: bipush        100
       7: putfield      #12                 // Field value:I
      10: return
}

D:\eclipse\workspace\asdf\bin>

Guess what? Exactly the same! Why? Because you can't USE value until you make an object by using the new keyword.

The oracle docs states that:

As you have seen, you can often provide an initial value for a field in its declaration:

public class BedAndBreakfast {
    // initialize to 10
    public static int capacity = 10;

    // initialize to false
    private boolean full = false;
} 

This works well when the initialization value is available and the initialization can be put on one line. However, this form of initialization has limitations because of its simplicity. If initialization requires some logic (for example, error handling or a for loop to fill a complex array), simple assignment is inadequate. Instance variables can be initialized in constructors, where error handling or other logic can be used. To provide the same capability for class variables, the Java programming language includes static initialization blocks.

So now you have confirmation that the whole point of doing it in the constructor is if you are doing something complex like initializing an array otherwise feel free to do it right there when you declare the field.

If you WERE to use static then you are obviously doing two different things. It's almost like a check to see if someone has ever created an instance of this object or not. Your variable would be 0 until someone creates an object and then it would be 100 afterward.

Upvotes: 4

Makoto
Makoto

Reputation: 106389

Well, it depends.

With the second case, value would be populated with its default value of 0, only to be reassigned at instantiation with 100. In the first case, value is just instantly given the value of 100.

Semantically, this would help a programmer - they would see that this particular value means something a little more than just it being arbitrary (although, it should be a constant value somewhere).

Programmatically, there's no pain if a primitive is set to some initial value. It means that there's something in there for you to use, and if your program depends on there being a non-negative or false value, by George it will work.

Things get more explicit when dealing with object references. Take, for instance, these two classes:

public class Foo {
    List<String> elements;
    public Foo() {
    }

    public Foo(String... items) {
        elements = new ArrayList<>();
        for(String item : items) {
            elements.add(item);
        }
   }
}

public class Bar {
    List<String> elements = new ArrayList<>();
    public Bar() {
    }

    public Bar(String... items) {
        for(String item : items) {
            elements.add(item);
        }
   }
}

There are intentionally no-arg constructors to hammer home the point - for Foo, if I attempt to use elements, then I'm in a bit of trouble if I don't use the appropriate constructor - elements is null!* I could then just instantiate it whenever I needed it, but I would very much want to avoid destroying a potentially newed and populated list.

That means a lot of code looking something like this:

if(elements == null) {
    elements = new ArrayList<>();
}

...then I have to worry about it being thread safe. Sheesh, talk about a hassle.

With Bar, I'm guaranteed that at instantiation, there is an instance of a list in elements, so I don't have to worry about it being null.**

This is known as eager instantiation. You really don't want to live without that object, so why wait until you think you need it (or lazily instantiate)?

*: The default value for all reference types is null.

**: You do have to worry about that being overwritten, but that's a concern outside of the scope of this question.

Upvotes: 1

arun
arun

Reputation: 227

Whenever a class is created the constructor is initialized first. So, when you declare or define a variable inside the constructor the memory is allocated to that variable at first and then the process will be continued.

Upvotes: 0

Parth Soni
Parth Soni

Reputation: 11648

If you're not doing any calculation or not taking any parameters, there's no difference in any of those above two, whether you initialize or not initialize those variable inside constructor.

If you declare them as the first one like you declare as:

public class Test {
    int value = 100;
    public Test() {

    }
}
  • It would be more of a readable format as you're assigning them value directly, no need to view from constructor.

  • It would be better also for If you have more than one constructor, you don't have to repeat the initializations (and you cannot forget them).

Upvotes: 0

Elliott Frisch
Elliott Frisch

Reputation: 201409

Field initialization code is copied into each constructor... if you had multiple constructors and wanted the field initialized with the same value in each (or even just most) then it would be better to initialize at declaration and override the value in the constructor.

Upvotes: 1

Related Questions