J'ai été piégé lorsque j'ai généré mes propres égaux de classe et hashCode en Java à l'aide de l'IDE

Conditions préalables

$ java -version
java version "10.0.2" 2018-07-17

Yuki Kotonari

Lorsque je définis ma propre classe en Java, ma propre collection de classes ne fonctionne pas correctement à moins que je ne remplace correctement ʻequalsethashCode`.

Cette fois, j'ai défini une classe originale simple et généré ʻequals et hashCode` en utilisant un IDE appelé IntelliJ, mais j'en étais accro, donc je vais le partager.

import java.util.*;

public class TestEqualsOld {
    public static void main(String[] args) {
        Set<DistanceToNode> someSet = new HashSet<>();
        someSet.add(new DistanceToNode(1, 2));
        System.out.println("actual = " + someSet.size() + " expected = 1");
        someSet.add(new DistanceToNode(2, 3));
        System.out.println("actual = " + someSet.size() + " expected = 2");
        someSet.remove(new DistanceToNode(1, 2));
        System.out.println("actual = " + someSet.size() + " expected = 1");
        boolean flag = new DistanceToNode(3, 4).equals(new DistanceToNode(3, 4));
        System.out.println("actual = " + flag + " expected = true");
    }
}

class DistanceToNode {
    private int dist;
    private int index;

    public DistanceToNode(int dist, int index) {
        this.dist = dist;
        this.index = index;
    }

    public int getDist() {
        return dist;
    }

    public int getIndex() {
        return index;
    }
}
actual = 1 expected = 1
actual = 2 expected = 2
actual = 2 expected = 1
actual = false expected = true
import java.util.*;

public class TestEqualsOld {
    public static void main(String[] args) {
        Set<DistanceToNode> someSet = new HashSet<>();
        someSet.add(new DistanceToNode(1, 2));
        System.out.println("actual = " + someSet.size() + " expected = 1");
        someSet.add(new DistanceToNode(2, 3));
        System.out.println("actual = " + someSet.size() + " expected = 2");
        someSet.remove(new DistanceToNode(1, 2));
        System.out.println("actual = " + someSet.size() + " expected = 1");
        boolean flag = new DistanceToNode(3, 4).equals(new DistanceToNode(3, 4));
        System.out.println("actual = " + flag + " expected = true");
    }
}

class DistanceToNode {
    private int dist;
    private int index;

    public DistanceToNode(int dist, int index) {
        this.dist = dist;
        this.index = index;
    }

    public int getDist() {
        return dist;
    }

    public int getIndex() {
        return index;
    }

    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        if (!super.equals(object)) return false;
        DistanceToNode that = (DistanceToNode) object;
        return dist == that.dist &&
                index == that.index;
    }

    public int hashCode() {
        return Objects.hash(super.hashCode(), dist, index);
    }
}
actual = 1 expected = 1
actual = 2 expected = 2
actual = 2 expected = 1
actual = false expected = true

―― J'ai eu mal à la tête pendant quelques jours ici, mais si vous regardez de près le code généré par IntelliJ, ʻequalsethashCode` utilisent les méthodes super.equals et super.hashCode en interne !!! J'ai pensé que cela fonctionnerait si je le réécrivais pour qu'il n'utilise pas super.equals ou super.hashCode, j'ai donc modifié le code comme suit. (J'ai également changé le nom de la classe.)

import java.util.*;

public class TestEquals {
    public static void main(String[] args) {
        Set<DistanceToNode> someSet = new HashSet<>();
        someSet.add(new DistanceToNode(1, 2));
        System.out.println(someSet.size());
        someSet.add(new DistanceToNode(2, 3));
        System.out.println(someSet.size());
        someSet.remove(new DistanceToNode(1, 2));
        System.out.println(someSet.size());
        boolean flag = new DistanceToNode(3, 4).equals(new DistanceToNode(3, 4));
        System.out.println(flag);
    }
}

class DistanceToNode {
    private int dist;
    private int index;

    public DistanceToNode(int dist, int index) {
        this.dist = dist;
        this.index = index;
    }

    public int getDist() {
        return dist;
    }

    public int getIndex() {
        return index;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        // if (!super.equals(object)) return false;
        DistanceToNode distanceToNode = (DistanceToNode) object;
        return dist == distanceToNode.dist &&
                index == distanceToNode.index;
    }

    @Override
    public int hashCode() {
        int result = 31;
        result = 31 * result + dist;
        result = 31 * result + index;
        return result;
        // return Objects.hash(super.hashCode(), dist, index);
    }
}
actual = 1 expected = 1
actual = 2 expected = 2
actual = 1 expected = 1
actual = true expected = true

Épilogue

――IntelliJ est pratique, mais j'ai appris une leçon précieuse: il ne faut pas être aveugle et parfois il faut utiliser sa propre tête. ――Je me suis demandé pourquoi un tel code est créé lorsque IntelliJ génère automatiquement des valeurs égales et hashCode, et y a-t-il une raison raisonnable?

Recommended Posts

J'ai été piégé lorsque j'ai généré mes propres égaux de classe et hashCode en Java à l'aide de l'IDE
[java] Ce que j'ai fait en comparant des listes dans ma propre classe
Comprendre equals et hashCode en Java
[Java Spring MVC] Je souhaite utiliser DI dans ma propre classe
Implémentez Thread en Java et essayez d'utiliser la classe anonyme Lambda
[Java] HashCode et remplacement égal
Classe StringBuffer et StringBuilder en Java
J'ai essayé d'utiliser JWT en Java
J'ai résumé les points à noter lors de l'utilisation combinée des ressources et des ressources
J'ai essayé de créer mon propre guide de transfert en utilisant OpenTrip Planner et GTFS
Valeur renvoyée lors de l'utilisation de Java n ° 1 Facultatif.if Présent qui a été utile en entreprise
J'ai essayé d'utiliser l'API Elasticsearch en Java
Lors de l'utilisation d'une liste en Java, java.awt.List sort et une erreur se produit
Soyez prudent avec les demandes et les réponses lors de l'utilisation de Serverless Framework avec Java
Appel de méthode Java depuis RPG (appel de méthode dans sa propre classe)
Comment obtenir le nom de classe de l'argument de LoggerFactory.getLogger lors de l'utilisation de SLF4J en Java
[Java] Précautions lors du référencement dans une classe parent et de l'instanciation dans une classe enfant