0

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.

3
  • 3
    I'd firstly suggest reading on object equality in Java (see here for API, but you probably want to broaden the search to concepts/tutorials). Also note that if you correctly override hashCode and equals, you can use Sets to automatically maintain duplicate-free collections. Commented Nov 26, 2018 at 16:35
  • You can add obj1.getClass().equals(obj2.getClass()) to the method that checks the books for equality. This condition is true only if both books are instances of the same subclass. May be a dupe of this. Commented Nov 26, 2018 at 16:39
  • Try using something like: if(book instanceof ReadingBook ) condition in your eqauls method, then cast it to the appropriate type if its true. Commented Nov 26, 2018 at 16:40

5 Answers 5

2

You can use the following design:

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

}
Sign up to request clarification or add additional context in comments.

Comments

1

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.

1 Comment

I've tried it, but since the "sameBookCheck" method gets 'Book' objects, the isEqual method runs from the 'Book' class and not from the LearningBook or ReadingBook
1

You can ask the book instance for its class and check class equality.

book1.getClass().equals(book2.getClass())

Comments

1

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
  }
}

2 Comments

But I also need to compare between the specific variable of the subclasses ('subject' for LearningBook and 'numberOfPages' for ReadingBook).
You are writing a method for this correct? Then if the type of those two objects are not equals you can return fasle. Else if the types are same, you can extend your methods to check the specific variables also. I'll add a example to my answer
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.