简体   繁体   中英

Initializing final variable in java constructor

Lets say I have a situation like this.

private final A a;
private final B b;
private final C c;
private ClassX(){
  this.c = createCSomehow();
}
public ClassX(A a){
  this();
  this.a = a;
  this.b = null;
}
public ClassX(B b) {
  this();
  this.b = b;
  this.a = null;
}

Why Idea is complaining about a and b property? Idea underline them and say: Variable a might not have been initialized. I am sure that I have no more constructors and that in every case a will be populated with some value.

I don't really know how to properly answer the why (JLS investigation needed), but for the how , the following should compile:

private final A a;
private final B b;
private final C c = createCSomehow();

public Main(A a){
  this.a = a;
  this.b = null;
}

public Main(B b) {
  this.b = b;
  this.a = null;
}

As per the JLS specs http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.2

A blank final instance variable must be definitely assigned (§16.9) at the end of every constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs. This is why Idea is complaining.

What about the case where the constructor that takes no arguments is called, c is the only object variable that's being initialized. The object variables a and b only get initialized in the constructors that take arguments. So the fix should be as follows?

final A a;
final B b;
final C c = createCSomehow();

public ClassX() {
    a = null;
    b = null;
}

public ClassX(A a) {
    this.a = a;
    b = null;
}

public ClassX(B b) {
    a = null;
    this.b = b;
}

As mentioned in the other answers, after leaving a constructor your final fields must be initialized. Hence provide one constructor which initializes all fields and reuse it by the public constructors to provide the concrete values. Like this code:

private ClassX(A a, B b) {
    this.a = a;
    this.b = b;
    this.c = createCSomehow();
}

public ClassX(A a){
  this(a, null);
}

public ClassX(B b) {
    this(null, b);
}

As Jeremy already said in comment, there could be some code that calls the private constructor instead of the intended public ones.

Concerning the fix, I prefer a pattern where 1 (private?) constructor sets all variables, and other additional constructors call this "main" constructor, eg:

private ClassX(A a, B b){
  this.a = a;
  this.b = b;
  this.c = createCSomehow();
}
public ClassX(A a){
  this(a, null);
}
public ClassX(B b) {
  this(null, b);
}

In java all the final field must be initialize to some value. They can be assign value only once either where they are declared or in the constructor. If some final field is not initialize with declaration then it should be initialize in the all the constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM