Java 8 Interview Questions and Answers

author image Hirely
at 05 Jan, 2025

Question: How do you create a thread in Java?

Answer:

In Java, you can create a thread in two main ways:

  1. By extending the Thread class
  2. By implementing the Runnable interface

Each method has its own use case, and the choice depends on your specific requirements.


1. Creating a Thread by Extending the Thread Class:

To create a thread by extending the Thread class, you need to follow these steps:

  1. Extend the Thread class.
  2. Override the run() method to define the task the thread will execute.
  3. Create an instance of your subclass and call the start() method to begin execution.

Example:

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread is running...");
    }

    public static void main(String[] args) {
        // Create an instance of MyThread
        MyThread thread = new MyThread();

        // Start the thread
        thread.start();
    }
}

Explanation:

  • Step 1: The MyThread class extends the Thread class.
  • Step 2: The run() method is overridden to define the task the thread will perform.
  • Step 3: The start() method is called to begin executing the thread. The start() method internally calls the run() method.

2. Creating a Thread by Implementing the Runnable Interface:

Another way to create a thread is by implementing the Runnable interface. This is a more flexible approach, as it allows you to separate the thread’s task from the thread itself.

  1. Implement the Runnable interface.
  2. Override the run() method to define the task.
  3. Pass the Runnable instance to a Thread object and call start().

Example:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable thread is running...");
    }

    public static void main(String[] args) {
        // Create an instance of MyRunnable
        MyRunnable myRunnable = new MyRunnable();

        // Create a thread object and pass the Runnable to it
        Thread thread = new Thread(myRunnable);

        // Start the thread
        thread.start();
    }
}

Explanation:

  • Step 1: The MyRunnable class implements the Runnable interface and provides the run() method.
  • Step 2: The run() method defines the task that will be executed by the thread.
  • Step 3: A new Thread object is created by passing the Runnable instance to the Thread constructor. The start() method is then called to begin execution.

3. Differences Between Extending Thread and Implementing Runnable:

AspectExtending ThreadImplementing Runnable
InheritanceInherits from Thread classImplements the Runnable interface
Task DefinitionTask is defined in the run() method of the subclassTask is defined in the run() method of the Runnable interface
FlexibilityLess flexible; can’t extend another class (because Java supports single inheritance)More flexible; can implement multiple interfaces or extend another class
UsageLess preferred for complex scenarios where multiple tasks need to be performedPreferred in cases where you need more flexibility, especially when using thread pools
Resource SharingNot as suitable for sharing resources between threads (unless synchronized)Better for sharing resources since it can be used with ExecutorService or thread pools

4. Starting the Thread:

After creating the thread (either by extending Thread or implementing Runnable), you start the thread using the start() method. The start() method internally calls the run() method, but it executes the run() method in a separate thread of execution.

Important Notes:

  • The start() method initiates the thread, but does not immediately execute the code inside the run() method. Instead, it schedules the thread to run.
  • The run() method is not executed directly; it is invoked by the Java Virtual Machine (JVM) when the thread is scheduled to run.
  • The Thread class also provides various methods for controlling the thread, such as sleep(), join(), and interrupt(), but these are usually used for advanced thread control.

Conclusion:

  • Extend the Thread class when you want to define the thread’s behavior in the subclass and are not concerned about reusing the thread behavior in multiple classes.
  • Implement the Runnable interface when you need flexibility, such as when you want to define the thread’s task separately from the thread itself or when multiple threads need to share the same task.

Question: What is the purpose of the final keyword in Java?

Answer:

The final keyword in Java is used to define constants, prevent method overriding, and restrict inheritance. It can be applied to variables, methods, and classes, and it has different meanings depending on where it is used.

Here’s a breakdown of the different uses of final:


1. Final Variables:

When the final keyword is applied to a variable, it makes the variable constant, meaning that its value cannot be changed once it has been assigned.

  • Primitive data types: If the variable is a primitive data type (e.g., int, float, etc.), it means the value cannot be modified.
  • Reference variables: If the variable is a reference type (e.g., an object), the reference (i.e., the memory address) cannot be changed, but the contents of the object itself can still be modified.

Example:

final int MAX_VALUE = 100; // The value of MAX_VALUE cannot be changed.

MAX_VALUE = 200; // Compile-time error: cannot assign a value to a final variable.

In the case of reference variables:

final StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");  // This is allowed because the object is still mutable.
sb = new StringBuilder("New Value");  // Compile-time error: cannot reassign the reference.

2. Final Methods:

When the final keyword is applied to a method, it means the method cannot be overridden by subclasses.

This is useful for preventing modification of critical methods, such as methods that provide essential functionality or security measures.

Example:

class Animal {
    public final void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    // This will result in a compile-time error because sound() is final in the parent class.
    public void sound() {
        System.out.println("Dog barks");
    }
}

3. Final Classes:

When the final keyword is applied to a class, it means the class cannot be subclassed. This is used when you want to prevent inheritance from a particular class.

Example:

final class MathUtil {
    public static int add(int a, int b) {
        return a + b;
    }
}

// This will result in a compile-time error because MathUtil is final and cannot be extended.
class AdvancedMathUtil extends MathUtil {
    // Some code
}

4. Final Parameters:

The final keyword can also be applied to method parameters to indicate that the parameter cannot be reassigned within the method. It ensures that the value passed to the method remains unchanged throughout its execution.

Example:

public void calculateSum(final int a, final int b) {
    // a = 10; // Compile-time error: cannot assign a value to final variable 'a'
    System.out.println(a + b);
}

Key Points to Remember:

  • Final Variables: Once assigned, their values cannot be changed.
  • Final Methods: Cannot be overridden by subclasses.
  • Final Classes: Cannot be subclassed or extended.
  • Final Parameters: Cannot be modified inside the method.

Conclusion:

The final keyword in Java provides a way to define constants, enforce method behavior (prevent overriding), and prevent inheritance. It is a powerful tool for ensuring that certain aspects of your program remain immutable and fixed, which can help improve code reliability, security, and maintainability.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as Java interview questions, Java interview experiences, and details about various Java job positions. Click here to check it out.

Related Posts

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now