Not sure how to complete this equals method - java

Could someone help me with this question please? I've tried looking up other examples of this to find what I need to do and keep running into something called and EqualsBuilder, is that what I need to use? Do I need to have it call on equals again if it satisfies neither of the IFs?
The following code contains a class definition and an incomplete method definition. The equals method is used to compare Buildings.
It is intended to return true if Buildings have the same names and number of floors (but are not necessarily the same Building) and false otherwise.
public class Building {
private String name;
private int noOfFloors;
public boolean equals (Object rhs) {
if (this == rhs) {
return true;
}
if (!(rhs instanceof Building)) {
return false;
}
Building b = (Building) rhs;
// missing return statement
}
}

public boolean equals (Object rhs) {
if (this == rhs) {
return true;
}
if (!(rhs instanceof Building)) {
return false;
}
Building b = (Building) rhs;
// This is what you're supposed to add. It will return true only if both
// object's attributes (name and number of floors) are the same
return this.name.equals(b.name) && this.noOfFloors == b.noOfFloors;
}

The only thing that you have to test for now is the fields of both objects. If they are equal, then you should return true, if at least one of them is not then you should return false.
Since your fields in that case are int and Stringyou can use == for the integer field and .equals() for the String field.
Something like this should do the job just fine:
if(this.name.equals(b.name) && this.noOfFloors == b.noOfFloors){
return true ;
}
else{
return false;
}

After the instanceOf tests you want to compare the fields of the object to the other object. Something like Objects.deepEquals() should do the trick for you nicely.

Related

Collection.contains yields wrong result

I've got an object which has got a couple of fields -- as you can see the hashcode and equals method is implemented just taking the id in account:
public class SpotResponse{
String id;
// bla bla other fields
public SpotResponse() {
}
public SpotResponse(#NonNull String id) {
this.id = id;
}
public String getId() {
return id;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SpotResponse that = (SpotResponse) o;
return id == that.id;
}
#Override
public int hashCode() {
return id.hashCode();
}
}
I've got a method which checks if a Collection<SpotResponse> newSpots
contains some oldSpots from a HashMap<String, SpotResponse> spots = new HashMap<>();
If I do this:
List<String> newKeys = new ArrayList<>();
for (SpotResponse response : newSpots) {
newKeys.add(response.getId());
}
for (SpotResponse oldSpot : spots.values()) {
if (newKeys.contains(oldSpot.getId())) {
continue;
}
/* blabla */
}
newKeys.contains() returns true properly, but if instead I do
newSpots.contains(oldSpot)
It always returns false. In this case, the Collection is an ArrayList (if this is of any help)
Your bug is in your equals implementation, on this line:
return id == that.id;
You're comparing two Strings (namely id and that.id) with ==, when you should use id.equals(that.id).
You have to be careful when using Contains with Primitives.
String is technically an object class wrapping a primitive of chars, but when you are comparing it, it is not comparing the literal object memory pointer, it is comparing the value at the memory pointer.
Contains is using .equals under the hood, so when overriding equals in your class you can't default back to the == comparison as that compares address and not necessarily value.
Hope that helps.

Comparing An Entry In A Map With An Object

