Java Question Bank with Answers
Answers for Core Java Question Bank
Chapter 2: Objects and Classes.
Difficult Level Questions
18. Design a Java class called Book with attributes title, author, isbn, and price (double). Implement the following:
- A parameterized constructor.
- A method displayBookDetails() that prints all book information.
- Override equals() and hashCode() such that two books are considered equal if their isbn is identical.
- Override toString() to return a user-friendly string representation of the book.
- Demonstrate the creation of an Array of Objects of type Book, add some books, and use the equals() method to check for duplicate books based on isbn.
Answer:
import java.util.Objects; // For Objects.hash() in hashCode()
public class Book {
private String title;
private String author;
private String isbn;
private double price;
// Parameterized Constructor
public Book(String title, String author, String isbn, double price) {
this.title = title;
this.author = author;
this.isbn = isbn;
this.price = price;
}
// Method to display book details
public void displayBookDetails() {
System.out.println("— Book Details —");
System.out.println("Title: " + title);
System.out.println("Author: " + author);
System.out.println("ISBN: " + isbn);
System.out.println("Price: $" + String.format("%.2f", price));
System.out.println("——————–");
}
// Override equals() method (based on ISBN)
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // Self check
if (obj == null || getClass() != obj.getClass()) return false; // Null or different class
Book otherBook = (Book) obj;
return Objects.equals(this.isbn, otherBook.isbn);
}
// Override hashCode() method (consistent with equals)
@Override
public int hashCode() {
return Objects.hash(isbn);
}
// Override toString() for easy display
@Override
public String toString() {
return "Book[Title=’" + title + "’, Author=’" + author + "’, ISBN=’" + isbn + "’, Price=$" + String.format("%.2f", price) + "]";
}
// Main method
public static void main(String[] args) {
// Create an array of Book objects
Book[] books = new Book[4]; // Array of size 4
// Initialize array elements
books[0] = new Book("The Hitchhiker’s Guide to the Galaxy", "Douglas Adams", "978-0345391803", 12.99);
books[1] = new Book("Pride and Prejudice", "Jane Austen", "978-0141439518", 9.50);
books[2] = new Book("The Hitchhiker’s Guide to the Galaxy", "Douglas Adams", "978-0345391803", 15.00); // Duplicate ISBN
books[3] = new Book("1984", "George Orwell", "978-0451524935", 10.25);
// Display all books
System.out.println("— All Books in the Array —");
for (Book book : books) {
System.out.println(book); // Uses toString()
}
System.out.println();
// Check for duplicate books based on ISBN
System.out.println("— Checking for Duplicate Books (based on ISBN) —");
for (int i = 0; i < books.length; i++) {
for (int j = i + 1; j < books.length; j++) {
if (books[i].equals(books[j])) {
System.out.println("Duplicate found!");
System.out.println("Book 1: " + books[i].title + " (ISBN: " + books[i].isbn + ")");
System.out.println("Book 2: " + books[j].title + " (ISBN: " + books[j].isbn + ")");
System.out.println("These books are considered equal based on ISBN.");
System.out.println("———————————————-");
}
}
}
}
}
19. Evaluate the role of static methods and static fields in designing utility classes (e.g., Math class). Compare the use of static members with instance members in terms of memory management and accessibility. Under what circumstances would you strictly avoid making a method static? Provide justifications.
Answer:
Role of static Methods and static
Fields in Utility Classes:
static
methods and static fields play a crucial role in designing utility
classes (also known as helper classes or service classes), which provide
functionalities that do not depend on the state of any particular object . The java.lang.Math class
is a prime example.
- static Fields: Utility classes often use static final fields for constants that are universally applicable and do not change (e.g., Math.PI, Math.E) . These constants are loaded once with the class and shared across the entire application, avoiding redundant memory allocation .
- static Methods: Utility classes consist primarily of static methods (e.g., Math.sqrt(), Math.random(), Integer.parseInt()) . These methods perform operations that take input, compute a result, and return it, without needing to access or modify any instance-specific data . They can be called directly on the class itself (Math.sqrt) without creating an object of the utility class .
Comparison with Instance Members:
| Feature | static Members | Instance Members | 
| Association | Associated with the class itself . | Associated with a specific object (instance) of the class . | 
| Memory Management | static fields are allocated once in the method area (or static memory) when the class is loaded . static methods are part of the class definition and don’t require separate memory per object. | Instance fields are allocated memory every time a new object is created (in the heap) . Instance methods operate on this object-specific data and are part of each object’s behavior, implicitly passed this. | 
| Accessibility | Accessed using the class name (ClassName.staticMember) . Can be accessed from static and non-static contexts. | Accessed using an object reference (objectName.instanceMember) . Can only be accessed from non-static contexts or from static contexts via an object reference. | 
| State | Do not manage or depend on object-specific state. static fields hold shared state . | Manage and depend on the unique state of each object . | 
| Initialization | static fields are initialized when the class is loaded (either directly or via static blocks) . | Instance fields are initialized when an object is created (via constructors or direct assignment at declaration). | 
Circumstances to Strictly Avoid Making a Method static (and Justifications):
You should strictly avoid making a method static in the following scenarios:
1. When the method needs to access or modify instance-specific data:
o Justification: static methods cannot directly access non-static (instance) variables or call non-static methods without an object reference . If a method inherently operates on the state of a particular object (e.g., getName() or setAge() for a Person object), it must be an instance method. Making it static would force you to pass the object explicitly as a parameter, which can break encapsulation and lead to less object-oriented design .
2. When the method needs to be overridden by subclasses:
o Justification: static methods cannot be overridden in Java . While a subclass can declare a static method with the same signature as a static method in its superclass, this is method hiding, not overriding. Polymorphism (the ability of a method to behave differently based on the actual object type at runtime) works only with instance methods . If you intend for a method’s behavior to vary across subclasses, it must be an instance method.
3. When the method’s behavior is tied to the lifecycle or state of an object:
o Justification: Methods that perform actions related to an object’s creation, destruction, or internal state changes (e.g., open() a file, close() a connection, calculateBalance() for an account) are inherently object-dependent. Making them static would disconnect them from the object they are supposed to operate on, leading to confusing design and potential errors if not managed carefully.
4. When a class is designed for dependency injection or interface-based programming:
o Justification: Static methods cannot be part of an interface in a way that allows them to be implemented by classes for polymorphic behavior. If you’re designing a system where you want to swap out different implementations of a service (e.g., a Logger interface with FileLogger and ConsoleLogger implementations), the methods must be instance methods to allow for polymorphism and flexible dependency management. static methods tightly couple the client code to a specific class.
