Equals method in sub classes - java

Here is the main class.
public class Person {
private String name;
public Person() {
name = "";
}
Its equal method is this
public boolean equals(Object otherObject) {
boolean isEqual = false;
if(otherObject != null && otherObject instanceof Person) {
Person otherPerson = (Person) otherObject;
if(this.name.equals(otherPerson.name))
isEqual = true;
}
return isEqual;
}
I have a subclass that extends the Person class.
public class Student extends Person {
private int studentNumber;
public Student() {
super();
studentNumber = 0;
}
How would I go about writing its equal method that will compare two object of type Student and will compare both variables. Name and studentNumber.
So far i have it similar to the Person class.
public boolean equals(Object otherObject) {
boolean isEqual = false;
if(otherObject != null && otherObject instanceof Student) {
Student otherPerson = (Student) otherObject;
if(this.studentnumber.equals(otherPerson.studentnumber))
isEqual = true;
}
return isEqual;
}

First of all: you need not test for null if you test instanceof; null is not instanceof anything. So, equals() for method can be simplified to:
public boolean equals(final Object obj)
{
if (!(o instanceOf Person))
return false;
final Person other = (Person) obj;
return name.equals(other.name);
}
THis means that in your Student class you may write your equals() method like this:
public boolean equals(final Object obj)
{
if (!super.equals(obj))
return false;
if (!(obj instanceof Student))
return false;
return studentnumber == other.studentnumber;
}
Note: do not forget hashCode().

You can use super.equals(). I have corrected some errors also with the studentNumber comparision.
public boolean equals(Object otherObject) {
boolean isEqual = false;
if (otherObject != null && otherObject instanceof Student) {
Student otherPerson = (Student) otherObject;
if (super.equals(otherObject) && this.studentNumber == otherPerson.studentNumber) {
isEqual = true;
}
}
return isEqual;
}

Related

Need to write a equals-method to check if a book is the same as another book but one book contains multiple values

Below is my code at this moment, I need to add to the equals method so when I create a two books they will only be equal if both of the attributes are the same. Hopefully you guys can help.
public class Book {
private String title;
private boolean bound;
Book(String title, boolean bound) {
this.title = title;
this.bound = bound;
}
#Override
public boolean equals(Object obj) {
if ((obj instanceof Book)) {
return true;
}
return false;
}
}
The correct implementation would be:
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(!(obj instanceof Book))
return false;
Book other = (Book) obj;
return bound == other.bound && Objects.equals(title, other.title);
}
Both object properties are respected!
** Update **
To avoid using instanceof you should use
if(this.getClass() != obj.getClass())
return false;
Thanks user16320675 for the hint!
You are almost there. However, the instanceof will always be true here if you are actually comparing to books. The below should work.
class Book {
private String title;
private boolean bound;
public Book(String title, boolean bound) {
this.title = title;
this.bound = bound;
}
public String getTitle(){
return this.title;
}
public boolean isBound(){
return this.bound;
}
#Override
public boolean equals(Obj obj) {
if(!(obj instanceof Book)){
return false;
}
if (((Book) obj).isBound() == this.isBound() && ((Book) obj).getTitle().equals(this.getTitle())) {
return true;
}
return false;
}
}
Now you can compare two books.
Book b1 = new Book(new String("Title1"), true);
Book b2 = new Book(new String("Title2"), true);
Book b3 = new Book(new String("Title1"), true);
System.out.println(b1.equals(b2)); // Output is false
System.out.println(b1.equals(b3)); // Output is true

Java - How to check if two objects, from the same abstract class, are equal

I'm writing a program which contains an abstract class of 'Book', and I have two classes ('LearnBook' and 'ReadingBook') which inherit from 'Book'.
Book:
Public abstract class Book {
protected String name;
protected String author;
LearningBook:
public class LearningBook extends Book {
private String subject;
ReadingBook:
public class ReadingBook extends Book {
private int numberOfPages;
At the main class I have Book array which can include any instance of Book.
I want to add a method which checks if two Book objects are exactly the same, to prevent duplicating in the Book array. it looks like this:
public boolean sameBookCheck(Book book1, Book book2)
So my first idea was to write an isEqual() method in the Book class, which checks if the "name" and the "author" are equals.
But then I need to check if it's a learning book or reading book so I could know if I need to compare the "subject" value or the "numberOfPage" value.
I have no idea how to do it and I'd appreciate your help.
You can use the following design:
In Book abstract class have an equals() function and check whether the other object is of type Book and have same values in all fields.
In LearningBook and ReadingBook have equals() function which first checks whether the other object is of same class, then call Book's equals() function, checking the fields of abstract class, and then check whether field(s) of current class have same values or not.
Have a look at the code:
abstract class Book {
protected String name;
protected String author;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((author == null) ? 0 : author.hashCode());
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 (!(obj instanceof Book))
return false;
Book other = (Book) obj;
if (author == null) {
if (other.author != null)
return false;
} else if (!author.equals(other.author))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
class LearningBook extends Book{
private String subject;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
#Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((subject == null) ? 0 : subject.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (!(obj instanceof LearningBook))
return false;
LearningBook other = (LearningBook) obj;
if (subject == null) {
if (other.subject != null)
return false;
} else if (!subject.equals(other.subject))
return false;
return true;
}
}
class ReadingBook extends Book{
private int numberOfPages;
public int getNumberOfPages() {
return numberOfPages;
}
public void setNumberOfPages(int numberOfPages) {
this.numberOfPages = numberOfPages;
}
#Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + numberOfPages;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (!(obj instanceof ReadingBook))
return false;
ReadingBook other = (ReadingBook) obj;
if (numberOfPages != other.numberOfPages)
return false;
return true;
}
}
public class Runner {
public static void main(String[] args) {
Book learningBook = new LearningBook();
learningBook.setAuthor("auth");
learningBook.setName("sci");
Book learningBook2 = new LearningBook();
learningBook2.setAuthor("auth");
learningBook2.setName("sci");
Book readingBook = new ReadingBook();
readingBook.setAuthor("auth");
readingBook.setName("sci");
//returns false
System.out.println(learningBook.equals(readingBook) );
//returns true
System.out.println(learningBook.equals(learningBook2) );
}
}
Write an equals-implementation for each of the three classes. Every implementation is only responsible for its own fields.
The equals-implementations from the sub-classes ReadingBook and LearningBook should somewhere call super.equals() - the equals-implementation of Book.
You can ask the book instance for its class and check class equality.
book1.getClass().equals(book2.getClass())
You can use instanceof method to compare the type of the Object. To check if it is a type of LearningBook or ReadingBook example
Answer for your comment,
Lets say when you check the two instance it says they are different, then there is no issue you can return false. But if the instances are also same then you can check it with something like this after that
if (both instances are same) {
if (yourObjectIs instanceof LearningBook) {
you can check the two values of LearningBook here and return true if the are equals
} else {
you can check the two values of ReadingBook here and return true if the are equals
}
}
As it was mentioned you should overwrite equals(Object object) method. In your example you can do it like this:
public abstract class Book{
#NonNull protected String name;
#NonNull protected String author;
public Book(String name, String author) {
this.name = name;
this.author = author;
}
#Override
public boolean equals(Object object) {
if (object instanceof Book) {
var book = (Book) object;
return this.name.equals(book.name) && this.author.equals(book.author);
} else
return false;
}
}
public class LearningBook extends Book{
#NonNull private String subject;
public LearningBook(String name, String author,String subject) {
super(name, author);
this.subject = subject;
}
#Override
public boolean equals(Object object) {
if (object instanceof LearningBook) {
var book = (LearningBook) object;
return this.subject.equals(book.subject) && super.equals(book);
} else
return false;
}
}
public class ReadingBook extends Book{
#NonNull private int numberOfPages;
public ReadingBook(String name, String author,int numberOfPages) {
super(name, author);
this.numberOfPages = numberOfPages;
}
#Override
public boolean equals(Object object) {
if (object instanceof ReadingBook) {
var book = (ReadingBook) object;
return super.equals(book) && this.numberOfPages == book.numberOfPages;
} else
return false;
}
}
I've used #NonNull annotation to avoid NPE in equals method.

Using Objects as keys in Java HashMap

package test;
import java.util.HashMap;
public class test {
public static void main(String args[]) {
HashMap<ID, String> h = new HashMap<ID, String> ();
String b;
ID id1 = new ID(100);
ID id2 = new ID(200);
ID id3 = new ID(200);
h.put(id1, "apple");
h.put(id2, "pear");
**System.out.println(h.containsKey(id3));**
}
}
class ID {
Integer code;
public ID(Integer id) {
this.code = id;
}
#Override
public int hashCode()
{
return code.hashCode();
}
#Override
public boolean equals(Object o)
{
return this.code.equals(o);
}
}
the output of this program is "false". I can't understand of this result. I implemented hashCode and equals which are overrided. I don't have an idea how to solve. How to use objects as keys in java HashMap?
Your equals implementation is wrong :
public boolean equals(Object o)
{
return this.code.equals(o); // this will never return true,
// since you are comparing an Integer instance
// to an ID instance
}
You should compare this code to the other code:
public boolean equals(Object o)
{
if (!(o instanceof ID))
return false;
ID oid = (ID) o;
return this.code.equals(oid.code);
}
Wrong Implementation of equals method. According to your implementation it executes the Integer class equals method. We should handle the logic without execute library classes equals methods.
#Override
public boolean equals(Object o) {
if (o == null || ((o instanceof ID) && o.hashCode() != this.hashCode())) {
return false;
}
return true;
}

== vs. equals() references/pointers JAVA

I'm learning about == vs. equals() and doing various examples. For this one, I understand why r==s is false, but why is r.equals(s) false if they now both have the same content?
public class StringProgram{
public static void main(String[] args) {
Person r = new Person("A");
Person s = new Person("J");
s.setName("A");
System.out.println(r.getName());//A
System.out.println(s.getName());//A
System.out.println(r==s);//false
System.out.println(r.equals(s));//false
}
}
Here is the code of Person :
public class Person{
private String name;
public Person(String d){
name=d;
}
public void setName(String a){
name=a;
}
public String getName(){
return name;
}
}
EDIT: I see that I have to override it now, but I still don't understand how the assignment works in the example below. I just don't understand why t.getName() is Keen if t is assigned to u.
public class StringProgram{
public static void main(String[] args) {
Person t = new Person("Gene");
Person u = t;
u.setName("Keen");
System.out.println(t.getName());//Keen
System.out.println(t.equals(u));//true
}
}
All classes in java inherit from the Object class. When you do an r.equals(s), it uses the .equals() method as defined in Object class. To make it work as you desire, you need to define the .equals() method for the Person class by overriding the .equals() method.
Eg. Add this in your Person class:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
Note: I used eclipse to generate the equals and hashcode method for me. You may read this thread to understand why hashcode() needs to be overridden.
equals() is just a method, there's nothing special about it. In particular, it doesn't automatically know how to compare the content of two objects.
The equals() method of class Object does the same thing as ==. If you do not override the equals() method in your class Person, then it's not automatically going to compare the content of Person objects.
You have to override the equals() method in class Person so that it does the comparison in the way you want.
public class Person {
private String name;
// ...
#Override
public boolean equals(Object o) {
if (!(o instanceof Person)) {
return false;
}
return ((Person) o).name.equals(this.name);
}
}
Java can't guess what you want to do, you have to tell it that two persons are the same if they have the same name. You must override equals :
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (o == null) return false;
if (!(o instanceof Person)) return false;
Person that = (Person) o;
if (name == null && that.name == null) return true;
if (name == null || that.name == null) return false;
return that.name.equals(name);
}
All java classes inherits from Object, and to properly compare your class you should override the equals() method.
public Person(String d){
name=d;
}
public void setName(String a){
name=a;
}
public String getName(){
return name;
}
#Override
public boolean equals(Object obj) {
return obj instanceof Person &&
this.getName().equals(((Person)obj).getName());
}

hashCode(), equals(Object) and compareTo(Class)

I've following the following Vertex class and it implements equals, hashCode and compareTo method. Even then my HashMap returns null. I don't know why?
public class Vertex implements Comparable<Vertex> {
int id;
public Vertex(int number) {
id = number;
}
public boolean equals(Object other) {
if (other == null)
return false;
else if (other.getClass() != this.getClass())
return false;
else {
Vertex copy = (Vertex) other;
if (copy.id == this.id)
return true;
else
return false;
}
}
public int hasCode() {
int prime = 31;
int smallPrime = 3;
int hashCode = this.id ^ smallPrime - prime * this.hasCode();
return hashCode;
}
public int compareTo(Vertex other) {
if (this.id < other.id)
return -1;
else if (this.id > other.id)
return 1;
else
return 0;
}
}
Your method is called hasCode(). Make it hashCode() instead.
I'd suggest using your IDE to automatically generate hashCode() and equals(..). That will generate the proper methods (right now you have a recursive call in hashCode())
Also, in your equals() method
else if(other.getClass()!=this.getClass())
return false;
can be changed to
else if(!(other instanceof Vertex))
return false;
Try this based on what Integer does. Note: the use of #Override would have shown you were overriding the wrong method.
public class Vertex {
final int id;
public Vertex(int number){
id = number;
}
#Override
public boolean equals(Object other){
if(!(other instanceof Vertex)) return false;
return ((Vertex)other).id == id;
}
#Override
public int hashCode() { return id; }
}

Categories