Ich steckte in einer Falle fest, als ich meine eigenen Klassen equals und hashCode in Java mit IDE generierte

Voraussetzungen

--IntelliJ-Version ist die neueste Version 2019.2 vom 13. September 2019

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

Yuki Kotonari

Wenn ich meine eigene Klasse in Java definiere, funktioniert meine eigene Klassensammlung nur dann ordnungsgemäß, wenn ich equals und hashCode ordnungsgemäß überschreibe.

Dieses Mal habe ich eine einfache Originalklasse definiert und mit einer IDE namens IntelliJ equals und hashCode generiert, aber ich war süchtig danach, also werde ich sie teilen.

--Erster Code, den ich geschrieben habe: Ich habe meine eigene Klasse namens "DistanceToNode" definiert und für diese Klasse Folgendes getan:

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

――Ich hatte hier einige Tage lang Kopfschmerzen, aber wenn Sie sich den von IntelliJ generierten Code genau ansehen, verwenden sowohl equals als auch hashCode intern die Methoden super.equals und super.hashCode !!! Hier Ich dachte, dass es funktionieren würde, wenn ich es so umschreibe, dass es nicht super.equals oder super.hashCode verwendet, also habe ich den Code wie folgt geändert. (Ich habe auch den Klassennamen geändert.)

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

Nachwort

――IntelliJ ist praktisch, aber ich habe eine wertvolle Lektion gelernt, dass Sie nicht blind sein sollten und manchmal Ihren eigenen Kopf benutzen müssen. ――Ich habe mich gefragt, warum ein solcher Code erstellt wird, wenn IntelliJ automatisch Gleichheits- und Hashcode generiert. Gibt es einen vernünftigen Grund? ――Ich wurde in den Kommentaren darüber informiert, aber für Klassen, die eine andere konkrete Klasse als die Object-Klasse erben, möchte ich nicht gleich true setzen, wenn die Mitgliedsvariablen der übergeordneten Klasse nicht übereinstimmen. Ich denke, deshalb ist es so. In diesem Fall empfand ich dieses Anliegen von IntelliJ als störend, da es sich um eine Klasse handelt, die die Object-Klasse direkt erbt. Ich glaube nicht, dass es für die IDE schwierig ist festzustellen, ob es sich um eine Klasse handelt, die die Object-Klasse direkt erbt. Daher frage ich mich, ob ein Kommentar des IntelliJ-Entwicklers dies beheben wird. --__ 9/14 Update __: Etwas Ähnliches wie die Frage, die ich hatte, wurde bereits veröffentlicht-> https://intellij-support.jetbrains.com/hc/en-us/community/posts/206873545 -Strange-generate-hashCode-

Recommended Posts

Ich steckte in einer Falle fest, als ich meine eigenen Klassen equals und hashCode in Java mit IDE generierte
[java] Was ich getan habe, als ich Listen in meiner eigenen Klasse verglichen habe
Verstehe gleich und hashCode in Java
[Java Spring MVC] Ich möchte DI in meiner eigenen Klasse verwenden
Implementieren Sie Thread in Java und versuchen Sie, die anonyme Klasse Lambda zu verwenden
[Java] HashCode und gleich Überschreibung
StringBuffer- und StringBuilder-Klasse in Java
Ich habe versucht, JWT in Java zu verwenden
Ich habe die Punkte zusammengefasst, die bei der kombinierten Verwendung von Ressourcen und Ressourcen zu beachten sind
Ich habe versucht, mit OpenTrip Planner und GTFS eine eigene Übertragungsanleitung zu erstellen
Rückgabewert bei Verwendung von Java Nr. 1 Optional.ifPresent, das im Geschäftsleben nützlich war
Ich habe versucht, die Elasticsearch-API in Java zu verwenden
Bei Verwendung einer Liste in Java wird java.awt.List ausgegeben und ein Fehler tritt auf
Seien Sie vorsichtig mit Anfragen und Antworten, wenn Sie das Serverless Framework mit Java verwenden
Java-Methodenaufruf von RPG (Methodenaufruf in eigener Klasse)
So erhalten Sie den Klassennamen des Arguments von LoggerFactory.getLogger, wenn Sie SLF4J in Java verwenden
[Java] Vorsichtsmaßnahmen beim Referenzieren in einer übergeordneten Klasse und beim Instanziieren in einer untergeordneten Klasse