I need help on to override the equals method. I have everything working except for the equals method. The equals method that I currently have is not giving me the correct answer. I can not seem to figure out what could be the problem.
My Class:
package myclasses;
public class Currency
{
private int dollars, cents;
public Currency()
{
dollars = 0;
cents = 0;
}
public Currency(int d, int c)
{
this.dollars = d;
this.cents = c;
setCents(cents);
}
public int getDollars()
{
return dollars;
}
public int getCents()
{
return cents;
}
private void setDollars(int dollars)
{
this.dollars = dollars;
}
private void setCents(int cents)
{
while(cents > 99)
{
cents = (cents - 100);
dollars++;
}
this.cents = cents;
}
public void setAmount(int newDollars, int newCents)
{
setDollars(dollars);
setCents(cents);
}
public void add(int dollars, int cents)
{
this.dollars = dollars + getDollars();
cents = cents + getCents();
setCents(cents);
}
public boolean equals(Object dollars, Object cents)
{
if(this == dollars && this == cents)
return true;
if(!(dollars instanceof Currency) || !(cents instanceof Currency))
return false;
Currency money = (Currency) dollars;
Currency penny = (Currency) cents;
return (this.dollars == money.dollars) && (this.cents == penny.cents);
//return Currency.dollars.equals(Currency.cents);
//return this.equals(dollars) && this.equals(cents);
}
public boolean isZero()
{
if(getDollars() == 0 && getCents() == 0)
{
return true;
}
return false;
}
public String toString()
{
return "$" + getDollars() + "." +
(getCents() < 10 ? ("0" + getCents()) : getCents());
}
}
Your equals() method has some errors like:
if(this == dollars && this == cents)
This will never be true... this must be:
if(this.dollars == dollars && this.cents == cents)
But I won't put any effort in coding the equals, is recommended to autogenerate equals. Something like this:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Currency other = (Currency) obj;
if (cents != other.cents)
return false;
if (dollars != other.dollars)
return false;
return true;
}
Also is highly recommended, (nearly unavoidable as #AdriaanKoster commented) when you override equals() method, also override hashCode()
In equals() definition:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
Hash code:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + cents;
result = prime * result + dollars;
return result;
}
I'm not quite sure why you are going the first check in your equals method. But I'll tell you how I am usually doing my equals method
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null) {
return false;
} else if (getClass() != obj.getClass()) {
return false;
}
//a cast of object to the class you are using should be here
if (this.someField.equals(castObject.someField)
&& this.otherField.equals(castObject.otherField)) {
return true;
}
return false;
}
So here's what's happening. The first part of the method does basic checks - whether the object that you are testing is the same as the parameter, whether the object is null, and whether they are from the same class. Note that they are else if's because there are more than just those 3 cases.
If you've not entered any of the 3 initial conditional statements, you will need to make a cast of the obj parameter to the class that you are in. You are safe to do so because of the last if -
else if (getClass() != obj.getClass()) {
return false;
}
After that simply define the rule by which you determine whether two objects are the same. In the example that I'm using, I'm checking the contents of two fields of the class. If they are the same, then the objects are equal.
If you are overriding equals method, then your above code is not correctly overriding equals method.
use below code instead for overriding equals--
public boolean equals(Object currency) {
Currency newref = null;
if (currency instanceof Currency) {
newref = (Currency)currency;
}
return (this.dollars == newref.dollars) && (this.cents == newref.cents);
}
Related
This question already has answers here:
How the equals() method works
(8 answers)
What issues should be considered when overriding equals and hashCode in Java?
(11 answers)
Closed 5 years ago.
Consider:
class Dog{
int height;
int weight;
String name;
}
public class DogTest {
public static void main(String[] args) {
Dog one = new Dog();
one.height=4;
one.name="fudo";
one.weight =2;
Dog two = new Dog();
two.height=4;
two.name="fudo";
two.weight =2;
if (one.equals(two)){
System.out.println("True");
}
else{
System.out.println("False");
}
}
}
Why does this output "False"? If it is by default in Java that "all objects are not equal even if they have same values" then how can I "persuade" Java that these two objects actually are equal?
Okay, even if two dogs have same name, height, weight one could be Dalmatian and the other one pit bull, and even if they are the same "race", in nature, they can always be different from one another.
PS: I understand that by saying if (one==two) {} we are comparing if they both refer to the same object on the heap, .equals on string's compares if they have same characters in the same order.
The equals method by default says "Is this the same object in memory?" unless you override it.
You didn't override it.
The behavior didn't change.
You'll want to add a new method like this
public boolean equals(Object o) {
if(o instanceof Dog) {
Dog d = (Dog)(o);
Dog t = this;
return t.height == d.height && t.weight == d.weight && t.name.equals(d.name);
}
return false;
}
Stephan brings up a good point - never, ever, ever implment equals without hashCode. Always use the same fields in both.
public int hashCode() {
int hash = name.hashCode();
hash = hash * 31 + weight;
hash = hash * 31 + height;
return hash;
}
You have to override your equals method in your Dog class. If not you are just comparing if those objects are the same instance in memory.
Here is an implementation of how to do this:
class Dog{
int height;
int weight;
String name;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Dog)) return false;
Dog dog = (Dog) o;
if (height != dog.height) return false;
if (weight != dog.weight) return false;
return name != null ? name.equals(dog.name) : dog.name == null;
}
}
Any IDE allows you to generate a hashcode and equals in an automatic way as getters and setters.
In your case without hashcode and equals, you will get false, because the objects cannot being at the same memory location.
Your (working) example below:
class Dog{
int height;
int weight;
String name;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + height;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + weight;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dog other = (Dog) obj;
if (height != other.height)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (weight != other.weight)
return false;
return true;
}
public static void main(String[] args) {
Dog one = new Dog();
one.height=4;
one.name="fudo";
one.weight =2;
Dog two = new Dog();
two.height=4;
two.name="fudo";
two.weight =2;
if (one.equals(two)){
System.out.println("True");
}
else{
System.out.println("False");
}
}
}
Result:
To generate hashCode and equals in automatic way in Eclipse:
Right click in your class and:
I've a class called Skill as:
public class Skill {
private final int type;
private final int level;
public Skill(int type, int level) {
this.type = type;
this.level = level;
}
// Getters
#Override
public int hashCode() {
int h = 17;
h = 31 * h + type;
h = 31 * h + level;
return h;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj instanceof Skill) {
Skill that = (Skill) obj;
return this.type == that.type && this.level == that.level;
}
return false;
}
}
Another called PSkill as:
public class PSkill extends Skill {
private final int preferenceLevel;
private final boolean mandatory;
public PSkill(int type, int level, int preferenceLevel, boolean mandatory) {
super(type, level);
this.preferenceLevel = preferenceLevel;
this.mandatory = mandatory;
}
// Getters
#Override
public int hashCode() {
return super.hashCode();
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj instanceof PSkill) {
PSkill that = (PSkill) obj;
return super.equals(obj)
&& this.preferenceLevel == that.preferenceLevel
&& this.mandatory == that.mandatory;
}
return false;
}
}
My requirement:
Search a set of PSkill objects to find a match for Skill object.
For e.g.: Skill - type:1, level:2 is a match for PSkill - type:1, level:2, preferenceLevel: any, mandatory: any
When I run the below, it works.
public class Invoker {
public static void main(String[] args) {
Set<PSkill> skills = new HashSet<>(Arrays.asList(new PSkill(1, 1, 1, true), new PSkill(1, 2, 1, true)));
System.out.println(skills.contains(new Skill(1, 1))); // prints true
System.out.println(skills.contains(new Skill(1, 3))); // prints false
}
}
And I know why because the hashCode() implementation for both types is same and in HashSet implementation, key.equals(k) is used and key in my case is Skill object and hence, the equality works.
From HashSet implementation
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k)))) // here
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) // and here
return e;
} while ((e = e.next) != null);
}
}
return null;
}
I know I broke the hashCode() and equals() contract. But the code is working as it should, i.e. check if a Skill matches any of the PSkills in the set.
My question is:
Is the equality check key.equals(k) in HashSet implementation dependent and could be reversed in a future release i.e. k.equals(key) and the code will stop working?
Also, any better ways to do it which could make it less fragile without simply looping over the collection? Thanks
This behavior is certainly not guaranteed. The contract is that if you provide correct implementations of hashCode and equals, you get a correct implementation of a hashset. If you don't follow your end of the contract, you don't have any guarantees on how well a set will work.
public class Glasses {
String manufacturer;
int price;
String type;
Glasses() {
}
Glasses(String prd, int pr) {
manufacturer = prd;
price = pr;
}
Glasses(String prd, int pr, String t) {
manufacturer = prd;
price = pr;
type = t;
}
public static void Compare() {
}
}
this is my code and i want to compare 2 glasses like i initialise an object glasses1(ray-ban,200,squared) and glasses2(china,100,rounded) and I want them to be compared. How can i do that?
You can overwrite the method equals(Object) from class Object which returns the boolean if they are equal (you can define by yourself within this method what needs to be equal to define these instances as equal).
If you want the classes to be sortable for sorted map then you can implement the interface Comparable and the method int compare(Object).
For instance:
#Override
public int compareTo(Glasses other) {
if (equals(other)) {
return 0;
} else {
//FIXME: when is a Glasses object smaller then an other Glasses object??
return 0;
}
}
#Override
public boolean equals(Object o) {
boolean equal = false;
if (o instanceof Glasses) {
Glasses other = (Glasses) o;
equal = true;
equal &= (manufacturer == null && other.manufacturer == null) || (manufacturer != null && manufacturer.equals(other.manufacturer));
equal &= price == other.price;
equal &= (type == null && other.type == null) || (type != null && type.equals(other.type));
}
return equal;
}
The implementation of the compare method is buggy because I don't know your logic when a Glasses object is 'smaller' or 'bigger' than an other Glasses object. Maybe you just need the equals method?
Addition:
The equals method can be made a little bit smaller but maybe a little bit harder to understand (depends on the fact if you know the handling of the "?"-operator):
#Override
public boolean equals(Object o) {
boolean equal = false;
if (o instanceof Glasses) {
Glasses other = (Glasses) o;
equal = true;
equal &= manufacturer == null ? other.manufacturer == null : manufacturer.equals(other.manufacturer);
equal &= price == other.price;
equal &= type == null ? other.type == null : type.equals(other.type);
}
return equal;
}
We all know that if equals method returns true, then two objects are equal.
Can anybody give an example where 2 objects have the same hash value but they are actually different?
I'm assuming you're familiar with the contract(s) associated with overriding equals() and hashCode(), and the implications of a collision-prone hashCode implementation. Given that, the following trivial example uses an object that holds two Integers and implements a very simple hashCode, and demonstrates how easy it is to have two objects that aren't equal but have the same hashCode. Providing a more sophisticated hashCode algorithm can alleviate this.
The output of running main is:
hashCodes: ih1: 6, ih2: 6
equals: false
Example code:
package example.stackoverflow;
public class IntHolder
{
private Integer primaryData;
private Integer secondaryData;
public IntHolder(Integer primaryData, Integer secondaryData)
{
this.primaryData = primaryData;
this.secondaryData = secondaryData;
}
#Override
public int hashCode()
{
return ((primaryData == null) ? 0 : primaryData.hashCode()) +
((secondaryData == null) ? 0 : secondaryData.hashCode());
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IntHolder other = (IntHolder) obj;
if (primaryData == null)
{
if (other.primaryData != null)
return false;
}
else if (!primaryData.equals(other.primaryData))
return false;
if (secondaryData == null)
{
if (other.secondaryData != null)
return false;
}
else if (!secondaryData.equals(other.secondaryData))
return false;
return true;
}
public static void main(String[] args)
{
IntHolder ih1 = new IntHolder(1, 5);
IntHolder ih2 = new IntHolder(3, 3);
System.out.println("hashCodes: ih1: " + ih1.hashCode() + ", ih2: " + ih2.hashCode());
System.out.println("equals: " + ih1.equals(ih2));
}
}
For reference, Eclipse's auto-generated hashCode() for the IntHolder class is:
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result
+ ((primaryData == null) ? 0 : primaryData.hashCode());
result = prime * result
+ ((secondaryData == null) ? 0 : secondaryData.hashCode());
return result;
}
String str1="abcdef";
String str2="abcdfG";
They both have the same hashcode and equals method returns false.
public class Employee {
protected long employeeId;
public boolean equals(Object o){
if(o == null) return false;
if(!(o instanceof) Employee) return false;
Employee other = (Employee) o;
return this.employeeId == other.employeeId;
}
public int hashCode(){
return (int) this.employeeId;
}
}
In this example, we have overridden the equals method - two employees are equal when they will have same employee id.
If two Employee objects are equal, they will also have the same hash code.
Your Ans -
In this example, we also implemented the hash code - hashcode is the employeeId that is rounded down to an int. That means that many employee id's could result in the same hash code, but these Employee objects would still not be equal, since they don't have the same employee id.
I have two java user defined java objects, how can i make these two objects to return same references with case ignore
Sample code:
public class compare{
private String name;
private Integer number;
}
java.lang.String has a method for this:
myString.equalsIgnoreCase("MyStRiNg");
If this is not what you are looking for please be more specific.
You must override hashcode and equals to properly compare two objects. The following is an IDE generated hashCode and equals method.
class A
{
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((number == null) ? 0 : number.hashCode());
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A other = (A) obj;
if (name == null)
{
if (other.name != null)
return false;
}
else if (!name.equalsIgnoreCase(other.name))
return false;
if (number == null)
{
if (other.number != null)
return false;
}
else if (!number.equals(other.number))
return false;
return true;
}
String name;
Integer number;
}