65

The following code in Java uses a final array of String.

final public class Main {
  public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};

  public static void main(String[] args) {
    for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
      System.out.print(CONSTANT_ARRAY[x] + " ");
    }
  }
}

It displays the following output on the console.

I can never change

If we try to reassign the declared final array of type String, we cause an error:

final public class Main {
  public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};

  public static void main(String[] args) {
    CONSTANT_ARRAY={"I", "can", "never", "change"}; //Error - can not assign to final variable CONSTANT_ARRAY.
    for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
      System.out.print(CONSTANT_ARRAY[x] + " ");
    }
  }
}

Error: cannot assign to final variable CONSTANT_ARRAY.

However, the following code works:

final public class Main {
  public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};

  public static void main(String[] args) {
    CONSTANT_ARRAY[2] = "always";  //Compiles fine.
    for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
      System.out.print(CONSTANT_ARRAY[x] + " ");
    }
  }
}

It displays

I can always change

This mean that we could manage to modify the value of the final array of type String. Can we modify the entire array in this way without violating the immutable rule of final?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Lion
  • 18,729
  • 22
  • 80
  • 110
  • Technically a duplicate of https://stackoverflow.com/questions/13979696/why-wont-declaring-an-array-final-make-it-immutable-in-java but this has more views/answers – TylerH Aug 19 '22 at 18:28

9 Answers9

104

final in Java affects the variable, it has nothing to do with the object you are assigning to it.

final String[] myArray = { "hi", "there" };
myArray = anotherArray; // Error, you can't do that. myArray is final
myArray[0] = "over";  // perfectly fine, final has nothing to do with it

Edit to add from comments: Note that I said object you are assigning to it. In Java an array is an object. This same thing applies to any other object:

final List<String> myList = new ArrayList<String>():
myList = anotherList; // error, you can't do that
myList.add("Hi there!"); // perfectly fine. 
Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • 4
    You said _object_, and that's good. This applies to all objects, not just arrays. It's fine to modify objects that are the value of final variables, too. E.g., `final List list = new ArrayList(); list.add("foo");`. – Joshua Taylor Sep 25 '13 at 21:42
  • Because array is define with a new operator, it is an object reference (it doesn't matter if it holds primitive or object type). Object reference can't be modified but the contents can be. Oracle document says "An array is a container object that holds a fixed number of values of a single type" [https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html]. The new operator returns a reference to the object it created. [https://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html] – Arpit Jul 07 '20 at 03:18
20

You are misinterpreting the final implementation. final applies to the array object reference, which means once it is initiated, the reference can never change but the array its self can be populated. "Its not violating the rules" you have specified only one rule about the reference change which is working accordingly. If you want the values should also never change you should go for Immutable lists i.e

List<String> items = Collections.unmodifiableList(Arrays.asList("I", "can", "never", "change"));
Ger
  • 889
  • 1
  • 12
  • 21
Shehzad
  • 2,870
  • 17
  • 21
12

You can only make it so the array reference can't be changed. If you want the elements to be unable to be changed, you need to use an unmodifiable collection of some kind.

Choker
  • 875
  • 6
  • 9
3

When you declare an array as final, you can change the elements in the array, however you cannot change the reference of this array.

choop
  • 921
  • 2
  • 9
  • 28
3

final only guarantees immutability of primitives. And also guarantees that a variable is assigned only once. If an object is mutable you can change the content of it event it defined as final. You may check immutable collections for your needs. Such as Collections.unmodifiableList() http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#unmodifiableList(java.util.List)

afsina
  • 132
  • 7
  • 3
    Doesn't the second sentence imply the first? –  Apr 26 '12 at 19:26
  • No. a variable can refer to an object reference, not necessarily a primitive. – afsina Apr 26 '12 at 19:28
  • 2
    Yeah, so what? Variables are variables, no matter if they're of a primitive type or of a reference type. And in either case, it can't be reassigned. –  Apr 26 '12 at 19:33
2

The reference to the array object is final (can not change e.g. in case you would attempt to associate a different Java array object (instance of String[]) to the same final variable...you'd get a compile time error).

BUT the fields of the final array object in your example are not final, and so you can modify their value. ...while the Java object you created, CONSTANT_ARRAY, after receiving an initial value, will have that value "forever" == until the JVM stops. :) It will be the same String Array instance "forever".

Final variables in Java are not a big deal, just spend some time to digest the topic/idea carefully. :-)
I suggest to all of those who are uncertain to meditate over this page, for example: https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4

Let me cite the respective part:

"Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.

This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array."

1

The value of the variable CONSTANT_ARRAY cannot change. That variable contains a (reference to an) array. However, the contents of the array can change. Same thing happens when you declare any kind of final variable that is not a simple scalar type (e.g. an object).

Be careful how you name your variables. :-) Calling it a CONSTANT_ARRAY doesn't make the contents of the array unchangeable.

Here's a good reference: The final word on final

MyPasswordIsLasercats
  • 1,610
  • 15
  • 24
theglauber
  • 28,367
  • 7
  • 29
  • 47
0

When a variable is declared with the final keyword, its value can’t be modified, essentially, a constant. This also means that you must initialize a final variable. If the final variable is a reference, this means that the variable cannot be re-bound to reference another object, but the internal state of the object pointed by that reference variable can be changed i.e. you can add or remove elements from the final array or final collection.

Ashish Karn
  • 1,127
  • 1
  • 9
  • 20
-2
    final int[] res;
    int[] res1;
    int[] res2 = new int[1];
    res2[0]=20;

    res1=res2;
    res1=res2;//no error
    System.out.println("res1:"+res1[0]);

    res = res2;//only once
   //res = res2;//error already initialised
    res2[0]=30;

    System.out.println("res:"+res[0]);     

output:: res1:20 res:30

  • 4
    Posting a piece of code is not really aligning with the spirit of stack overflow. Kindly answer with content, context and details. – Raghav Sep 18 '17 at 05:00