-1

I have encountered a peculiar effect when initializing fields in Java. My code:

import java.util.Locale;

public class Vehicle {

String name;
static Locale locale;
String localeString = locale.toString();
static int number;
int numberVehicle;
String localSign = localeString + numberVehicle;



public Vehicle(String name) {
    this.name = name;
}

static{
     locale = Locale.getDefault();
}

{
    numberVehicle = ++number;
}

@Override
public String toString() {
    return "Vehicle{" +
            ", name=" + name +
            ", numberOfVehicle=" + numberVehicle +
            ", localSign='" + localSign +'\'' +
            '}';
}

}

When I initialize 3 cars and print it, I get:

Vehicle{, name=citroen, numberOfVehicle=1, localSign='pl_PL0'}

Vehicle{, name=opel, numberOfVehicle=2, localSign='pl_PL0'}

Vehicle{, name=zyguli, numberOfVehicle=3, localSign='pl_PL0'}

The numberVehicle is increased as intended however the localSign, which should contain numberVehicle: String localSign = localeString + numberVehicle; is always with "0' as the numberVehicle would not be increased. When I debug it with breakpoints it shows the value to localSign is assigned when numberVehicle is initialized withh 0. That seems to me strange, because I did assign the correct value in the instance initializiation block

{
numberVehicle = ++number;
}

As far as I know (also found here: https://stackoverflow.com/a/15413629/13612259 ) initialization blocks are executed prior to constructor, so I do not understand why String localSign = localeString + numberVehicle; is executed when numberVehicle is not assigned with proper value. I would be grateful if someone could help me by indicating what I have missed.

Marome
  • 47
  • 1
  • 11
GregSim
  • 31
  • 3

2 Answers2

1

Cutting down your code to the relevant bits:

static int number;
int numberVehicle;
String localSign = localeString + numberVehicle;

{
    numberVehicle = ++number;
}

The instance initializer (that increment number) is executed after you assign the value to localSign, so you read the uninitialized value.

Assignments on field declarations and instance initializers are executed in the order you declare them. So, the code above is equivalent to:

int numberVehicle;
String localSign;

{
    localSign = localeString + numberVehicle;
    numberVehicle = ++number;
}

(Actually, the contents of the instance initializers are inserted into the constructor, after the implicit/explicit call to the super/self constructor, and before the rest of the body. Your constructor actually becomes:

public Vehicle(String name) {
    super();

    // From field and instance initializers.
    localSign = localeString + numberVehicle;
    numberVehicle = ++number;

    // Constructor body.
    this.name = name;
}

To fix this, either move the instance initializer before the String assignment; or, easier, assign numberVehicle on the field:

int numberVehicle = ++number;
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
0

I don't know if I fully understand what you are trying to do, but why not something like:

import java.util.Locale;

public class Vehicle {

    String name;
    static Locale locale = Locale.getDefault();
    String localeString = locale.toString();
    static int number;
    int numberVehicle;
    String localSign = localeString + numberVehicle;

    public Vehicle(String name) {
        this.name = name;
    }

    {
       numberVehicle = ++number;
       localSign = localeString + numberVehicle;
    }

    @Override
    public String toString() {
        return "Vehicle{" +
            ", name=" + name +
            ", numberOfVehicle=" + numberVehicle +
            ", localSign='" + localSign +'\'' +
            '}';
    }
}

Also, keep in mind that since you have static int number; and I cannot see any setter, this value will always be 0. The same goes for numberOfVehicle with the difference that one is initialised with the instantiation and the other in a static way.

fjsv
  • 705
  • 10
  • 23
  • I have thought I increase it in initization block, that is executed prior to constructor: { numberVehicle = ++number; } The point I wanted to achieve is to use and understand initialization block, thats why I have not put this into constructor. – GregSim Jun 04 '20 at 12:44
  • Ok, but at least the Locale assignment can be done directly in the field instead of in a static block. – fjsv Jun 04 '20 at 12:47
  • I've edited my answer. You need to reassign the value of `localSign` and that should be it – fjsv Jun 04 '20 at 12:48
  • Thank you! Now it is working as I intended. So the conclusion for me would be that separation of moments of initialization between "regular fields" and intialization block can create such errors. – GregSim Jun 04 '20 at 13:10
  • 1
    The initialization on the `locationSign` field is redundant: `String localSign;`. – Andy Turner Jun 04 '20 at 15:22