Java: Duplicate objects getting added to set? - java

If I run the below code then the output is 2 which means that the set contains 2 elements. However I think that set should contain 1 since both the objects are equal based on hashcode() value as well as .equals() method.
Seems like some obvious mistake in my understanding ?
package HELLO;
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) throws Exception {
Set<Alpha> s = new HashSet<Alpha>();
Alpha a1 = new Alpha();
Alpha a2 = new Alpha();
s.add(a1);
s.add(a2);
System.out.println(s.size());
}
}
class Alpha {
int a = 10;
public int hashcode() {
return a;
}
public boolean equals(Object obj) {
return (obj instanceof Alpha && ((Alpha) obj).a == this.a);
}
public String toString() {
return "Alpha : " + a;
}
}

Your hashcode method does not override the Object class's hashCode method and thus your equals method breaks contract since it doesn't agree with the hashCode results, and you can have objects that are "equal" but have different hashCodes.
Remember: You should always use the #Override annotation when overriding methods as this will help you catch this and similar errors.
#Override // ** don't forget this annotation
public int hashCode() { // *** note capitalization of the "C"
return a;
}
Also, you will want to improve your code formatting, especially when posting code here for our review. We will be able to better understand your code and help you if it conforms to standards (that's why standards exist). So try to keep your indentations consistent with all code lines that are in the same block indented at the same level, and you will want to be sure that base level code, including imports, outer class declarations and its end curly brace, is flush left:
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) throws Exception {
Set<Alpha> s = new HashSet<Alpha>();
Alpha a1 = new Alpha();
Alpha a2 = new Alpha();
s.add(a1);
s.add(a2);
System.out.println(s.size());
}
}
class Alpha {
int a = 10;
#Override
public int hashCode() {
return a;
}
public String toString() {
return "Alpha : " + a;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Alpha other = (Alpha) obj;
if (a != other.a)
return false;
return true;
}
}
For a beautiful review on this, please read: Overriding equals and hashCode in Java

The #Overrides annotation is to override the method with the same name in the super class".
#Override
public int hashCode() {
return a;
}
#Override
public boolean equals(Object obj) {
return (obj instanceof Alpha && ((Alpha) obj).a == this.a);
}
#Override
public String toString() {
return "Alpha : " + a;
}

your method hashcode should be named hashCode (capital letter "C").
If you plan on overriding methods you should use the #Override annotation.
If you had used that annotation, you'd have noticed the problem earlier as the code wouldn't have compiled.

Related

When trying to overwrite a equals method in Java, it won't compare the values only the object itself?

In this exercise, I need to create a equals() method for a Drink class. Two drinks are the same if they have the same name and same size. I am receiving false from testing the method, even though I'm certain it should be true.
The main code:
public class Drink {
private String name;
private double size;
public Drink(String name, double size)
{
this.name = name;
this.size = size;
}
public String getName()
{
return name;
}
public double getSize()
{
return size;
}
//I tried to stringify the double values
public boolean equals(Drink a, Drink b){
String q = String.valueOf(a.getSize());
String w = String.valueOf(b.getSize());
if(q.equals(w) && a.getName().equals(b.getName())){
return true;
}
else{
return false;
}
}
}
The tester Code:
public class DrinkTester
{
public static void main(String[] args)
{
Drink one = new Drink("Soda", 12);
Drink two = new Drink("Soda", 12);
Drink three = new Drink("Soda", 20);
System.out.println(one.equals(two));
System.out.println(one.equals(three));
}
}
You need to override the equals method, if you use the
#Override annotation you'll see if you're doing it right.
public boolean equals(Object obj) {
return (this == obj);
}
That is the Object one, so yours might for example look like:
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Drink drink = (Drink) obj;
return this.size.equals(drink.size)
&& this.name.equals(drink.name);
}
you'll also have to override your hashCode if you want your code to work optimally.
(And i've only recently noticed that if you use Objects.hash in your overridden hashCode method, your overridden equals method won't get used, the Objects one will get used instead)

