¿Por qué puedo editar el contenido de una matriz final en Java?

6 minutos de lectura

Avatar de usuario de León
León

El siguiente código en Java utiliza un final gama de 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] + " ");
    }
  }
}

Muestra el siguiente resultado en la consola.

I can never change

Si tratamos de reasignar lo declarado final matriz de tipo Stringprovocamos un 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: no se puede asignar a la variable final CONSTANT_ARRAY.

Sin embargo, el siguiente código funciona:

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] + " ");
    }
  }
}

Muestra

I can always change

Esto quiere decir que podríamos llegar a modificar el valor de la final matriz de tipo String. ¿Podemos modificar toda la matriz de esta manera sin violar la regla inmutable de final?

  • Técnicamente un duplicado de stackoverflow.com/questions/13979696/… pero esto tiene más vistas/respuestas

    – TylerH

    19 de agosto a las 18:28

Avatar de usuario de Brian Roach
Brian Cucaracha

final en Java afecta a la variableno tiene nada que ver con el objeto que le estás asignando.

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

Editar para agregar desde los comentarios: Tenga en cuenta que dije objeto que le estás asignando. En Java, una matriz es un objeto. Esto mismo se aplica a cualquier otro objeto:

final List<String> myList = new ArrayList<String>():
myList = anotherList; // error, you can't do that
myList.add("Hi there!"); // perfectly fine. 

  • Usted dijo objeto, y eso es bueno. Esto se aplica a todos los objetos, no solo a las matrices. También está bien modificar objetos que son el valor de las variables finales. P.ej, final List<String> list = new ArrayList<String>(); list.add("foo");.

    – Josué Taylor

    25/09/2013 a las 21:42


  • Debido a que la matriz se define con un nuevo operador, es una referencia de objeto (no importa si contiene un tipo primitivo o de objeto). La referencia del objeto no se puede modificar, pero el contenido sí. El documento de Oracle dice “Una matriz es un objeto contenedor que contiene un número fijo de valores de un solo tipo” [docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html]. El operador new devuelve una referencia al objeto que creó. [docs.oracle.com/javase/tutorial/java/javaOO/…

    – Arpit

    Jul 7, 2020 at 3:18

Shehzad's user avatar
Shehzad

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"));

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.

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

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)

  • Doesn’t the second sentence imply the first?

    – user395760

    Apr 26, 2012 at 19:26


  • No. a variable can refer to an object reference, not necessarily a primitive.

    – afsina

    Apr 26, 2012 at 19:28

  • 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.

    – user395760

    Apr 26, 2012 at 19:33

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[]) a la misma variable final… obtendría un error de tiempo de compilación).

PERO los campos del objeto de matriz final en su ejemplo no son definitivos, por lo que puede modificar su valor. …mientras que el objeto Java que creó, CONSTANT_ARRAY, después de recibir un valor inicial, tendrá ese valor “para siempre” == hasta que la JVM se detenga. 🙂 Será la misma instancia de String Array “para siempre”.

Las variables finales en Java no son un gran problema, solo dedique un tiempo a digerir el tema/idea con cuidado. 🙂

Sugiero a todos aquellos que no están seguros que mediten sobre esta página, por ejemplo:
https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4

Permítanme citar la parte respectiva:

Una vez que se ha asignado una variable final, siempre contiene el mismo valor. Si una variable final contiene una referencia a un objeto, entonces el estado del objeto puede cambiar mediante operaciones en el objeto, pero la variable siempre se referirá al mismo objeto.

Esto se aplica también a los arreglos, porque los arreglos son objetos; si una variable final contiene una referencia a una matriz, entonces los componentes de la matriz pueden cambiarse mediante operaciones en la matriz, pero la variable siempre se referirá a la misma matriz”.

  • ¿La segunda oración no implica la primera?

    usuario395760

    26 de abril de 2012 a las 19:26


  • No. una variable puede hacer referencia a una referencia de objeto, no necesariamente una primitiva.

    – afsina

    26 de abril de 2012 a las 19:28

  • Sí, ¿y qué? Las variables son variables, no importa si son de tipo primitivo o de tipo de referencia. Y en cualquier caso, no se puede reasignar.

    usuario395760

    26 de abril de 2012 a las 19:33

Avatar de usuario de MyPasswordIsLasercats
Mi contraseña es Lasercats

El valor de la variable CONSTANT_ARRAY no puede cambiar. Esa variable contiene una (referencia a una) matriz. sin embargo, el contenido de la matriz pueden cambio. Lo mismo sucede cuando declara cualquier tipo de variable final que no sea un tipo escalar simple (por ejemplo, un objeto).

Tenga cuidado con cómo nombra sus variables. 🙂 Llamarlo CONSTANT_ARRAY no hace que el contenido de la matriz no se pueda modificar.

Aquí hay una buena referencia: La última palabra sobre la final

¿Ha sido útil esta solución?