java - from - List.contains() falla mientras funciona.equals()
override contains java (4)
El hecho de que los Test
equals
su Test
puedan volverse verdaderos cuando le pasa un String no significa que los equals
String
volverán a ser verdaderos cuando le pase una instancia de Test
. De hecho, los equals
String
solo pueden devolver true
cuando la instancia que se le pasa es otra String
:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) { // the passed instance must be a String
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
ArrayList
contains
llamadas indexOf
que utiliza el método equals
de la instancia buscada (la String
"a" en su ejemplo), no el tipo de elemento de la List
(que es Test
en su caso):
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i])) // o in your case is a String while
// elementData[i] is a Test
// so String''s equals returns false
return i;
}
return -1;
}
Tengo un objeto ArrayList
de objetos de Test
, que usan una cadena como verificación de equivalencia. Quiero poder usar List.contains()
para verificar si la lista contiene un objeto que usa una cadena determinada.
Simplemente:
Test a = new Test("a");
a.equals("a"); // True
List<Test> test = new ArrayList<Test>();
test.add(a);
test.contains("a"); // False!
Función de igual y hash:
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (!(o instanceof Test)) {
return (o instanceof String) && (name.equals(o));
}
Test t = (Test)o;
return name.equals(t.GetName());
}
@Override
public int hashCode() {
return name.hashCode();
}
Leí eso para asegurarme de que contains
trabajos para una clase personalizada, necesita anular equals
. Por lo tanto, es muy extraño para mí que si bien equals
devuelve verdadero, contains
retornos como falso.
¿Cómo puedo hacer que esto funcione?
El problema es que List<E>.contains(object o)
está documentado para devolver true:
si y solo si esta lista contiene al menos un elemento e tal que (o == null? e == null: o.equals (e)).
(Desde https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object- )
Tenga en cuenta que no realiza la prueba como e.equals(o)
que es lo que sería necesario para que su prueba funcione. Su método equals no funciona de manera conmutativa (''simétricamente'' usando los términos de los documentos de Java).
Java documenta que el método equals()
para una clase debe seguir estas reglas:
El método equals implementa una relación de equivalencia en referencias de objetos no nulos:
- Es reflexivo: para cualquier valor de referencia no nulo
x
,x.equals(x)
debe devolver verdadero.- Es simétrico: para cualquier valor de referencia no nulo
x
ey
,x.equals(y)
debería devolver verdadero si y solo siy.equals(x)
devuelve verdadero.- Es transitivo: para cualquier valor de referencia no nulo
x
,y
yz
, six.equals(y)
devuelve true yy.equals(z)
devuelve true, entoncesx.equals(z)
debe devolver true.- Es consistente: para cualquier valor de referencia no nulo
y
, las múltiples invocaciones dex.equals(y)
devuelven consistentemente verdadero o devuelven falso constantemente, siempre que no se modifique la información utilizada en comparaciones iguales en los objetos.- Para cualquier valor de referencia que no sea nulo
x
,x.equals(null)
debe devolver falso.
Si tú escribes
test.contains(new Test("a"));
entonces seguramente volverá verdadero. Está buscando un objeto de cadena en la lista de Prueba.
equals()
siempre debe ser commutative , es decir, a.equals(b)
y b.equals(a)
siempre deben devolver el mismo valor. O simétrico , como lo llama el javadoc de equals()
:
El método
equals
implementa una relación de equivalencia en referencias de objetos no nulos:
- Es reflexivo : para cualquier valor de referencia no nulo
x
,x.equals(x)
debe devolvertrue
.- Es simétrico : para cualquier valor de referencia no nulo
x
ey
,x.equals(y)
debería devolvertrue
si y solo siy.equals(x)
devuelvetrue
.- Es transitivo : para cualquier valor de referencia no nulo
x
,y
yz
, six.equals(y)
devuelvetrue
yy.equals(z)
devuelvetrue
, entoncesx.equals(z)
debe devolvertrue
.- Es consistente : para cualquier valor de referencia no nulo
y
, las múltiples invocaciones dex.equals(y)
devuelven consistentementetrue
o devuelvenfalse
constantemente, siempre que no se modifique la información utilizada en comparacionesequals
en los objetos.- Para cualquier valor de referencia no nulo
x
,x.equals(null)
debería devolverfalse
.
Desafortunadamente, incluso la Biblioteca de tiempo de ejecución de Java lo equivoca. Date.equals(Timestamp)
comparará los valores de milisegundos, ignorando los nanosegundos presentes en la Timestamp
, mientras que Timestamp.equals(Date)
devuelve false
.