2012-06-10 16 views
5

en cuenta dos referencias de tipo entero que llamar al método de fábrica estática valueOf como se muestra a continuación: -¿Está bien comparar objetos inmutables en Java utilizando en lugar de == es igual

Integer a = Integer.valueOf("10"); 
    Integer b = Integer.valueOf("10"); 

Entero Teniendo en cuenta que es inmutable, se está bien comparar a y b usando == en lugar de usar el método igual. Supongo que el método valueOf asegura que solo se crea una instancia de Integer con el valor 10 y se devuelve una referencia a esta instancia para cada entero creado con un valor 10.

En general, ¿está bien compararlo? dos referencias de una clase inmutable que se crean utilizando una llamada al mismo método de fábrica estático utilizando == en lugar de iguales?

Edit: La clase Integer se usó solo a modo de ejemplo. Soy consciente de que Intgers upto 127 volverá verdadero si se comparan con ==. Lo que necesito saber es que cuando creo mi propia clase inmutable, digamos MyImmutable con un método create() que asegure que no se creen objetos MyImmutable duplicados, ¿estará bien si comparo 2 referencias MyImmutable creadas usando el método create por usando == en lugar de igual.

+0

Por favor, lea [esto] (http: //www.javabeat.net/qna/13-what-is-difference-between-equals-and- /) –

+2

La inmutabilidad solo implica que no pueden cambiar. Se debe tener especial cuidado con el almacenamiento en caché (no 'nuevo') para garantizar que se devuelven los mismos valores para los mismos parámetros de entrada. –

+0

Puede usar '==' en lugar de iguales para los tipos donde equals no se ha anulado. Como esto podría cambiar en el futuro, igualar es casi siempre mejor. El único momento en el que diría que '==' es mejor es con tipos como 'enum' que podría ser' null' y usar '==' simplifica el código en este caso. –

Respuesta

6

No, eso no es seguro en general. El operador == compara las referencias, no los valores.

El uso de == funciona para enteros entre -128 y 127, pero no para otros enteros. El código siguiente muestra que == no siempre funcionará:

Integer a = Integer.valueOf(10); 
Integer b = Integer.valueOf(10); 
System.out.println(a == b); 

true 

Integer c = Integer.valueOf(1000); 
Integer d = Integer.valueOf(1000); 
System.out.println(c == d); 

false 

ver su funcionamiento en línea: ideone

La explicación de este comportamiento radica en la aplicación de Integer.valueOf:

public static Integer valueOf(int i) { 
    final int offset = 128; 
    if (i >= -128 && i <= 127) { // must cache 
     return IntegerCache.cache[i + offset]; 
    } 
    return new Integer(i); 
} 

source

No es que el estándar requiera que los enteros de boxeo para las entradas pequeñas (-128 a 127) dan objetos con las mismas referencias.

5.1.7 Conversión boxeo

Si el valor p de ser en caja es verdadero, falso, un byte, un char en el rango \ u0000 a \ u007f, o un int o número corto entre - 128 y 127, entonces, r1 y r2 sean los resultados de dos conversiones de boxeo de p. Siempre es el caso que r1 == r2.

Sin embargo, la norma no ofrece garantías para los enteros fuera de este rango.


En general, ¿está bien para comparar dos referencias de una clase inmutable que se crean mediante una llamada al mismo método de fábrica estática mediante el uso de == en lugar de los iguales?

Como se muestra arriba, no funcionará en general. Pero si se asegura de que dos objetos inmutables con el mismo valor siempre tengan la misma referencia, entonces sí, podría funcionar.Sin embargo, hay algunas reglas que debe seguir cuidadosamente:

  • El constructor no debe ser público.
  • Todos los objetos que cree mediante el método estático deben almacenarse en caché.
  • Cada vez que se le pida que cree un objeto, primero debe verificar la caché para ver si ya ha creado un objeto con el mismo valor.
+0

Mi pregunta no es sobre la clase Entero. Espero recibir una respuesta general. – CKing

+0

Lo siento. Me perdí la última parte. He iniciado sesión a través de mi Galaxy S3 y no es lo mismo que una computadora de escritorio/portátil. :) – CKing

+0

Esta es de hecho la respuesta que estaba buscando. ¡Muchas gracias! – CKing

7

== y equals() es fundamentalmente diferente.

Debe leer este post para más detalles:

Difference between Equals/equals and == operator?

No tiene nada que ver con los objetos inmutables.

+1

Sé la diferencia entre iguales y == muy bien. Intenta comprender mi pregunta antes de decir lo obvio. – CKing

+1

Ok. Le daré un ejemplo donde estará bien usar == para comparar. Por ejemplo, tengo una aplicación que tiene un objeto Usuario. Me aseguro de que solo instanciar una instancia para cada usuario, es decir. Cuando llamo al usuario con id 123, siempre habrá un solo objeto de usuario en mi aplicación completa con id 123. En este caso, usar == es aceptable para comparar 2 objetos de usuario para ver si son el mismo usuario. –

+0

De lo contrario, generalmente no está bien comparar 2 objetos usando == Lo siento si dije lo obvio, pero su pregunta antes de la edición fue una dirección completamente diferente. –

1

No son el mismo objeto, por lo que == no será verdadero. Con objetos, esté seguro y use equals().

+2

Técnicamente, cachés 'valueOf' (por defecto) -128 a 127 por lo que en este caso' a == b' será verdadero. Pero sí, definitivamente use '.equals' de todos modos. – Kevin

+0

Estoy hablando de una clase que garantiza que no se creen duplicados. Intente comprender una pregunta antes de saltar a una respuesta. – CKing

+1

@bot: su pregunta original no indicaba que la clase garantizara que no se crearon duplicados. Editó su pregunta después de que se publicó esta respuesta. –

5

Si su método de fábrica devuelve el mismo objeto para entradas iguales, es seguro compararlos con ==. Por ejemplo, String.intern funciona de esta manera. Los mensajes también se pueden comparar con ==. Pero Integer.valueOf devuelve el mismo objeto solo para el rango -128 ... 127 (en la configuración predeterminada).

Integer.valueOf(127) == Integer.valueOf(127) 

pero

Integer.valueOf(128) != Integer.valueOf(128) 

En términos generales se debe utilizar es igual método para comparar los objetos. El operador == podría usarse para mejorar el rendimiento, cuando hay un número pequeño de valores diferentes para el objeto. No recomendaría usar este método, a menos que esté 100% seguro de lo que está haciendo.

+0

Gracias por entender la pregunta en lugar de indicar el obvio. Entonces, mi propia clase inmutable, ¿está bien usar == en lugar de iguales si puedo asegurar que nunca existirán duplucates? – CKing

+0

Si su método de fábrica funciona correctamente y nadie hará algunas cosas sucias como llamar a constructores privados mediante reflexión, todo debería funcionar. Entonces, si tienes buenas razones para hacerlo, adelante. – vbezhenar

2

La inmutabilidad y la igualdad no tienen necesariamente algo que ver entre sí. == se compara para igualdad de referencia, es decir, se compara si ambas variables apuntan a la misma instancia del objeto. Igualdad significa que ambos objetos comparten el mismo valor. La inmutabilidad ahora significa que no puedes alterar un objeto después de su construcción.

Entonces, puede tener dos obejcts inmutables, que representan el mismo valor (es decir, son iguales para que a.equals (b) devuelva verdadero) pero que no son la misma instancia.

Tengo un pequeño ejemplo para usted aquí:

 
public class MyPoint { 
    private int x; 
    private int y; 

    public MyPoint(int x, int y) { 
     this.x = x; 
     this.y = y; 
    } 

    public int getX() { 
     return x; 
    } 

    public int getY() { 
     return y; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (!(obj instanceof MyPoint)) 
      return false; 
     MyPoint p = (MyPoint) obj; 
     return this.x == p.x && this.y == p.y; 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     MyPoint p = new MyPoint(2, 2); 
     MyPoint q = new MyPoint(2, 2); 
     MyPoint r = q; 

     System.out.println(p == q); 
     System.out.println(p == r); 
     System.out.println(q == r); 
     System.out.println(p.equals(q)); 
     System.out.println(p.equals(r)); 
     System.out.println(q.equals(r)); 

    } 

}

La salida es: falsa falsa cierto cierto cierto cierto

MyPoint es inmutable . No puede cambiar sus valores/su estado después de que se haya inicializado. Pero, como puede ver, dos objetos de myPoint pueden ser igual a, pero es posible que no sean la misma instancia.

Creo que lo que tienes en mente es algún tipo de patrón de peso mosca, donde solo existe un objeto para cada estado posible del objeto. El peso mosca también significa comúnmente que esos obejcts son inmutables.

+0

¡Gracias por la referencia de peso mosca! – CKing

Cuestiones relacionadas