2011-04-06 16 views
74

Sé que esto es probablemente muy estúpida, pero una gran cantidad de lugares pretendo que la clase de enteros en Java es inmutable, sin embargo, el siguiente código:es entero Inmutable

Integer a=3; 
Integer b=3; 
a+=b; 
System.out.println(a); 

ejecuta sin ningún tipo de problemas para dar la (esperada) resultado 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é?

+12

La clase es inmutable, pero el autoboxing está haciendo que las cosas funky sucedan: http://stackoverflow.com/questions/3085332/comparison-between-variables-pointing-to-same-integer-object – birryree

+0

Gracias, boxeo fue la palabra clave Necesitaba google :) –

+6

Estás confundiendo inmutable con un valor final o constante. –

Respuesta

77

Inmutable no significa que a nunca puede igualar otro valor. Por ejemplo, String es inmutable también, pero todavía se puede hacer esto:

String str = "hello"; 
// str equals "hello" 
str = str + "world"; 
// now str equals "helloworld" 

Entonces, ¿qué pasó? Como String es inmutable, claramente str no se modificó. Pero ahora es igual a algo diferente. Esto se debe a que str ahora es un objeto recién instanciado por completo, al igual que su Integer. Por lo tanto, el valor de a no se modificó, pero se reemplazó por un objeto completamente nuevo, es decir, new Integer(6).

+11

"Esto es porque str ahora es un objeto completamente instanciado por última vez". O, más bien, str (un varibale) _points_ a un nuevo objeto. El objeto en sí no es mutable, pero como la variable no es definitiva, puede apuntar a un objeto diferente. – Sandman

+0

Sí, apunta a un objeto diferente que fue instanciado como resultado de la operación '+ ='. –

+9

Estrictamente hablando, * no necesita * ser un * nuevo * objeto. El boxeo usa 'Integer.valueOf (int)' y ese método mantiene un caché de objetos 'Integer'. Entonces, el resultado de '+ =' en una variable 'Integer' podría ser un objeto que existía anteriormente (o podría ser el mismo objeto ... en el caso de' a + = 0'). –

41

a es una "referencia" para algún entero (3), su forma abreviada a+=b realmente significa hacer esto:

a = new Integer(3 + 3) 

Así que no, los números enteros no son mutables, pero las variables que apuntan a ellos son *.

* Es posible tener variables inmutables, estas 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. 
3

Inmutables no significa que no se 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 que lo entienda usted mismo, realice la asignación Integer 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 copias 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.

4

Sí 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.

2

"Las clases inmutables no necesitan constructores de copia". ¿Alguien quiere explicar por qué?

La razón es que hay raramente cualquier necesidad de copiar (o incluso cualquier punto de la copia) 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.

Hay algunas suposiciones subyacentes sin embargo:

  • Se supone que su aplicación no coloque ningún significado en la identidad del objeto de instancias de la clase.

  • Supone que la clase ha sobrecargado equals y hashCode para que una copia de una instancia sea "igual que" la original ... según estos métodos.

Uno o ambos de estos supuestos podría ser falsa, y que podría justificar la adición de un constructor de copia.

16

Se puede determinar que el objeto ha cambiado usando System.identityHashCode() (Una mejor manera es utilizar llanura == sin embargo no es tan obvio que la referencia más que el valor ha 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))); 

impresiones

before a +=3; a=3 id=70f9f9d8 
after a +=3; a=6 id=2b820dda 

Puede ver que el "id" subyacente del objeto a se refiere a ha cambiado.

+0

System.identityHashCode() es un muy buen consejo. Gracias por esto. –

9

a la pregunta inicial se le preguntó,

Integer a=3; 
Integer b=3; 
a+=b; 
System.out.println(a); 

entero es inmutable, por lo que lo que ha sucedido anteriormente es 'a' se ha cambiado a una nueva referencia de valor 6. El valor inicial 3 se queda con ninguna referencia en la memoria (no se ha cambiado), 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.

0

puedo dejar claro que entero (y otra de su credo como flotador, corto, etc) son inmutables por simple código de ejemplo:

Código de ejemplo

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 real

El resultado viene a él Hola Hay 100 en lugar de resultado esperado (en el caso de ambos sb y siendo i objetos mutables) Hola allí 1000

Esto muestra el objeto creado por i en el principal no se modifica , mientras que sb se modifica.

Así que StringBuilder demostró un comportamiento mutable pero no entero.

So Integer es inmutable.Por lo tanto Probadas

Otro código sin sólo números enteros:

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; 
    } 


} 
+0

Estás haciendo dos cosas diferentes: intentar reasignar el número entero y llamar a un método en el generador de cadenas. Si haces 'private void doStringBuilder (StringBuilder sb) {sb = new StringBuilder(); } 'then' sb' no se modifica. – MT0

+0

Agregué StringBuilder (que es mutable) para simplemente yuxtaponer entero con otro objeto que es mutable. Si lo desea, puede eliminar todo el código relacionado con StringBuilder y simplemente imprimirlo para ver 100. –

+0

@ MT0 agregó el código minimalista para su referencia. –

0

Así es como 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 podría mutar "un" imprimiría 8 pero no porque es inmutable, por eso es 3. Tu ejemplo es solo una ne w asignación.

-1
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 
} 

de salida es:

Hola adiós d un

Así char es mutable, Cadena Entero int y son inmutables.

+0

Esta respuesta no proporciona ninguna información de los demás. –