I have a Map in Java like so,
private HashMap<String, Object[][]> theMap;
Where the key is a String and the entry is going to be something along the line of,
theMap = new HashMap<>();
Object[][] theData = {
{Boolean.FALSE, "Text"}
};
theMap.put("Key1", theData);
Somewhere along the line I would like to check if an entry in the map is equivalent to another object. Currently I am doing it like this,
Object[][] tempData = {
{Boolean.FALSE, "Text"}
};
for(Object key: entries.keySet()) {
if(entries.get(key).equals(tempData)) {
entries.remove(key);
}
}
And it is not working.
I would prefer the comparison to be done with an object rather than with another map. I'm wondering what I'm doing wrong with this comparison here?
The reason you are not getting equality is that arrays inherit Object#equals() which is based on identity, not equality of contents. You could consider using java.util.Arrays.deepEquals(Object[], Object[]) to compare.
That is the answer to the immediate question. However, using a 2-dimensional array of Object to hold a boolean and a String is really bad code smell and indicates you need to encapsulate what you are putting in the array.
Identity vs Equivalence
Please make sure that you understand that by default the equals() method of Object checks on whether two object references are referring to the same object (identity), which is not what your code is checking.
Instead, your code is checking whether the two objects (the values you put on the map) are having the same value (equivalence).
Here are two articles about this topic:
What is the difference between identity and equality in OOP?
Overriding equals method in Java
In this particular problem of yours, I think the solution involves two steps:
Your tempData and theData does not seems to be an array
of elements of the same type (it does not appear to be a 2-dimensional
array either). Instead, it contains a Boolean value and then a
String value. In this case, I think you really should think
through what this thingy is and design a class for it (I am showing
an example below)
The class should override the equals() (and hashCode()) methods
so that you can use its equals() for equivalence checking.
Note also that your IDE (e.g. Eclipse) probably can generate a template for equals() and hashCode() for you.
Example: (here I assume your Boolean represents a condition, and your String represents a message)
class MyRecord {
private Boolean condition;
private String message;
public Boolean getCondition() {
return condition;
}
public void setCondition(Boolean condition) {
this.condition = condition;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((condition == null) ? 0 : condition.hashCode());
result = prime * result
+ ((message == null) ? 0 : message.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;
MyRecord other = (MyRecord) obj;
if (condition == null) {
if (other.condition != null)
return false;
} else if (!condition.equals(other.condition))
return false;
if (message == null) {
if (other.message != null)
return false;
} else if (!message.equals(other.message))
return false;
return true;
}
}

How can I get the return value of a superclass method without executing it?

This is my superclass equals() method:
public boolean equals(Object other){
Car c = (Car)other;
if(this.make.equals(c.make) && this.model.equals(c.model)){
System.out.println("True, Cars are equal");
return true;
}
else
System.out.println("False, Cars are not equal");
return false;
}
Here is my subclass equals() method:
public boolean equals(Object other) {
GreenCar g = (GreenCar) other;
if(super.equals(g)==true){
if (this.type.equals(g.type)) {
System.out.println("True, Cars are equal");
return true;
} else {
System.out.println("False, Cars are not equal");
return false;
}
}
else
System.out.println("False, Cars are not equal");
return false;
}
When it runs the check at if(super.equals(g)==true){ it executes the method and prints out true or false. How can I just check the return value?
You cannot run the method without letting it print anything.
This is why most of your methods should not have "side effects" (like printing things to the screen).
Remove the println calls from both equals methods. Add them to the code that calls equals instead.
In your super class, you could write something like
protected boolean equals(Object other, boolean debug) {
if (other instanceof Car) {
Car c = (Car) other;
if (this.make.equals(c.make) && this.model.equals(c.model)) {
if (debug) {
System.out.println("True, Cars are equal");
}
return true;
}
}
if (debug) {
System.out.println("False, Cars are not equal");
}
return false;
}
then you can modify your equals() method (still in the super class) like
public boolean equals(Object other) {
return equals(other, true); // <-- default to debug.
}
next your subclass should call the version that takes the debug flag like
if (super.equals(g, false)) { // you don't need == true
Alternatively, you might use a Logger and enable and disable debug on demand.
Like people have said you need to take out those println's if you want it to not print something when you call it, because every time you call the method it will print.
Just as a note you can shorten some of your methods by taking out those elses since it will have returned before getting to the next body of code if the conditional was true. For example
public boolean equals(Object other){
Car c = (Car)other;
if(this.make.equals(c.make) && this.model.equals(c.model))//if this is true
return true;//the method ends here
return false;//if the method hasn't ended yet then the conditional must be false
}
Also I noticed that you used if(super.equals(g)==true) but if you just put if(super.equals(g)) it has the same effect since you are putting in a boolean and it checks if the boolean is true or not. If you want to have the effect of if((boolean)==false) you can do if(!(boolean)) because it checks if the opposite of that boolean is true.

Comparing two collections using hamcrest contains() method

I have two collections which I am trying to compare for equality in my unit tests, but I am struggling with the contains method. Here is what I have:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(expectedItems, contains(actualItems));
}
items contains the same objects as expectedItems so I would expect the assertion to be true but this is the output I get:
[Item{name=iPhone}, Item{name=Skateboard}] --> Expected
[Item{name=iPhone}, Item{name=Skateboard}] --> Actual
java.lang.AssertionError:
Expected: iterable containing [<[Item{name=iPhone}, Item{name=Skateboard}]>]
but: item 0: was <Item{name=iPhone}>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
Please can you help me where I am going wrong with using the contains method?
public class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return Objects.toStringHelper(this).add("name", name).toString();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.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;
Item other = (Item) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
A Collection's .contains(...) uses the equals and hashCode methods of the Objects. In order to use equals (or in this case contains) on your own Objects, you need to override the equals and hashCode methods of your class. This is because Java uses references behind the scenes, so even though the field may be equal, the Object-references are not.
In Eclipse you can generate them using right-mouse click -> Source -> Generate hashCode() and equals().... But, since you never stated you use Eclipse, here is an example of the methods that are generated:
// Overriding this class' equals and hashCode methods for Object comparing purposes
// using the Collection's contains
// contains does the following behind the scenes: Check if both inputs aren't null,
// check if the HashCodes match, check if the Objects are equal.
// Therefore to use the Collection's contains for Objects with the same fields, we
// need to override the Object's equals and hashCode methods
// These methods below are generated by Eclipse itself using "Source -> Generate
// hashCode() and equals()..."
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.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;
Item other = (Item) obj;
if(name == null){
if(other.name != null)
return false;
}
else if(!name.equals(other.name))
return false;
return true;
}
If you add both of these to your Item-class, the contains will work.
EDIT:
I'm not sure, but when I look at your code I think the following might be wrong:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
// You first print both lists
System.out.println(expectedItems);
System.out.println(items);
// And then add the two items to the expectedItems
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(expectedItems, contains(actualItems));
}
If you try the following instead:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
// First add both items
expectedItems.add(iPhone);
expectedItems.add(skateboard);
// Then print both lists
System.out.println(expectedItems);
System.out.println(items);
assertThat(expectedItems, contains(actualItems));
}
Does the expectedList now contain 4 items?
[Item{name=iPhone}, Item{name=Skateboard}, Item{name=iPhone}, Item{name=Skateboard}] --> Expected
[Item{name=iPhone}, Item{name=Skateboard}] --> Actual
In that case you shouldn't add the two items, since they are already present in the list.
Also, you're trying to use the contains on the entire list. Normally the contains is used to see if a single item is present in the list. So you could either use something like this:
for(Item i : expectedList){
assertTrue(actualList.contains(i));
}
or perhaps something like this, in case you use these libraries:
assertThat(actualList, is(expectedList));
I'm not sure if this is the cause and if this will fix it, since you use a different JUnit library then I usually do and I'm not sure if these syntax with the Asserts are possible.
I really don't think you actually need hamcrest for this. Wouldn't it be easier to make the asserts in one of the following ways:
A list is still an object at the end of the day:
org.junit.Assert.assertEquals(expected, actual)
An old fashion functionality for lists by using containsAll(..):
org.junit.Assert.assertTrue(expectedItems.containsAll(actualItems))
Using asserts for arrays' equality:
org.junit.Assert.assertArrayEquals(expectedItems.toArray(), actualItems.toArray())
Of course you can use hamcrest as well:
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.containsInAnyOrder(actual.toArray()));
OR
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.contains(actual.toArray()));
You basically asserting that expectedItems is a list with one element and this element is expected to be a list itself with the two items iPhone and skateboard.
To assert that expectedItems and actualItems have the same elements in the same order try this:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
assertThat(actualItems, contains(iPhone, skateboard));
}
And beware that assertThat expects the "actual" object as first parameter and not the "expected".
Alternatively you can do something like that:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(actualItems, contains(expectedItems.toArray(new Item[expectedItems.size()])));
}

