Is there any 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 I would rather do one over the other? Obviously, if the constructor accepts parameters that are later given to the fields, this is the reason:

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

Or maybe I need to do some special calculations.

But if I do not do this, is there another good reason?

+7
java
source share
8 answers

Well, it all depends on how you plan to use this. I'm going to assume that you are not planning to set value static, but this is just for internal purposes.

First, consider 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? Similar! What for? Since you cannot use the value until you create the object using the new keyword.

oracle docs claims that:

As you saw, you can often specify the initial value for a field in your statement:

 public class BedAndBreakfast { // initialize to 10 public static int capacity = 10; // initialize to false private boolean full = false; } 

This works well when an initialization value is available, and one line can be enabled for initialization. However, this form of initialization has limitations because of its simplicity. If some logic is required for initialization (for example, error handling or a for loop to populate a complex array), a simple assignment is inadequate. Instance variables can be initialized to constructors, which can use error handling or other logic. To provide the same opportunity for class variables, the Java programming language includes static initialization blocks.

So, now you have confirmation that all this is done in the constructor if you are doing something complicated, for example, by initializing an array, otherwise you can do it right there when you declare the field.

If you need to use static , you obviously do two different things. It is almost like a check to find out if someone has created an instance of this object or not. Your variable will be 0 until someone creates an object, and then after that there will be 100 .

+4
source share

The field initialization code is copied to each constructor ... if you have several constructors and you want the field to be initialized with the same value in each (or even just in most), then it would be better to initialize when declaring and override the value in the constructor.

+1
source share

Well, it depends.

In the second case, the value will be populated with its default value of 0 , only for reassignment when created with 100 . In the first case, value immediately gets the value 100 .

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

Programmatically, there is no pain if the primitive is set to some initial value. This means that there is something for you, and if your program depends on the presence of a non-negative or false value, George will work.

Things become more explicit when working with object references. Take, for example, 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 clog the home point - for Foo , if I try to use elements , then I have a bit of a problem, if I don't use the corresponding constructor - elements is null ! * Then I could just create an instance when I need it, but I would really like to avoid destroying a potentially new and populated list.

That means a lot of code looks something like this:

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

... then I have to worry about being thread safe. Sheesh, talk about the chores.

With Bar I am guaranteed that when you instantiate it, it has an instance of the list in elements , so I don’t have to worry about being null . **

This is called impatient creation . You really do not want to live without this object, so why wait until you think that you need it (or a lazy instance )?

*: the default value for all link types is null .

**: You need to worry about this being texted, but this is a problem that goes beyond the scope of this question.

+1
source share

If you do not perform any calculations or accept any parameters, there is no difference in any of the above, regardless of whether you initialize or do not initialize this variable inside the constructor.

If you declare them first, as you declare as:

 public class Test { int value = 100; public Test() { } } 
  • This will be a more readable format, since you assign them a value directly, there is no need to view it from the constructor.

  • It would be better if you had several constructors, you do not need to repeat the initializations (and you cannot forget them).

0
source share

Whenever a class is created, the constructor is initialized first. Thus, when you declare or define a variable inside the constructor, memory is first assigned to that variable, and then the process continues.

0
source share

There is only one field in your example, and you decide which initialization path is better than the other.

But if you increase complexity by initializing many fields (say 30 or 40), then it really matters a lot.

In this situation, consider what Joshua Bloch has to say about initialization through constructors .

The following is a summary

  • The telescope constructor template works, but it’s hard to write client code when there are many parameters, and it’s even harder to read.
  • The solution is a form of the Builder template, where instead of the desired object directly, the client calls the constructor (or static factory) with all the required parameters and receives the builder object.
0
source share

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

A field will always be initialized to 100 if you define it as below, regardless of which constructor is called:

 int field = 100; 

but otherwise, you must initialize the field in each constructor.

There can only be one constructor in your class, but just think about whether there will be any other constructor in future versions of your class?

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

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

  • initialization blocks

    {// initialization}

  • final methods

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

All Articles