¿Alguna razón para preferir getClass() sobre instanciade al generar .equals()?
Estoy usando Eclipse para generar .equals()
y .hashCode()
, y hay una opción denominada "Usar 'instancia de' para comparar tipos". El valor predeterminado es que esta opción no esté marcada y se use .getClass()
para comparar tipos. ¿Hay alguna razón por la que debería .getClass()
preferirlo instanceof
?
Sin uso 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;
Normalmente marco la instanceof
opción y luego entro y elimino la if (obj == null)
marca " ". (Es redundante ya que los objetos nulos siempre fallarán instanceof
). ¿Hay alguna razón por la que sea una mala idea?
Josh Bloch favorece su enfoque:
La razón por la que estoy a favor de este
instanceof
enfoque es que cuando lo usasgetClass
, tienes la restricción de que los objetos sólo son iguales a otros objetos de la misma clase, el mismo tipo de tiempo de ejecución. Si extiende una clase y le agrega un par de métodos inofensivos, luego verifica si algún objeto de la subclase es igual a un objeto de la superclase, incluso si los objetos son iguales en todos los aspectos importantes, obtendrá el sorprendente respuesta de que no son iguales. De hecho, esto viola una interpretación estricta del principio de sustitución de Liskov y puede conducir a un comportamiento muy sorprendente. En Java, es particularmente importante porque la mayoría de las colecciones (HashTable
, etc.) se basan en el método igual. Si coloca un miembro de la superclase en una tabla hash como clave y luego lo busca usando una instancia de subclase, no lo encontrará porque no son iguales.
Vea también esta respuesta SO .
El capítulo 3 de Java efectivo también cubre esto.
Si usa instanceof
, realizar su equals
implementación final
preservará el contrato de simetría del método: x.equals(y) == y.equals(x)
. Si final
parece restrictivo, examine cuidadosamente su noción de equivalencia de objetos para asegurarse de que sus implementaciones primordiales mantengan completamente el contrato establecido por la Object
clase.
Lo que intento decir aquí es que si cree que getClass()
es la única forma confiable de preservar la simetría, probablemente esté usando equals()
el método incorrecto.
Claro, es fácil de usar getClass()
para preservar la simetría requerida equals()
, pero solo porque x.equals(y)
y y.equals(x)
siempre son falsos. La sustituibilidad de Liskov lo alentaría a encontrar una implementación que preserve la simetría y que pueda rendir true
cuando tenga sentido. Si una subclase tiene una noción de igualdad radicalmente diferente, ¿es realmente una subclase?