--IntelliJ version is the latest version 2019.2 as of September 13, 2019
$ java -version
java version "10.0.2" 2018-07-17
When I define my own classes in Java, my own collection of classes doesn't work properly unless I properly override ʻequalsand
hashCode`.
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 ʻequalsand
hashCode` 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 ʻequalsand
hashCode` 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
――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