Top

Java Programming

11.

Explain the contract between `equals()` and `hashCode()`.

Ans:

The contract between equals() and hashCode() is critical when using objects in hash-based collections like HashMap, HashSet, and Hashtable.

The contract, as defined in the Object class documentation, states:

  1. If two objects are equal according to the equals(Object) method, then calling the hashCode() method on each of the two objects must produce the same integer result. (If a.equals(b) is true, then a.hashCode() == b.hashCode() must be true.)
  2. If two objects are unequal according to the equals(Object) method, it is not required that calling the hashCode() method on each of the two objects produce distinct integer results. However, producing distinct results for unequal objects may improve the performance of hash tables. (If a.equals(b) is false, a.hashCode() == b.hashCode() can be true or false.)

In simple terms:

  • Equal objects MUST have the same hash code.
  • Unequal objects MAY have the same hash code (this is called a hash collision).

Failing to follow this contract will lead to incorrect behavior when objects are stored in hash-based collections. For example, if you add an object to a `HashSet` and then try to check if it `contains()` an equal object, the check will fail if the hash codes are different, even if `.equals()` would return true.

12.

What is the difference between checked and unchecked exceptions?

Ans:

In Java, the exception hierarchy is headed by the Throwable class.

Checked Exceptions:

  • These are exceptions that are checked at compile-time.
  • They are subclasses of the Exception class (but not subclasses of RuntimeException).
  • If a method can throw a checked exception, it must either handle the exception using a try-catch block or declare it using the throws keyword.
  • Examples include IOException, SQLException, and ClassNotFoundException. They represent exceptional conditions that a well-written application should anticipate and recover from.

Unchecked Exceptions (Runtime Exceptions):

  • These are exceptions that are not checked at compile-time.
  • They are subclasses of the RuntimeException class.
  • The compiler does not force you to handle or declare them.
  • They usually indicate programming errors, such as logic errors or improper use of an API.
  • Examples include NullPointerException, ArrayIndexOutOfBoundsException, and IllegalArgumentException.

There is also a third category, Errors, which are also unchecked. They represent serious problems that a reasonable application should not try to catch, such as OutOfMemoryError or StackOverflowError.

13.

What is the difference between `throw` and `throws`?

Ans:

  • The throw keyword is used to explicitly throw a single exception from a method or any block of code. It is used inside a method body to throw an instance of an Exception or any of its subclasses.
void checkAge(int age) {
    if (age < 18) {
        throw new ArithmeticException("Access denied - You must be at least 18 years old.");
    }
}
  • The throws keyword is used in a method signature to declare the exceptions that the method might throw. It informs the caller of the method about the exceptions it needs to handle. It can declare multiple exceptions, separated by a comma.
// This method declares that it can throw an IOException
import java.io.IOException;

void myMethod() throws IOException {
    // code that might produce an IOException
}

14.

What is the purpose of the `finally` block?

Ans:

The finally block is an optional block in a try-catch statement that is used to execute important cleanup code.

The key feature of the finally block is that it always executes, regardless of whether an exception was thrown or caught in the try block. The only times a `finally` block will not execute are if the JVM exits (e.g., System.exit() is called) or if a catastrophic error occurs that halts the thread.

It is primarily used for resource de-allocation, such as:

  • Closing a file stream.
  • Closing a database connection.
  • Closing a network socket.

This ensures that resources are released properly, preventing resource leaks.

Connection conn = null;
try {
    conn = Database.getConnection();
    // ... perform database operations
} catch (SQLException e) {
    // ... handle exception
} finally {
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) {
            /* log or ignore */
        }
    }
}

Note: The `try-with-resources` statement, introduced in Java 7, is now the preferred way to handle resource cleanup as it's more concise and less error-prone.

15.

What is the `try-with-resources` statement?

Ans:

Introduced in Java 7, the try-with-resources statement is a feature that ensures that each resource is closed at the end of the statement. It simplifies the cleanup of resources like files, sockets, and database connections.

Any object that implements the java.lang.AutoCloseable or java.io.Closeable interface can be used as a resource.

Before Java 7 (using a `finally` block):