Java Deep Comparison Returns False when Comparing a Deep Copy

I created an abstract class Fruit, which overrides the equals() method. Then I created a subclass, Orange, which overrides the copy() and the equals() method. In my test file, TestFruit.java, I am creating an array of oranges and testing their methods. I am trying to create a deep copy of orange and do a deep comparison between the parent orange and the copy. However, in my output, the comparison always returns false. I checked the parent and the copy's attributes and they do seem to be the same. Any pointers would be appreciated. I am pretty new to Java and copying. I attached my code below.
Fruit.java:
package juicer;
import copy.Copyable;
public abstract class Fruit implements Copyable, Cloneable
{
private double mass;
private boolean isJuicedRemoved;
protected Fruit(double theMass)
throws IllegalMassException
{
{
if (theMass <= 0)
{
throw new IllegalMassException(theMass);
}
else
{
this.mass = theMass;
this.isJuicedRemoved = false;
}
}
}
protected Fruit(Fruit fruit)
{
this.mass = fruit.mass;
this.isJuicedRemoved = fruit.isJuicedRemoved;
}
public double getMass()
{
return mass;
}
public boolean getIsJuicedExtracted()
{
return isJuicedRemoved;
}
protected void setMass(double value)
{
this.mass = value;
}
protected abstract double juiceRatio();
public double extractJuice()
{
double liquidMass = amountJuice();
if (!isJuicedRemoved)
{
isJuicedRemoved = true;
mass -= liquidMass;
}
return liquidMass;
}
public double amountJuice()
{
if (isJuicedRemoved) return 0.0;
return mass * juiceRatio();
}
#Override
public boolean equals(Object obj)
{
// Steps to override the equals() method():
// Step 1: Test if obj is an instance of Fruit.
// If it is not, then return false.
if (!(obj instanceof Fruit)) return false;
// Step 2: Cast obj to an Fruit.
Fruit rhs = (Fruit)obj;
// Step 3: Test if the data fields of the invoking object are
// equal to the ones in rhs using a deep comparison
// and return this result.
return super.equals(obj) && // test for equality in the super class
mass == rhs.mass &&
isJuicedRemoved == rhs.isJuicedRemoved;
}
#Override
public int hashCode()
{
int result = super.hashCode();
result = 31*result + Double.hashCode(mass);
result = 31*result + Boolean.hashCode(isJuicedRemoved);
return result;
}
#Override
public Object clone() throws CloneNotSupportedException
{
Fruit objectClone = (Fruit)super.clone();
objectClone.mass = mass;
objectClone.isJuicedRemoved = isJuicedRemoved;
return objectClone;
}
#Override
public String toString()
{
return "\tmass = " + mass +
"\n\tisJuiceExtracted = " + isJuicedRemoved + "\n";
}
}
Orange.java:
package juicer;
public class Orange extends Fruit
{
public Orange(double mass)
{
super(mass);
}
// copy constructor
public Orange(Orange other)
{
super(other);
}
#Override
protected double juiceRatio()
{
return 0.87;
}
#Override
public boolean equals(Object obj)
{
// Steps to override the equals() method():
// Step 1: Test if obj is an instance of Orange.
// If it is not, then return false.
if (!(obj instanceof Orange)) return false;
// Step 2: Cast obj to an Orange.
// This step is not needed since the only data fields this
// class has are the ones it inherits.
// Step 3: Test if the data fields of the invoking object are
// equal to the ones in rhs using a deep comparison
// and return this result.
return super.equals(obj);
}
#Override
public Object copy()
{
return new Orange(this);
}
#Override
public String toString()
{
return "Orange:\n" + super.toString();
}
}
TestFruit.java:
package test;
import juicer.*;
import java.util.Random;
public class TestFruit
{
public static void main(String[] args)
{
Orange[] oranges = new Orange[1];
//Random double generator for mass
Random rd = new Random();
//create oranges
for (int i = 0; i <= oranges.length - 1; i++ )
{
oranges[i] = new Orange(rd.nextDouble());
}
for (Orange orange : oranges)
{
Orange orangeCopy = new Orange(orange);
if (orange == orangeCopy)
{
System.out.print("The comparison is true!");
}
else
{
System.out.print("Does not match.");
}
}
}
}
One of the common misconceptions in Java is the use of == vs .equals(). When you use == to compare two objects in Java, internally it's comparing its memory address. == does not actually call .equals().
In this case, you have two distinct orange objects, so the comparison will always return false.
If you use a.equals(b), then it will actually invoke your equals method which you implemented.
As #Andreas pointed out in the comments, there's another issue. Calling super.equals(obj) in Fruit will call the superclass implementation of equals, and the superclass of Fruit is Object. Object.equals() behaves the same as == (i.e. also checking for reference equality). Overriding .equals() is not trivial, so it can often be nice to have the IDE generate it for you.
In contrast with a language like C++, Java does not have operator overloading. This means that you can't define a different implementation for ==. This is why it's best practice to always call .equals() when comparing any non-primitive types (unless you're explicitly checking reference equality, which is rare).

Comparing object in Java

Here is my application
public class testwithmain {
public static void main(String[]args)
{
Money m12CHF = new Money(12,"CHF");
System.out.println(m12CHF.amount());
Money m14CHF = new Money(14,"CHF");
System.out.println(m14CHF.amount());
Money expected = new Money(26,"CHF");
System.out.println("expected "+expected.amount()+expected.currency());
Money result = m12CHF.add(m14CHF);
System.out.println("result "+result.amount()+result.currency());
System.out.println(expected.equals(result));
}
}
//-------------------------
public class Money {
private int fAmount;
private String fCurrency;
public Money(int amount, String currency) {
fAmount = amount;
fCurrency = currency;
}
public int amount() {return fAmount;}
public String currency() {return fCurrency;}
public Money add(Money m) {
return new Money(amount() + m.amount(), currency());
}
}
The result is:
12
14
expected 26CHF
result 26CHF
false
Please, why i have false ?
Thank you so much.
Your Money class lacks an implementation of equals method, which is required in order for Java to know that the object representing the result of m12CHF.add(m14CHF) and the new Money(26,"CHF") represent the same thing, even though the two are distinct Java objects.
The code inside equals should follow this general template:
#Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Money)) {
return false;
}
Money other = (Money) o;
... // Your code goes here
}
#Override
public int hashCode() {
return Objects.hash(fAmount, fCurrency);
}
Your implementation needs to compare fAmount and fCurrency of your object to the values in other.fAmount and other.fCurrency. Use equals for comparison of String objects; numbers can be compared with == operators.
As Nexevis said you need to override the equals method (which is inherited from the object class)
#Override
public boolean equals(Object obj){
if(obj instanceof Money){
Money other = (Money)obj;
//now you define when two intance object of Money are equal...
}
//...
}
Why is this necessary?
Because the current equals that you are using it is the equals from the Object class. Object's equals method defines that two objects are the same when they have the same reference

