2008-12-12 7 views
11

Al ejecutar FindBugs en mi proyecto, tengo algunas instancias del error descrito anteriormente.Advertencia de Findbugs: el método Equals no debería asumir nada sobre el tipo de su argumento

A saber, mis versiones primordiales de iguales arrojan el objeto RHS en el mismo tipo que el objeto en el que se define la versión principal.

Sin embargo, no estoy seguro de si es posible un mejor diseño, ya que AFAIK Java no permite la variación en los parámetros del método, por lo que no es posible definir ningún otro tipo para el parámetro igual.

¿Estoy haciendo algo muy malo o los FindBugs están demasiado ansiosos?

Una forma diferente de expresar esta pregunta es: cuál es el comportamiento correcto si el objeto pasado a igual no es del mismo tipo que un LHS: ¿Es falso o debería haber una excepción?

Por ejemplo:

public boolean equals(Object rhs) 
{ 
    MyType rhsMyType = (MyType)rhs; // Should throw exception 
    if(this.field1().equals(rhsMyType.field1())... // Or whatever 
} 
+0

suena un poco extraño. por favor muéstranos un código. –

Respuesta

27

Por lo general, en la aplicación es igual que usted puede comprobar para ver si la clase del argumento es igual (o compatible) a la clase que implementa antes de depositarlo. Algo como esto:

if (getClass() != obj.getClass()) 
    return false; 
MyObj myObj = (MyObj) obj; 

Al hacerlo de esta forma se evitará la advertencia FindBugs.

una nota al margen para hacer frente a un comentario:
Algunas personas sostienen a utilizar en lugar de instanceofgetClass para comprobar la seguridad de tipos. Hay un gran debate sobre eso, en el que traté de no entrar cuando noté que puede verificar la compatibilidad de clase o, pero supongo que no puedo evitarlo. Todo se reduce a esto: si usa instanceof, puede admitir la igualdad entre las instancias de una clase y las instancias de su subclase, pero corre el riesgo de romper el contrato simétrico de equals. En general, recomendaría no usar instanceof a menos que sepa que lo necesita y que sepa lo que está haciendo. Para obtener más información, véase:

+4

Esencialmente lo que esto significa es: en lugar de lanzar una ClassCastException, su método equals() debería devolver false. – Darron

+0

¿Pero es esa la práctica correcta en esas situaciones? Quiero decir, idealmente me hubiera gustado una verificación de tipo de tiempo de compilación, que no puedo obtener debido a las limitaciones de Java. – Uri

+0

¿Por qué? ¿Qué hay de malo en verificar la igualdad entre tipos no relacionados? Es una pregunta con una respuesta perfectamente fina y bien definida. –

7

probablemente estás haciendo algo como esto:

public class Foo { 
    // some code 

    public void equals(Object o) { 
    Foo other = (Foo) o; 
    // the real equals code 
    } 
} 

En este ejemplo, usted está asumiendo algo sobre el argumento de iguales(): Usted está asumiendo que es de tipo Foo. ¡Este no es el caso! También puede obtener un String (en cuyo caso, casi con certeza debe devolver false).

lo que el código debería tener este aspecto:

public void equals(Object o) { 
    if (!(o instanceof Foo)) { 
    return false; 
    } 
    Foo other = (Foo) o; 
    // the real equals code 
} 

(o utilizar el más estricto getClass() != o.getClass() mencionado por Dave L.

También puede ver de esta manera:

Integer i = new Integer(42); 
String s = "fourtytwo"; 
boolean b = i.equals(s); 

¿Hay alguna razón para que este código arroje un ClassCastException en lugar de terminar normalmente y establezca b en? 10?

Lanzar una ClassCastException como respuesta a .equals() no sería sensato. Porque incluso si es una pregunta estúpida ("¡Por supuesto que una Cadena nunca es igual a un Foo!"), Sigue siendo válida con una respuesta perfectamente correcta ("no" == false).

0

comienzo mi equals (Object) implementaciones de esta manera:

if ((object == null) || !(object instaceof ThisClass)) { 
    return false; 
} 

Esto también evitará que el aviso FindBugs pero no volverán automáticamente false cuando una subclase de ThisClass está siendo entregado También podría ser considerado. igual, especialmente si su método equals(Object) no ha sido anulado.

+3

La verificación nula es redundante con instanceof. Tenga cuidado al usar instanceof; si el contrato refinado de un igual no final no especifica las condiciones para la igualdad (como java.util.Set lo hace), es probable que se rompa el requisito de simetría. – erickson

1

Recomendaría ignorar dicha advertencia de findbugs. En la práctica, si se llama a igual con un objeto de una clase inesperada, es casi seguro que se trata de un error y desea fallar rápidamente en los errores.

Por ejemplo, si tiene un 'ArrayList files' y llama files.contains ("MyFile.txt"), sería bueno si tiene una ClassCastException. En cambio, Java simplemente devuelve falso, y es probable que demore un tiempo hasta que descubras ese error.

Cuestiones relacionadas