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