Como o método contains () de uma ArrayList avalia objects?

Digamos que eu crie um object e adicione-o à minha ArrayList . Se eu, então, criar outro object com exatamente a mesma input de construtor, o método contains() avaliará os dois objects como iguais? Suponha que o construtor não faça nada engraçado com a input, e as variables ​​armazenadas em ambos os objects são 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; } } 

É assim que a class deve ser implementada para conter contains() return true ?

ArrayList implements a interface de lista.

Se você olhar o Javadoc para List no método contains , verá que ele usa o método equals() para avaliar se dois objects são iguais.

Eu acho que implementações corretas devem 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; } } 

O ArrayList usa o método equals implementado na class (seu caso Thing class) para fazer a comparação equals.

Geralmente você também deve sobrescrever o hashCode() toda vez que você replace equals() , mesmo que apenas pelo aumento de desempenho. HashCode() decide em qual “bucket” seu object é classificado ao fazer uma comparação, portanto, quaisquer dois objects que equal() avaliados como true devem retornar o mesmo hashCode value() . Não consigo lembrar o comportamento padrão de hashCode() (se ele retornar 0, seu código deve funcionar, mas devagar, mas se ele retornar o endereço, seu código falhará). Eu lembro de um monte de vezes quando meu código falhou porque eu esqueci de replace hashCode() embora. 🙂

Ele usa o método equals nos objects. Portanto, a menos que Thing substitua equals e use as variables ​​armazenadas nos objects para comparação, ela não retornará true no 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; } } 

Você deve escrever:

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

Agora funciona;)

Só queria observar que a seguinte implementação está errada quando o value não é um 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; } } 

Nesse caso, proponho o seguinte:

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

Outros pôsteres abordaram a questão sobre como o contains () funciona.

Um aspecto igualmente importante da sua pergunta é como implementar corretamente igual (). E a resposta para isso é realmente dependente do que constitui a igualdade de object para essa class em particular. No exemplo que você forneceu, se você tem dois objects diferentes que possuem x = 5, eles são iguais? Isso realmente depende do que você está tentando fazer.

Se você está interessado apenas na igualdade de objects, então a implementação padrão de .equals () (aquela fornecida por Object) usa apenas a identidade (isto é, == outra). Se é isso que você quer, então não implemente equals () em sua class (deixe herdar de Object). O código que você escreveu, enquanto está correto se você está indo para a identidade, nunca apareceria em uma class real b / c não fornece nenhum benefício sobre o uso da implementação padrão Object.equals ().

Se você está apenas começando com essas coisas, eu recomendo fortemente o livro Effective Java de Joshua Bloch. É uma ótima leitura e abrange esse tipo de coisa (além de como implementar corretamente equals () quando você está tentando fazer mais do que comparações baseadas em identidade)

Atalho do JavaDoc :

contém booleano (object o)

Retorna true se essa lista contiver o elemento especificado. Mais formalmente, retorna true se e somente se essa lista contiver pelo menos um elemento e tal que (o == null? E == null: o.equals (e))