Estou usando o Eclipse para gerar .equals()
e .hashCode()
, e há uma opção chamada "Use 'instanceof' para comparar tipos". O padrão é que essa opção seja desmarcada e usada .getClass()
para comparar tipos. Existe alguma razão eu preferiria .getClass()
mais instanceof
?
Sem usar instanceof
:
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Usando instanceof
:
if (obj == null)
return false;
if (!(obj instanceof MyClass))
return false;
Costumo marcar a instanceof
opção e, em seguida, removo a if (obj == null)
verificação. (É redundante, pois os objetos nulos sempre falham instanceof
.) Existe algum motivo para que seja uma má idéia?
java
eclipse
equals
instanceof
Kip
fonte
fonte
x instanceof SomeClass
é falsa sex
fornull
. Portanto, a segunda sintaxe não precisa da verificação nula.Respostas:
Se você usar
instanceof
, tornando a suaequals
implementaçãofinal
irá preservar o contrato simetria do método:x.equals(y) == y.equals(x)
. Sefinal
parecer restritivo, examine cuidadosamente sua noção de equivalência de objetos para garantir que suas implementações principais mantenham completamente o contrato estabelecido pelaObject
classe.fonte
final
parece restritivo" (em ambosequals
ehashCode
), usegetClass()
igualdade em vez deinstanceof
, a fim de preservar os requisitos de simetria e transitividade doequals
contrato.Josh Bloch favorece sua abordagem:
Veja também esta resposta SO .
O capítulo 3 efetivo sobre Java também cobre isso.
fonte
getClass
não viola o LSP, uma vez que o LSP se refere apenas ao que pode ser feito com instâncias existentes - e não a que tipos de instâncias podem ser construídos. A classe retornada porgetClass
é uma propriedade imutável de uma instância do objeto. O LSP não implica que seja possível criar uma subclasse em que essa propriedade indique qualquer classe que não seja a que o criou.Angelika Langers Segredos dos iguais entra nisso com uma discussão longa e detalhada de alguns exemplos comuns e conhecidos, incluindo Josh Bloch e Barbara Liskov, descobrindo alguns problemas na maioria deles. Ela também entra no
instanceof
vsgetClass
. Algumas citações delefonte
O motivo para usar
getClass
é garantir a propriedade simétrica doequals
contrato. Dos JavaDocs da equals:Usando instanceof, é possível não ser simétrico. Considere o exemplo: Cão estende Animal. Animal
equals
faz umainstanceof
verificação de Animal. Dog'sequals
faz umainstanceof
verificação de Dog. Dê Animal a e Cão d (com outros campos iguais):Isso viola a propriedade simétrica.
Para seguir rigorosamente o contrato da equal, a simetria deve ser garantida e, portanto, a classe precisa ser a mesma.
fonte
a.equals(c)
eb.equals(c)
, em seguida,a.equals(b)
(a abordagem ingênua de fazerDog.equals
apenasreturn super.equals(object)
quando!(object instanceof Dog)
, mas a verificação dos campos extras quando é um exemplo do cão não violaria simetria mas violaria transitividade)getClass()
verificação de igualdade ou umainstanceof
verificação se criar seus métodosequals
e .hashCode
final
Isso é um debate religioso. Ambas as abordagens têm seus problemas.
Bloch tem outro conselho relevante no Effective Java Second Edition :
fonte
getClass
violaria o LSP, a menos que a classe base documentasse especificamente um meio pelo qual seria possível criar instâncias de subclasses diferentes que se comparam da mesma forma. Que violação de LSP você vê?getClass()
não deve ser considerado significativo além do fato de que a classe em questão é conversível na classe base, o retorno degetClass()
deve ser considerado como qualquer outra propriedade que deve corresponder para que as instâncias sejam iguais.Corrija-me se eu estiver errado, mas getClass () será útil quando você quiser garantir que sua instância NÃO seja uma subclasse da classe com a qual você está comparando. Se você usar instanceof nessa situação, NÃO poderá saber porque:
fonte
Se você quiser garantir que apenas essa classe corresponda, use
getClass() ==
. Se você deseja combinar subclasses,instanceof
é necessário.Além disso, instanceof não corresponderá a um nulo, mas é seguro comparar com um nulo. Portanto, você não precisa anulá-lo.
fonte
Depende se você considerar se uma subclasse de uma determinada classe é igual ao seu pai.
aqui eu usaria 'instanceof', porque eu quero que um sobrenome seja comparado ao nome da família
aqui eu usaria 'getClass', porque a classe já diz que as duas instâncias não são equivalentes.
fonte
instanceof funciona para instâncias da mesma classe ou de suas subclasses
ArryaList e RoleList são ambos instanceof List
Enquanto
getClass () == o.getClass () será verdadeiro somente se os dois objetos (this e o) pertencerem exatamente à mesma classe.
Portanto, dependendo do que você precisa comparar, você pode usar um ou outro.
Se sua lógica é: "Um objeto é igual a outro somente se ambos são da mesma classe", você deve procurar o "igual", que eu acho que é a maioria dos casos.
fonte
Ambos os métodos têm seus problemas.
Se a subclasse alterar a identidade, será necessário comparar as classes reais. Caso contrário, você violará a propriedade simétrica. Por exemplo, diferentes tipos de
Person
s não devem ser considerados equivalentes, mesmo que tenham o mesmo nome.No entanto, algumas subclasses não alteram a identidade e precisam ser usadas
instanceof
. Por exemplo, se tivermos um monte deShape
objetos imutáveis , então umRectangle
com comprimento e largura de 1 deve ser igual à unidadeSquare
.Na prática, acho que é mais provável que o caso anterior seja verdadeiro. Geralmente, a subclasse é uma parte fundamental da sua identidade e ser exatamente como seus pais, exceto que você pode fazer uma coisinha não faz com que você seja igual.
fonte
Na verdade, instanceof verifica onde um objeto pertence a alguma hierarquia ou não. ex: o objeto Carro pertence à classe Vehical. Portanto, a "nova instância Car () do Vehical" retorna verdadeira. E "new Car (). GetClass (). Equals (Vehical.class)" retorna false, embora o objeto Car pertença à classe Vehical, mas seja classificado como um tipo separado.
fonte