primitivos - tipos de variables en java ejemplos
¿Los primitivos de Java son inmutables? (5)
Si un método tiene una variable local i
:
int i = 10;
y luego asigno un nuevo valor:
i = 11;
¿Esto asignará una nueva ubicación de memoria? ¿O simplemente reemplaza el valor original?
¿Significa esto que los primitivos son inmutables?
¿Esto asignará una nueva ubicación de memoria? ¿O simplemente reemplaza el valor original?
Java realmente no garantiza que las variables correspondan a las ubicaciones de memoria; por ejemplo, su método podría estar optimizado de tal forma que i
esté almacenado en un registro, o incluso que no pueda almacenarse, si el compilador puede ver que en realidad nunca usa su valor, o si puede rastrearlo a través del código. y use los valores apropiados directamente.
Pero dejando eso de lado. . . si tomamos la abstracción aquí para que una variable local denote una ubicación de memoria en la pila de llamadas, entonces i = 11
simplemente modificará el valor en esa ubicación de memoria. No necesitará usar una nueva ubicación de memoria, porque la variable i
era lo único que se refería a la ubicación anterior.
¿Significa esto que los primitivos son inmutables?
Sí y no: sí, los primitivos son inmutables, pero no, eso no se debe a lo anterior.
Cuando decimos que algo es mutable, queremos decir que puede ser mutado: cambiado sin dejar de tener la misma identidad. Por ejemplo, cuando creces tu cabello, te estás mutando a ti mismo: sigues siendo tú, pero uno de tus atributos es diferente.
En el caso de los primitivos, todos sus atributos están completamente determinados por su identidad; 1
siempre significa 1
, no importa qué, y 1 + 1
es siempre 2
. No puedes cambiar eso.
Si una variable int
dada tiene el valor 1
, puede cambiarla para tener el valor 2
lugar, pero eso es un cambio total de identidad: ya no tiene el mismo valor que tenía antes. Eso es como cambiarme para señalar a otra persona en lugar de a mí: en realidad no me cambia, simplemente me
cambia a me
.
Con objetos, por supuesto, a menudo puede hacer ambas cosas:
StringBuilder sb = new StringBuilder("foo");
sb.append("bar"); // mutate the object identified by sb
sb = new StringBuilder(); // change sb to identify a different object
sb = null; // change sb not to identify any object at all
En lenguaje común, ambos se describirán como "cambio de sb
", porque las personas usarán " sb
" para referirse a la variable (que contiene una referencia) y al objeto al que hace referencia (cuando se refiere a uno). Este tipo de relajación está bien, siempre y cuando recuerdes la distinción cuando importa.
Esta no es una respuesta completa, pero es una forma de probar la inmutabilidad de los valores de tipo primitivo.
Si los valores primitivos (literales) son mutables, entonces el siguiente código funcionaría bien:
int i = 10; // assigned i the literal value of 10
5 = i; // reassign the value of 5 to equal 10
System.out.println(5); // prints 10
Por supuesto, esto no es verdad.
Los valores enteros, como 5, 10 y 11 ya están almacenados en la memoria. Cuando establece una variable igual a uno de ellos, cambia el valor en la ranura de memoria donde i
.
Puedes ver esto aquí a través del bytecode para el siguiente código:
public void test(){
int i = 10;
i = 11;
i = 10;
}
Bytecode:
// access flags 0x1
public test()V
L0
LINENUMBER 26 L0
BIPUSH 10 // retrieve literal value 10
ISTORE 1 // store it in value at stack 1: i
L1
LINENUMBER 27 L1
BIPUSH 11 // same, but for literal value 11
ISTORE 1
L2
LINENUMBER 28 L2
BIPUSH 10 // repeat of first set. Still references the same literal 10.
ISTORE 1
L3
LINENUMBER 29 L3
RETURN
L4
LOCALVARIABLE this LTest; L0 L4 0
LOCALVARIABLE i I L1 L4 1
MAXSTACK = 1
MAXLOCALS = 2
Como puede ver en el bytecode (con suerte), hace referencia al valor literal (ejemplo: 10) y luego lo almacena en la ranura para la variable i
. Cuando cambia el valor de i
, solo está cambiando qué valor se almacena en esa ranura. Los valores en sí mismos no están cambiando, la ubicación de ellos es.
Los literales primitivos y las variables primitivas final
son inmutables. No las variables primitivas final
son mutables.
La identidad de cualquier variable primitiva es el nombre de esa variable y es obvio que dicha identidad es inmutable.
Sí, son inmutables. Son totalmente inalterables.
Hay una buena explicación enterrada here . Es para Go, pero es lo mismo en Java. O cualquier otro idioma en la familia C.
Immutable
significa que cada vez que el valor de y el objeto ha cambiado, se crea una nueva referencia para él en la pila. No se puede hablar de inmutabilidad en el caso de tipos primitivos, solo las Clases de Contenedor son inmutables. Java usa copy_by_value
no por referencia.
No importa si pasa variables primitivas o de referencia, siempre está pasando una copia de los bits en la variable. Entonces, para una variable primitiva, está pasando una copia de los bits que representan el valor y si está pasando una variable de referencia de objeto, está pasando una copia de los bits que representan la referencia a un objeto.
Por ejemplo, si pasa una variable int con el valor de 3, está pasando una copia de los bits que representan 3.
Una vez que se ha declarado una primitiva, its primitive type can never change
, aunque su valor puede cambiar.