overriding equals and hashCode in Collection

I am new in Collection, as per my knowledge I have already override the hashCode() and Equals() method in Data class, but when I trying to search the element it is giving "not found". Why? Please look at the code below aand help me to find the bug.
import java.util.*;
public class WordCounter {
public static void main(String args[]) {
HashSet<Data> set=new HashSet<Data>();
set.add(new Data("this",2));
set.add(new Data("that",3));
set.add(new Data("which",6));
set.add(new Data("how",7));
System.out.println(new Data("how",7).hashCode());
set.add(new Data("hey",3));
set.add(new Data("me",5));
Iterator<Data> itr=set.iterator();
while(itr.hasNext()) {
Data d=itr.next();
d.display();
}
Data e=new Data("how",7);
System.out.println(e.hashCode()+"\t");
if(set.contains(e))
System.out.println("found");
else
System.out.println("not found");
}
}
Data Class:
class Data {
String word;
int fre;
public Data(String w,int f) {
word=w;
fre=f;
}
public void display() {
System.out.println(word+"\t"+fre);
}
public boolean equals(Data e) {
return this.word.equals(e.word) && this.fre == e.fre;
}
public int hashCode() {
return this.word.hashCode() + this.fre;
}
}
Perhaps your equals method is not used?
The signature is
public boolean equals(Object obj);
And it appears you have
public boolean equals(Data e);
Consider adding #Overrideannotations when you want to override a parent method (in this case java.lang.Object)
Update
Changing your method to this solves the case.
public boolean equals(Object d) {
Data e = (Data) d;
return this.word.equals(e.word) && this.fre == e.fre;
}
You equals() method is not used, because it has wrong signature. The correct signature is public boolean equals(Object o){ /* ... */ }. Because the signatures don't match, you are effectively overloading the method instead of overriding. The working equals() example:
#Override
public boolean equals(Object e)
{
if(!(e instanceof Data)){
return false;
}
Data d = (Data)e;
return this.word.equals(d.word) && this.fre == d.fre;
}
When overriding a method, use the #Override annotation - then the code fails to compile if the signatures don't match, thus:
#Override
public boolean equals(Data d){ ... }
Will give you an error and save some debugging time. Also check out this question.

