2008-12-12 5 views
11

Lors de l'exécution de FindBugs sur mon projet, j'ai rencontré quelques instances de l'erreur décrite ci-dessus. En d'autres termes, mes versions précédentes d'égal à égal transforment l'objet RHS en le même type que l'objet dans lequel la version de remplacement est définie.Findbugs warning: La méthode Equals ne doit pas prendre en compte le type de son argument

Cependant, je ne suis pas sûr si une meilleure conception est possible, AFAIK Java n'autorisant pas la variance dans les paramètres de la méthode, il n'est donc pas possible de définir un autre type pour le paramètre equals. Est-ce que je fais quelque chose de très mal, ou FindBugs est-il trop impatient? Une autre façon de formuler cette question est: quel est le comportement correct si l'objet passé à égal n'est pas du même type qu'un LHS: est-ce un faux, ou devrait-il y avoir une exception?

Par exemple:

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

cela semble un peu étrange. s'il vous plaît nous montrer du code. –

Répondre

27

En règle générale, la mise en œuvre, vous pouvez égale vérifier si la classe de l'argument est égal (ou compatible) à la classe d'exécution avant de le jeter. Quelque chose comme ceci:

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

En procédant ainsi empêchera l'avertissement FindBugs.

Une note de côté pour répondre à un commentaire:
Certaines personnes affirment utiliser instanceof au lieu de getClass pour vérifier la sécurité de type. Il y a un grand débat là-dessus, que j'essayais de ne pas aborder lorsque j'ai noté que vous pouvez vérifier la compatibilité de la classe ou, mais je suppose que je ne peux pas y échapper. Cela se résume à cela - si vous utilisez instanceof vous pouvez soutenir l'égalité entre les instances d'une classe et les instances de sa sous-classe, mais vous risquez de rompre le contrat symétrique de equals. En règle générale, je recommande de ne pas utiliser instanceof sauf si vous savez que vous en avez besoin et vous savez ce que vous faites. Pour plus d'informations, voir:

+4

Essentiellement ce que cela signifie: plutôt que de lancer une exception ClassCastException, votre méthode equals() devrait renvoyer false. – Darron

+0

Mais est-ce la bonne pratique dans ces situations? Je veux dire, idéalement j'aurais aimé une vérification de type à la compilation, que je ne peux pas obtenir à cause des limitations de Java. – Uri

+0

Pourquoi? Quel est le problème avec la vérification de l'égalité entre les types non liés? C'est une question avec une réponse parfaitement bien et bien définie. –

7

Vous êtes probablement faire quelque chose comme ceci:

public class Foo { 
    // some code 

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

Dans cet exemple, vous assumez quelque chose sur l'argument d'égal à égal(): Vous assumez c'est de type Foo. Cela ne doit pas être le cas! Vous pouvez également obtenir une chaîne (auquel cas vous devriez presque certainement retourner faux).

Donc, votre code devrait ressembler à ceci:

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

(ou utiliser plus strictes getClass() != o.getClass() mentionné par Dave L.

Vous pouvez aussi regarder cette façon:

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

Y at-il une raison pour laquelle ce code devrait lancer un ClassCastException au lieu de terminer normalement et de définir b àdix ?

Jeter un ClassCastException en réponse à .equals() ne serait pas raisonnable. Parce que même si c'est une question stupide ("Bien sûr, une chaîne n'est jamais égale à un Foo!"), Elle est toujours valide avec une réponse parfaitement bonne ("non" == false).

0

Je commence mes equals (Object) mises en œuvre comme ceci:

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

Cela permettra également d'éviter l'avertissement FindBugs mais ne reviendra pas automatiquement false quand une sous-classe de ThisClass est remis Il pourrait aussi être envisagée. égal, surtout si sa méthode equals(Object) n'a pas été surchargée.

+3

La vérification null est redondante avec instanceof. Soyez prudent en utilisant instanceof; Si le contrat raffiné d'un non-final n'équilibre pas les conditions d'égalité (comme java.util.Set), vous risquez de casser l'exigence de symétrie. – erickson

1

Je recommande d'ignorer l'avertissement findbugs. En pratique, si equals est appelé avec un objet d'une classe inattendue, c'est presque certainement un bug, et vous voulez échouer rapidement sur les bugs. Par exemple, si vous avez un 'ArrayList files' et appelez files.contains ("MyFile.txt"), ce serait bien si vous avez une exception ClassCastException. Au lieu de cela, Java renvoie juste false, et il faudra probablement beaucoup de temps jusqu'à ce que vous découvriez ce bug.

Questions connexes