How does the "final" keyword in Java work? (I can still modify an object.) Ask Question

How does the

In Java we use final keyword with variables to specify its values are not to be changed. But I see that you can change the value in the constructor / methods of the class. Again, if the variable is static then it is a compilation error.

Here is the 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);
  }
}

Above code works fine and no errors.

Now change the variable as static:

private static final List foo;

Now it is a compilation error. How does this final really work?

ベストアンサー1

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.
Now a days interviewers are asking another favorite question what is effectively final from java 1.8.
I will explain in the end about this effectively final in java 1.8.

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 an 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

上記はModification-2あなたの質問からの抜粋です。上記のケースでは、最初に参照されたオブジェクトは変更されていませんが、許可されているコンテンツが内部に追加されています。参照変数に をfoo割り当てようとすると、コンパイラーからエラーが出ます。ルール変数を初期化した場合、別のオブジェクトを参照するように変更することはできません。(この場合)new ArrayList()foo
finalArrayList

最終クラスはサブクラス化できません。
最終メソッドはオーバーライドできません。(このメソッドはスーパークラスにあります)
最終メソッドはオーバーライドできます。(文法的に読んでください。このメソッドはサブクラスにあります)

さて、 Java 1.8 で実際に final となるものを見てみましょう。

public class EffectivelyFinalDemo { //compile code with java 1.8
    public void process() {
        int thisValueIsFinalWithoutFinalKeyword = 10; //variable is effectively final
        
        //to work without final keyword you should not reassign value to above variable like given below 
        thisValueIsFinalWithoutFinalKeyword = getNewValue(); // delete this line when I tell you.
        
        class MethodLocalClass {
            public void innerMethod() {
                //below line is now showing compiler error like give below
                //Local variable thisValueIsFinalWithoutFinalKeyword defined in an enclosing scope must be final or effectively final
                System.out.println(thisValueIsFinalWithoutFinalKeyword); //on this line only final variables are allowed because this is method local class
                // if you want to test effectively final is working without final keyword then delete line which I told you to delete in above program.  
            }
        }
    }

    private int getNewValue() {
        return 0;
    }
}

上記のプログラムは、final キーワードを使用しないと、Java 1.7 または <1.8 でエラーをスローします。事実上、final はメソッド ローカル内部クラスの一部です。メソッド ローカル クラスでこのような事実上 final を使用することはほとんどないと思いますが、面接のために準備しておく必要があります。

おすすめ記事