Does Collection's contain method ever return false for an instance added to it?

I was going through Joshua Bloch's online Chapter on "overridding equals() method".
Here's the link.
The following section confuses me,
Reflexivity—The first requirement says merely that an object must be
equal to itself. It is hard to imagine violating this requirement
unintentionally. If you were to violate it and then add an instance of
your class to a collection, the collection’s contains method would
almost certainly say that the collection did not contain the instance
that you just added.
Question - Is it possible for a collection's contain method to return false on an instance added to it?
I tried but the result returned is always true.
To illustrate the point, have this simple class:
class C {
private int i;
public C(int i) { this.i = i; }
}
Now, if you do:
C c1 = new C(1);
C c2 = new C(1);
List<C> l = new ArrayList<C>();
l.add(c1);
l.contains(c2) will return false, since c2.equals(c1) is false, in spite of the fact that both instances have the same constructor arguments.
This is because class C does not override .equals() nor .hashCode().
In general, each time your class is bound to be used in a Collection of any kind, you had better override both of these methods. In this case:
// Note: final class, final member -- that makes this class immutable
final class C {
private final int i;
public C(int i) { this.i = i; }
#Override
public int hashCode() { return i; }
#Override
public boolean equals(Object o)
{
// no object equals null
if (o == null)
return false;
// an object is always equal to itself
if (this == o)
return true;
// immutable class: if the class of the other is not the same,
// objects are not equal
if (getClass() != o.getClass())
return false;
// Both objects are of the same class: check their members
return i == ((C) o).i;
}
}
Question - Is it possible for a collection's contain method to return false on an instance added to it?
Not unless the added object's equals() violates the contract, as the quote from the book explains.
As suggested by #Karthik T, try this with an object whose equals() unconditionally returns false (thereby violating the contract).
Here is a demonstration of a collection's contains method returning false for an object that has just been added to the collection. I took a normal equals and hashCode, generated by Eclipse, and changed the equals method to be non-reflexive. Specifically, it returns false when comparing an object to itself.
import java.util.LinkedList;
import java.util.List;
public class Test {
int someValue;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + someValue;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
// Bad. Non-reflexive. Should return true.
return false;
}
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
if (someValue != other.someValue)
return false;
return true;
}
public static void main(String[] args) {
List<Test> myList = new LinkedList<Test>();
Test myObject = new Test();
myList.add(myObject);
System.out.println(myList.contains(myObject));
}
}

Categories