I was trapped when I generated my own class equals and hashCode in Java using IDE

Prerequisites

--IntelliJ version is the latest version 2019.2 as of September 13, 2019

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

Yuki Kotonari

When I define my own classes in Java, my own collection of classes doesn't work properly unless I properly override ʻequalsandhashCode`.

This time, I defined a simple original class and generated ʻequals and hashCode` using an IDE called IntelliJ, but I was addicted to it, so I will share it.

--First code I wrote: I defined my own class called DistanceToNode and did the following for that class: --Add elements in Set-> Add another element-> Delete the first added element --Create two class instances with the same value and compare them with equals

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;
    }
}

--The execution result of this code is as follows. Even after remove an element from Set, the number of elements is 2, and when comparing two instances with the same value by equals, false is returned. Because we haven't overridden ʻequals and hashCode`, the method in the Object class, which is a super class, is used instead to determine if the references are equal, not if the values are equal. is there.

actual = 1 expected = 1
actual = 2 expected = 2
actual = 2 expected = 1
actual = false expected = true

--So, let's automatically generate ʻequalsandhashCode` of the previous code using IntelliJ. Place the cursor on the class, right-click and select Generate> equals () and hashCode (). I chose "IntelliJ Default" which is selected by default as Template. Then, the following code was generated.

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);
    }
}

――The result of executing the code did not change surprisingly! Is there a problem somewhere in ʻequals, hashCode` made by IntelliJ?

actual = 1 expected = 1
actual = 2 expected = 2
actual = 2 expected = 1
actual = false expected = true

――I had a headache for a few days here, but if you look closely at the code generated by IntelliJ, both ʻequalsandhashCode` use super.equals and super.hashCode methods internally !!! Here I thought that it would work if I rewrote it so that it does not use super.equals or super.hashCode, so I modified the code as follows. (I also changed the class name.)

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);
    }
}

--The result of executing the code is as follows! It seems that it is now possible to compare by value properly, which is good ...

actual = 1 expected = 1
actual = 2 expected = 2
actual = 1 expected = 1
actual = true expected = true

Afterword

――IntelliJ is convenient, but I learned a valuable lesson that you should not be blind and sometimes you have to use your own head. ――I wondered why such code is created when IntelliJ automatically generates equals and hashCode, and is there any reasonable reason? ――I was told in the comments, but for classes that inherit some concrete class other than the Object class, if the member variables of the parent class do not match, I do not want to set equals to true. I think that's why it's like this. In this case, because it is a class that directly inherits the Object class, I felt that this concern of IntelliJ was a nuisance. I don't think it's difficult for the IDE to determine if it's a class that directly inherits the Object class, so I wonder if it will be fixed by commenting to the IntelliJ developer. --__ 9/14 Update __: Something similar to the question I felt was already posted-> https://intellij-support.jetbrains.com/hc/en-us/community/posts/206873545 -Strange-generated-hashCode- --In the case of a class that directly inherits the Object class, just ask if it is possible to modify it so that it generates code that does not use the parent class equals or hashCode.

Recommended Posts

I was trapped when I generated my own class equals and hashCode in Java using IDE
[java] What I did when comparing Lists in my own class
Understanding equals and hashCode in Java
[Java Spring MVC] I want to use DI in my own class
Implement Thread in Java and try using anonymous class, lambda
[Java] HashCode and equals overrides
StringBuffer and StringBuilder Class in Java
I tried using JWT in Java
I summarized the points to note when using resources and resources in combination
I tried to make my own transfer guide using OpenTripPlanner and GTFS
Return value when using Java No. 1 Optional.ifPresent that was useful in business
I tried using Elasticsearch API in Java
When using a list in Java, java.awt.List comes out and an error occurs
Be careful with requests and responses when using the Serverless Framework in Java
Java method call from RPG (method call in own class)
How to get the class name of the argument of LoggerFactory.getLogger when using SLF4J in Java
[Java] Precautions when referencing a reference type in a parent class and instantiating it in a child class