public boolean equals(Object other)

This is for a Fraction program. I have private ints num and den, Fraction, and FractionInterface - the standard homework problem. I have done pretty much everything and now have been stuck for a few hours on the equals method. Since other is an Object, I can't equate it to Fraction. Here's what I have:
public boolean equals(Object other){
if (other == this){
return true;
} else {
return false;
}
}
This compiles but it gives incorrect results:
1/2 eq 1/2 = true
1/2 eq 1/2 = true
1/2 eq 1/2 = false
1/2 eq 1/2 = false
If I try other == Fraction, it doesn't compile. Thanks for any help!
You can test if other is an instance of FractionInterface and use a cast:
public boolean equals(Object other){
if (other == this){
return true;
} else if (other instanceof FractionInterface) {
FractionInterface fOther = (FractionInterface) other;
// compare numerator and denominator...
} else {
return false;
}
}
Note that instanceof will be false if other == null, so there's no need for a separate null check.
Try this out:
First, cast the other object
Fraction otherFraction = (Fraction) other;
Then, determine the condition that the two fractions are equivalent.
This will include some logic involving the comparing of numerator and denominators (expect to use getNum() and getDen() for the otherFraction.
You should check whether the argument is an instance of your class and return false if it isn't and cast it to your class and compare according to your needs if it is. It's common to write equals() method like this:
public boolean equals(Object obj) {
if (!(obj instanceof Fraction)) {
return false;
}
Fraction that = (Fraction) obj;
... // Your algorithm to compare two fractions: this and that.
}
You should make sure that your algorithm for comparing two fractions meets all the requirements described in equals() documentation.
You need to test if the object has the Fraction class, and if so, cast it to a Fraction:
if (other.getClass() != Fraction.class) {
return false;
}
Fraction otherFraction = (Fraction) other;
// compare the fields of this and otherFraction
Before doing this, make sure to also test for null.
You are comparing that the two objects references refer to the same object.
You will need to check that the other is of type Fraction and then type cast it to a Fraction. You are then about to compare the two parts of the Fraction.
I think you're close, but you're missing a few key concepts. This is because your as is won't work in all situations. Try this for example using your existing code...
Fraction a = // this is however you're making a fraction object...
Fraction b = // do EXACT same thing here that you did for a
// And then, this will illustrate what is wrong with your program...
if(a.equals(b)) {
System.out.println("This won't print");
} else {
System.out.println("This will print because your method just checks for reference");
}
So here are the basics you need to understand:
Difference between == and equals
Comparing type as opposed to reference or value
Avoiding casting by putting your "equals" method in the proper place
First off...
public boolean equals(Object other){
if (other == this){
return true;
} else {
return false;
}
}
You're missing the point of the "equals" method in Java. == is used to compare references while this.equals(foo) is used to put the logic for comparing objects in a localized place.
The other concept you're missing is how instanceof should be used. When you ask this...
If I try other == Fraction, it doesn't compile.
This is because you're looking to compare the type of the object. To do this, you would simply do...
if(other instanceOf Fraction) {
// do stuff...
}
All of that being said, there is one last concept, which is putting the equals definition in the proper place. You need to put it inside your Fraction class and define it like this...
public boolean equals(Fraction other) {
// do something like this (you will have to define toDouble)
if(this == other || this.toDouble() == other.toDouble()) {
return true;
}
return false;
}
This will override the default...
public boolean equals(Object other) {/* ... */}
And it will make it EXTREMELY convenient. Here is some sample code of how...
Fraction fractionA = new Fraction("2/4");
Fraction fractionB = new Fraction("1/2");
Fraction fractionC = new Fraction("1/3");
Object trollObject = new Object();
// And then call random equals objects...
if(fractionA.equals(fractionB)) {
// should be true...
}
if(fractionB.equals(fractionA)) {
// should be true...
}
// This avoids having to do any casting because
// since you've only defined a Fraction.equals(Fraction) method
// it should instead default to the Object.equals method
if(trollObject.equals(fractionB)) {
}
Here's a quite standard pattern:
public boolean equals(Object other) {
if (other == this) return true;
if (other == null) return false;
if (other.getClass() != this.getClass()) return false;
Fraction o = (Fraction) other;
// now you compare their num, den, and possibly sign
}
People may argue if we should use getClass() or instanceof. It matters only if Fraction is extended, and it depends on what you want if it is extended. Just keep in mind a contract of equals() is a.equals(b) should get the same result as b.equals(a) if neither one is null, and a subclass may have a different equals() that potentially breaks the contract.
== operator compares hash codes of objects. That is reason why your method is not ok, you should write it like this :
public boolean equals(Object other){
if (other instanceof Fraction){
return ((Fraction)other).getNum == this.num && ((Fraction)other).getDen == this.den;
} else {
return false;
}
}
I hope that it will helpful to you .try this code.
import java.io.*;
class Cast
{
public static void main(String args[]) throws IOException
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
byte a=20;
short s=31468;
int i=12345678;
char c=’c';
float f=3.56f;
//Widening or promotion [java question bank][1]
System.out.println(“a=(short) “+(short) a);
System.out.println(“a=(int) “+(int) a);
System.out.println(“a=(long) “+(long)a);
System.out.println(“a=(float) “+(float)a);
System.out.println();
System.out.println();
System.out.println(“s=(int) “+(int)s);
System.out.println(“s=(long) “+(long)s);
System.out.println(“s=(float) “+(float)s);
System.out.println();
System.out.println();
System.out.println(“i=(long) “+(long)i);
System.out.println(“i=(float) “+(float)i);
System.out.println(“i=(double) “+(double)i);
//Narrowing using [java question bank][2]
System.out.println(“f=(byte) “+(byte)f);
System.out.println(“f=(short) “+(short)f);
System.out.println(“f=(char) “+(char)f);
System.out.println(“f=(long) “+(long)f);
System.out.println();
System.out.println();
System.out.println(“i=(byte) “+(byte)i);
System.out.println(“i=(short) “+(short)i);
System.out.println();
System.out.println();
System.out.println(“s=(byte) “+(byte)s);
}
}

Categories

Resources