FileOutputStream fos = null;
try {
    fos = new FileOutputStream("file.txt");
    fos.write("Hello".getBytes());
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fos != null) {
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

With `try-with-resources`:

try (FileOutputStream fos = new FileOutputStream("file.txt")) {
    fos.write("Hello".getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

The compiler automatically generates the code to close the FileOutputStream resource, making the code much cleaner and safer by avoiding common resource leak errors.

16.

What is the Collections Framework?

Ans:

The Java Collections Framework is a unified architecture for representing and manipulating collections (groups of objects).

It provides a set of standard interfaces and classes to handle common data structures. Key interfaces include:

  • Collection: The root interface of the framework.
  • List: An ordered collection that allows duplicate elements. Major implementations are ArrayList and LinkedList.
  • Set: A collection that does not allow duplicate elements. Major implementations are HashSet, LinkedHashSet, and TreeSet.
  • Queue: A collection used to hold elements prior to processing, typically in a FIFO (First-In, First-Out) order.
  • Map: An object that maps keys to values. It does not allow duplicate keys. It is not a true 'Collection' as it doesn't extend the Collection interface, but it is considered part of the framework. Major implementations are HashMap, LinkedHashMap, and TreeMap.

The framework provides high-performance implementations of these data structures and algorithms to manipulate them (like sorting and searching via the `Collections` utility class).

17.

What is the difference between `ArrayList` and `LinkedList`?

Ans:

Both `ArrayList` and `LinkedList` are implementations of the `List` interface, but they have very different underlying data structures.

FeatureArrayListLinkedList
Underlying StructureUses a dynamic array to store elements.Uses a doubly-linked list (each element has a reference to the previous and next element).
Element AccessFast. Provides fast random access using the get(int index) method, which takes O(1) time, because it can be calculated directly from the array index.Slow. To access an element at a specific index, it has to traverse the list from the beginning or end, which takes O(n) time.
Insertion/DeletionSlow. Adding or removing an element from the middle of the list is slow because it requires shifting all subsequent elements, which takes O(n) time. Adding to the end is generally O(1).Fast. Adding or removing an element from the beginning or end is very fast (O(1)). Insertion/deletion in the middle is also faster than ArrayList if you already have a reference to the node.
Memory OverheadLower memory overhead as it only stores the elements.Higher memory overhead because each element (node) stores the data plus references to the next and previous nodes.
When to UseBest choice when your primary need is to access elements by their index and you don't have a lot of insertion/deletion operations in the middle of the list.Best choice when you have a large number of insertion/deletion operations, especially at the beginning or end of the list, and random access is not a priority.

18.

How does a `HashMap` work internally?

Ans:

A HashMap in Java works on the principle of hashing. It stores data in key-value pairs.

  1. put(key, value) operation:
    • When you call put(key, value), the HashMap first calculates the hash code of the key by calling its hashCode() method.
    • This hash code is then used to calculate an index (or 'bucket location') within the HashMap's internal array of nodes. The formula is typically index = hashCode(key) & (n-1), where 'n' is the size of the array.
    • The HashMap goes to that index.
      • If the bucket is empty, it creates a new Node(key, value) and places it there.
      • If the bucket is not empty (a hash collision), it iterates through the nodes in that bucket (which are stored in a linked list or, since Java 8, a balanced tree if the list gets too long). For each node, it checks if the key is the same using the equals() method.
      • If a node with the same key is found, it updates the value of that node.
      • If no node with the same key is found, it adds the new node to the end of the list (or tree) in that bucket.
  2. get(key) operation:
    • It follows the same process: calculate the hash code, find the bucket index.
    • It then iterates through the nodes in that bucket, using the equals() method to find the node with the exact key, and returns the corresponding value. If no such key is found, it returns null.

This is why the contract between equals() and hashCode() is so important for the correct functioning of a `HashMap`.

19.

What is the difference between `HashSet`, `LinkedHashSet`, and `TreeSet`?

Ans:

All three are implementations of the `Set` interface, which means they store unique elements.

FeatureHashSetLinkedHashSetTreeSet
Underlying StructureBacked by a HashMap.Backed by a LinkedHashMap. It's a combination of a hash table and a linked list.Backed by a TreeMap, which uses a Red-Black Tree (a self-balancing binary search tree).
OrderingUnordered. It makes no guarantees about the iteration order of the elements; it may even change over time.Ordered. It maintains the insertion order of elements. When you iterate through it, elements appear in the order they were added.Sorted. It stores elements in a sorted order (either natural ordering or by a specified Comparator).
PerformanceOffers the best performance for add, remove, and contains operations (O(1) on average).Slightly slower than HashSet due to the overhead of maintaining the linked list, but still O(1) on average.Slower for add, remove, and contains operations (O(log n)) because it needs to maintain the sorted order.
Null ElementsAllows one null element.Allows one null element.Does not allow null elements (will throw a NullPointerException), as it needs to compare elements.

20.

What is the difference between `Comparable` and `Comparator`?

Ans:

Both interfaces are used to sort objects in Java.

Comparable Interface:

  • It is used to define the natural ordering of a class.
  • The class whose objects need to be sorted must implement this interface itself.
  • It contains a single method: int compareTo(Object obj).
  • It provides a single way of sorting. For example, you might implement `Comparable` in an `Employee` class to sort employees by their ID.
public class Employee implements Comparable<Employee> {
    //...
    private int id;

    @Override
    public int compareTo(Employee other) {
        return Integer.compare(this.id, other.id);
    }
}

// To sort: Collections.sort(listOfEmployees);

Comparator Interface:

  • It is used to define a custom ordering for a class, or to sort objects of a class that you cannot modify.
  • A separate class is created that implements the `Comparator` interface.
  • It contains a single method: int compare(Object obj1, Object obj2).
  • It provides multiple ways of sorting. You can create one comparator to sort `Employee` objects by name, another to sort them by salary, etc.
public class SortEmployeeByName implements Comparator<Employee> {
    @Override
    public int compare(Employee e1, Employee e2) {
        return e1.getName().compareTo(e2.getName());
    }
}

// To sort: Collections.sort(listOfEmployees, new SortEmployeeByName());

In summary, use `Comparable` for the default, natural order. Use `Comparator` for custom or multiple sorting orders.

Loading…
Tags: Java Programming Interview Questions and Answers || Java Programming Sort Questions and Answers || Java Programming Detailed Questions and Answers || Java Programming Tutorial