overriding equals and hashCode in Collection - java

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.

Related

contains() with Generic Type

I need to convert the method "contains()"
public boolean contains(List<Integer> list, int value){
for (int i : list) {
if(i == value)
return true;
into a method that can search for every datatype but i dont really know how to do it.
import java.util.List;
public class Search<T> {
public boolean contains(List<T> list, T value){
for ( T i : list) {
if(i == value)
return true;
}
return false;
}
}
This is my attempt so far but i dont know if this is all i have to do or not.
I hope someone can help me out.
There is already a method in List<T> that does that, List<T>::contains.
If you want to implement your own there are two ways to do it:
Same instance:
Here if the equals method hasn't been overridden it will return true if they are literally the same instance in memory.
public <T> boolean contains(List<T> list, T object){
for( T t : list){
if(t.equals(object))
return true;
}
return false;
}
Similar objects
Here you are forcing your T class to implement the Comparable interface, which contains a compareTo(o : Object) that returns 0 if they are similar.
public <T extends Comparable> boolean contains(List<T> list, T object){
for( T t : list){
if(t.compareTo(object) == 0)
return true;
}
return false;
}
Try equals instead of ==
import java.util.List;
public class Search<T> {
public boolean contains(List<T> list, T value){
for ( T i : list) {
if(i.equals(value))
return true;
}
return false;
}
}

why below code returning set size as 5? even though hashcode and equals method is overridden it should return set size as 3

//why output of this code is 5 instead of 3
//why output of this code is 5 instead of 3
//why output of this code is 5 instead of 3//why output of this code is 5 instead of 3
public class Dummy {
public static void main(String[] args) {
Set set = new HashSet();
set.add(new Student("abc"));
set.add(new Student("abcd"));
set.add(new Student("abc"));
set.add(new Student("abc"));
set.add(new Student("abcdef"));
System.out.println(set.size());
}
}
class Student
{
private String age;
public Student(String age)
{
this.age=age;
}
public boolean equals(Student stu)
{
System.out.println("equals from Student parameter called");
return false;
}
public boolean equals(Object obj)
{
System.out.println("equals from Object parameter called");
return true;
}
public int hashcode()
{
System.out.println("hashcode called");
return 17;
}
}
It's not supposed to be public int hashcode(), it's public int hashCode(), so you've only overridden equals(). There may still be "equal" (based on your implementation) objects in different buckets since they don't all get same hash.
The #Override annotation is very helpful in these kinds of cases.

Trouble with assertEquals (Java)

I'm trying to make a game of "Rock, papers, scissors". I have tests like these:
#Test
public void rockBeatsScissors() {
assertEquals(rock, rock.vs(scissors));
}
I think it should be enough to write a function Equals, for example:
public class Rock {
Object vs(Scissors s) {
return new Rock();
}
Object vs(Paper p) {
return new Paper();
}
Object vs(Rock r) {
return new Rock();
}
boolean equals(Rock r) {
return true;
}
boolean equals(Paper p) {
return false;
}
boolean equals(Scissors s) {
return false;
}
}
(I know I should add a HashCode function, by the way)
I run the tests and I only get failures. What am I doing wrong?
The equals() method used by assertEquals() would be the one which takes Object as argument. Right now, you haven't overridden the Object#equals() method, but provided your own set of 3 equals method, which wouldn't even be used, and thus the default Object class method is used, which just does reference comparison.
You've to give following implementation:
/**
* Terrible `equals()` method implementation. Just for demonstration purpose.
*/
#Override
public boolean equals(Object obj) {
return obj instanceof Rock;
}

Why does contains value return false?

Please don't mind the my convention mistakes
class test implements Comparable<test>
{
int id;
String name;
public test(int id,String name)
{
this.id=id;
this.name=name;
}
#Override
public int compareTo(test o) {
if(this.id>o.id)
return 1;
else if(this.id==o.id)
return 0;
else
return -1;
}
}
class le
{
public static void main(String[] args) {
TreeMap<test,test> p=new TreeMap<test,test>();
p.put(new test(1,"sad"), new test(3121, "adweq"));
p.put(new test(2, "asds"),new test(3123,"awdq"));
p.put(new test(23,"akjdb"),new test(23123,"dqWQDD"));
Set<Map.Entry<test,test>> s=p.entrySet();
Iterator <Map.Entry<test, test>> i=s.iterator();
while(i.hasNext())
{
Map.Entry<test, test> m=i.next();
System.out.println(m.getKey().id);
System.out.println(m.getValue().name);
}
System.out.println(p.containsKey(new test(1,"sad")));//returning true
System.out.println(p.containsValue(new test(3123,"awdq")));//why it is returning false
}
}
here i have made a treemap,and wanted to know why does in containsvalue method it return false? whereas i have implemented comparable interface>
a compareTo() method is not enough - you need to implement an equals() method (and is recommended to also override hashCode() when you override equals()). Here's how:
class test implements Comparable<test>
{
int id;
String name;
public test(int id,String name)
{
this.id=id;
this.name=name;
}
#Override
public int compareTo(test o) {
if(this.id>o.id)
return 1;
else if(this.id==o.id)
return 0;
else
return -1;
}
#Override
public boolean equals(Object o) {
if (o == null)
return false;
if(!this.getClass().equals(o.getClass())
return false;
test that = (test) o;
return this.compareTo(that) == 0;
}
#Override
public int hashCode() { return id; }
}
Side note
Why does equals() use getClass().equals(o.getClass()) rather than (o instanceof test)?
Let us assume there is a subclass of the test class called test2 and that t1 and t2 are objects of type test, test2 (respectively).
If test2 overrides equals() then t1.equals(t2) can yield different result than t2.equals(t1) if equals() in test were implemented using instanceof. This violates the equals() contract (specifically, the symmetric requirement).
Because your class test doesn't override equals() and hashCode(), something like
#Override
public boolean equals(Object o) {
if (o instanceof test) {
test t = (test) o;
return t.id == o.id;
}
return false;
}
#Override
public int hashCode() {
return Integer.valueOf(id).hashCode();
}
Assuming that id equality is sufficient. Additionally, test is a poor class name. The Java naming convention would be Test but that's also a poor name. Maybe, EqualityTest (so it has some meaning).
You need to override Object.equals in your Test class in order to check for equality between new test(3123,"awdq") and another instance of new test(3123,"awdq").
It is also recommended to override Object.hashCode when overriding equals.

Java: Duplicate objects getting added to set?

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.

Categories