java - son - principios inmutables
Es entero inmutable (10)
"Las clases inmutables no necesitan constructores de copia". ¿Alguien quiere explicar por qué?
La razón es que raramente hay necesidad de copiar (o incluso de copiar) una instancia de una clase inmutable. La copia del objeto debe ser "igual que" el original, y si es el mismo, no debería haber necesidad de crearlo.
Sin embargo, hay algunas suposiciones subyacentes:
Supone que su aplicación no tiene ningún significado en la identidad del objeto de las instancias de la clase.
Supone que la clase ha sobrecargado
equals
yhashCode
para que una copia de una instancia sea "igual a" la original ... según estos métodos.
Cualquiera o ambas suposiciones podrían ser falsas, y eso podría justificar la adición de un constructor de copia.
Sé que esto es probablemente muy estúpido, pero muchos lugares afirman que la clase Integer en Java es inmutable, sin embargo, el siguiente código:
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
Se ejecuta sin ningún problema dando el resultado (esperado) 6. Entonces efectivamente el valor de a ha cambiado. ¿Eso no significa que Integer es mutable? Pregunta secundaria y un poco offtopic: "Las clases inmutables no necesitan constructores de copia". ¿Alguien quiere explicar por qué?
A la pregunta inicial,
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
El entero es inmutable, entonces lo que sucedió arriba es ''a'' cambiado a una nueva referencia de valor 6. El valor inicial 3 queda sin referencia en la memoria (no ha sido modificado), por lo que puede ser basura recolectada.
Si esto le sucede a una Cadena, se mantendrá en la agrupación (en el espacio PermGen) durante un período más largo que los Enteros, ya que espera tener referencias.
Así es como yo entiendo inmutable
int a=3;
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8
Si int puede mutar, "a" imprimirá 8 pero no lo hace porque es inmutable, por eso es 3. Su ejemplo es solo una nueva tarea.
Inmutable no significa que a
nunca puede igualar a otro valor. Por ejemplo, String
es inmutable, pero aún puedo hacer esto:
String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"
Entonces, ¿qué pasó allí? Dado que String
es inmutable, claramente str
no fue cambiado. Pero ahora es igual a algo diferente. Esto se debe a que str
es ahora un objeto recién instanciado por completo, al igual que su Integer
. Entonces, el valor de a
no cambió, sino que fue reemplazado por un objeto completamente nuevo, es decir, un new Integer(6)
.
Inmutable no significa que no puede cambiar el valor de una variable. Simplemente significa que cualquier nueva asignación crea un nuevo objeto (le asigna una nueva ubicación de memoria) y luego se le asigna el valor.
Para comprender esto por usted mismo, realice la asignación de enteros en un bucle (con un entero declarado fuera del bucle) y observe los objetos activos en la memoria.
La razón por la cual el constructor de copia no es necesario para objetos inmutables es simple sentido común. Como cada tarea crea un nuevo objeto, el lenguaje ya crea técnicamente una copia, por lo que no es necesario crear otra copia.
Puede determinar que el objeto ha cambiado usando System.identityHashCode()
(Una forma mejor es usar plain ==
sin embargo, no es tan obvio que la referencia en lugar del valor haya cambiado)
Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
huellas dactilares
before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda
Puede ver que el "id" subyacente del objeto a
refiere ha cambiado.
Puedo dejar en claro que Integer (y otros de su credo como Float, Short, etc.) son inmutables por simple código de muestra:
Código de muestra
public class Test{
public static void main(String... args){
Integer i = 100;
StringBuilder sb = new StringBuilder("Hi");
Test c = new Test();
c.doInteger(i);
c.doStringBuilder(sb);
System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
}
private void doInteger(Integer i){
i=1000;
}
private void doStringBuilder(StringBuilder sb){
sb.append(" there");
}
}
Resultado actual
El resultado es Hi él 100 en lugar del resultado esperado (en el caso de que tanto sb como yo sean objetos mutables) Hola, 1000
Esto muestra que el objeto creado por i en main no se modifica, mientras que sb se modifica.
Así que StringBuilder demostró un comportamiento mutable pero no entero.
Entonces Integer es inmutable. Por lo tanto demostrado
Otro código sin solo Entero:
public class Test{
public static void main(String... args){
Integer i = 100;
Test c = new Test();
c.doInteger(i);
System.out.println(i); //Expected result is 1000 in case Integer is mutable
}
private void doInteger(Integer i){
i=1000;
}
}
Sí, el entero es inmutable.
A es una referencia que apunta a un objeto. Cuando ejecuta un + = 3, eso reasigna A para hacer referencia a un nuevo objeto Integer, con un valor diferente.
Nunca modificó el objeto original, sino que apuntó la referencia a un objeto diferente.
Lea sobre la diferencia entre objetos y referencias here .
a
es una "referencia" a un entero (3), tu taquigrafía a+=b
realmente significa hacer esto:
a = new Integer(3 + 3)
Entonces, no, los enteros no son mutables, pero las variables que los señalan son *.
* Es posible tener variables inmutables, que se denotan con la palabra clave final
, lo que significa que la referencia no puede cambiar.
final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1="Hi";
String s2=s1;
s1="Bye";
System.out.println(s2); //Hi (if String was mutable output would be: Bye)
System.out.println(s1); //Bye
Integer i=1000;
Integer i2=i;
i=5000;
System.out.println(i2); // 1000
System.out.println(i); // 5000
int j=1000;
int j2=j;
j=5000;
System.out.println(j2); // 1000
System.out.println(j); // 5000
char c=''a'';
char b=c;
c=''d'';
System.out.println(c); // d
System.out.println(b); // a
}
La salida es:
Hola adios 1000 5000 1000 5000 d a
Así que char es mutable, String Integer e int son inmutables.