Thursday, March 23, 2017

Java - How Final Keyword Works

Sharing a very good explanation of how Java's "final" keyword works.

In Java we use final keyword to variables that can only be initialized once. You are always allowed to initialize a "final" variable, but the Java compiler makes sure that you can only do it once.

Consider the following code:

import java.util.ArrayList;
import java.util.List;

class Test {
  private final List foo;

  public Test()
  {
      foo = new ArrayList();
      foo.add("foo"); // Modification-1
  }

  public static void main(String[] args)
  {
      Test t = new Test();
      t.foo.add("bar"); // Modification-2
      System.out.println("print - " + t.foo);
  }
}

You initialize foo in the constructor, and you can change the contents of foo in the main method, but you can only initialize foo once. If you try to do "t.foo = new ArrayList();" in the main method and you will get a compilation error. Note: Calling methods on an object stored in a final variable has nothing to do with the semantics of final. In other words: final is only about the reference itself, and not about the contents of the referenced object.

Also, this is a favorite interview question. With this questions, the interviewer tries to find out how well you understand the behavior of objects with respect to constructors, methods, class variables (static variables) and instance variables.

Let's modify the code to:
import java.util.ArrayList;
import java.util.List;

class Test {

    private final List foo;

    public Test() {
        foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }

    public void setFoo(List foo) {
       //this.foo = foo; Results in compile time error.
    }
}


In the above case, we have defined a constructor for Test and gave it a setFoo method.

About constructor: Constructor can be invoked only one time per object creation by using the new keyword. You cannot invoke constructor multiple times, because constructor are not designed to do so.

About method: A method can be invoked as many times as you want (Even never) and the compiler knows it.

Scenario 1:

private final List foo;  // 1

foo is an instance variable. When we create Test class object then the instance variable foo, will be copied inside the object of Test class. If we assign foo inside the constructor, then the compiler knows that the constructor will be invoked only once, so there is no problem assigning it inside the constructor.

If we assign foo inside a method, the compiler knows that a method can be called multiple times, which means the value will have to be changed multiple times, which is not allowed for a final variable. So the compiler decides constructor is good choice! You can assign a value to a final variable only one time.

Scenario 2:

private static final List foo = new ArrayList();

foo is now a static variable. When we create an instance of Test class, foo will not be copied to the object because foo is static. Now foo is not and independent property of each object. This is a property of Test class. But foo can be seen by multiple objects and if every object which is created by using the new keyword which will ultimately invoke the Test constructor which changes the value at the time of multiple object creation (Remember static foo is not copied in every object, but is shared between multiple objects.)

Scenario 3:

t.foo.add("bar"); // Modification-2

Above Modification-2 is from your question. In the above case, you are not changing the first referenced object, but you are adding content inside foo which is allowed. Compiler complains if you try to assign a new ArrayList() to the foo reference variable.

Rule If you have initialized a final variable, then you cannot change it to refer to a different object. (In this case ArrayList)

In a conclusion:
final classes cannot be subclassed
final methods cannot be overridden. (This method is in superclass)
final methods can override. (Read this in grammatical way. This method is in a subclass)

Source: http://stackoverflow.com/questions/15655012/how-final-keyword-works

No comments: