¿Cómo evalúa los objetos el método contains () de un ArrayList?

Digamos que creo un objeto y lo agrego a mi ArrayList . Si luego creo otro objeto con exactamente la misma entrada de constructor, ¿el método contains() evaluará que los dos objetos sean iguales? Supongamos que el constructor no hace nada gracioso con la entrada, y las variables almacenadas en ambos objetos son idénticas.

 ArrayList basket = new ArrayList(); Thing thing = new Thing(100); basket.add(thing); Thing another = new Thing(100); basket.contains(another); // true or false? 

 class Thing { public int value; public Thing (int x) { value = x; } equals (Thing x) { if (x.value == value) return true; return false; } } 

¿Es así como debería implementarse la class para que contains() return sea true ?

ArrayList implements la interfaz de lista.

Si observa Javadoc for List en el método contains , verá que usa el método equals() para evaluar si dos objetos son iguales.

Creo que las implementaciones correctas deberían ser

 public class Thing { public int value; public Thing (int x) { this.value = x; } @Override public boolean equals(Object object) { boolean sameSame = false; if (object != null && object instanceof Thing) { sameSame = this.value == ((Thing) object).value; } return sameSame; } } 

ArrayList usa el método equals implementado en la clase (su clase Thing de caso) para hacer la comparación de iguales.

En general, también debe anular hashCode() cada vez que anule equals() , incluso si solo se hashCode() boost el rendimiento. HashCode() decide en qué ‘cubo’ se ordena su objeto al hacer una comparación, de modo que cualquier objeto que equal() evalúa como verdadero debe devolver el mismo value() hashCode value() . No recuerdo el comportamiento predeterminado de hashCode() (si devuelve 0, entonces su código debería funcionar pero lentamente, pero si devuelve la dirección, entonces su código fallará). Recuerdo un montón de veces cuando mi código falló porque me olvidé de anular hashCode() sin embargo. 🙂

Utiliza el método igual en los objetos. De modo que, a menos que Thing overrides sea igual y use las variables almacenadas en los objetos para comparación, no devolverá true en el método contains() .

 class Thing { public int value; public Thing (int x) { value = x; } equals (Thing x) { if (x.value == value) return true; return false; } } 

Debes escribir:

 class Thing { public int value; public Thing (int x) { value = x; } public boolean equals (Object o) { Thing x = (Thing) o; if (x.value == value) return true; return false; } } 

Ahora funciona 😉

Solo quería señalar que la siguiente implementación es incorrecta cuando el value no es un tipo primitivo:

 public class Thing { public Object value; public Thing (Object x) { this.value = x; } @Override public boolean equals(Object object) { boolean sameSame = false; if (object != null && object instanceof Thing) { sameSame = this.value == ((Thing) object).value; } return sameSame; } } 

En ese caso, propongo lo siguiente:

 public class Thing { public Object value; public Thing (Object x) { value = x; } @Override public boolean equals(Object object) { if (object != null && object instanceof Thing) { Thing thing = (Thing) object; if (value == null) { return (thing.value == null); } else { return value.equals(thing.value); } } return false; } } 

Otros carteles han abordado la pregunta sobre cómo funciona contains ().

Un aspecto igualmente importante de su pregunta es cómo implementar correctamente equals (). Y la respuesta a esto depende realmente de lo que constituye la igualdad de objeto para esta clase en particular. En el ejemplo que proporcionó, si tiene dos objetos diferentes que tienen x = 5, ¿son iguales? Realmente depende de lo que estás tratando de hacer.

Si solo está interesado en la igualdad de objetos, entonces la implementación predeterminada de .equals () (la proporcionada por Object) usa solo identidad (es decir, = = otro). Si eso es lo que quieres, entonces no implemente equals () en tu clase (deja que herede de Object). El código que escribió, aunque es correcto si va en busca de identidad, nunca aparecería en una clase real b / c. No proporciona ningún beneficio sobre el uso de la implementación predeterminada de Object.equals ().

Si recién está comenzando con estas cosas, recomiendo encarecidamente el libro Effective Java de Joshua Bloch. Es una lectura excelente, y cubre este tipo de cosas (además de cómo implementar correctamente equals () cuando intenta hacer más que comparaciones basadas en la identidad)

Acceso directo desde JavaDoc :

boolean contains (Object o)

Devuelve verdadero si esta lista contiene el elemento especificado. Más formalmente, devuelve verdadero si y solo si esta lista contiene al menos un elemento e tal que (o == null? E == null: o.equals (e))