fbpx

Top 100 Java 11 Interview Questions and Answers

Top 100 Java 11 Interview Questions and Answers
Contents show

1. What are the new features introduced in Java 11?

Answer:
Java 11 introduced features like the var keyword for local variables, HTTP client API, improved garbage collector, and Epsilon GC. It also included updates to existing libraries and added new methods in the String class.

Code Snippet:

var name = "John Doe";
System.out.println(name);

Explanation:
The var keyword allows type inference, making code more concise.

Learn more about Java 11 features


2. How does the var keyword work in Java?

Answer:
The var keyword allows the compiler to infer the type of a local variable based on the value assigned to it. It cannot be used for method parameters, fields, or return types.

Code Snippet:

var age = 30; // Compiler infers type as int

Explanation:
In this example, the compiler knows age is of type int because it’s assigned an integer value.

Learn more about var


3. How do you perform an HTTP GET request using the new HTTP Client API in Java 11?

Answer:
Java 11 introduced the HttpClient class to make HTTP requests. Here’s an example of a GET request:

Code Snippet:

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(new URI("https://jsonplaceholder.typicode.com/posts/1"))
                .GET()
                .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}

Explanation:
This code snippet sends a GET request to a URL and prints the response.

Learn more about HttpClient


4. What is Epsilon GC in Java 11?

Answer:
Epsilon GC is a no-op garbage collector introduced in Java 11. It doesn’t perform any actual garbage collection, making it useful for performance testing and scenarios where garbage collection is unnecessary.

Code Snippet:

java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC MyProgram

Explanation:
This command enables Epsilon GC for running a Java program.

Learn more about Epsilon GC


5. How do you use the String::isBlank method introduced in Java 11?

Answer:
The isBlank method checks if a string is empty or contains only white spaces.

Code Snippet:

String str = "  ";
boolean isBlank = str.isBlank(); // true

Explanation:
In this example, isBlank returns true because str contains only white spaces.

Learn more about String::isBlank


6. What is the purpose of the java.util.concurrent.Flow package introduced in Java 9 and enhanced in Java 11?

Answer:
The java.util.concurrent.Flow package provides classes and interfaces for reactive programming. It defines the Publisher, Subscriber, and Subscription interfaces for implementing the reactive stream pattern.

Code Snippet:

// Example of a simple Publisher
import java.util.concurrent.Flow;
public class SimplePublisher implements Flow.Publisher<Integer> {
    // Implementation here
}

Explanation:
This code snippet demonstrates creating a simple Publisher class.

Learn more about java.util.concurrent.Flow


7. How do you use the Local-Variable Syntax for Lambda Parameters feature introduced in Java 11?

Answer:
Java 11 allows using var for lambda parameters, enabling more concise code.

Code Snippet:

// Before Java 11
list.forEach((String s) -> System.out.println(s));

// With Java 11
list.forEach((var s) -> System.out.println(s));

Explanation:
In the second example, var is used instead of explicitly specifying the type.

Learn more about Local-Variable Syntax for Lambda Parameters


8. What is the purpose of the java.nio.file.Files::readString method introduced in Java 11?

Answer:
The readString method reads a file and returns its content as a string, simplifying file reading operations.

Code Snippet:

import java.nio.file.*;
public class Main {
    public static void main(String[] args) throws Exception {
        String content = Files.readString(Paths.get("file.txt"));
        System.out.println(content);
    }
}

Explanation:
This code snippet reads the content of a file named file.txt.

Learn more about java.nio.file.Files::readString


9. How do you use the java.nio.file.Path::of method introduced in Java 11?

Answer:
The of method creates a Path instance from a string, allowing easier manipulation of file paths.

Code Snippet:

Path path = Path.of("/usr/local/bin");

Explanation:
In this example, a Path instance is created for the directory /usr/local/bin.

Learn more about java.nio.file.Path::of


10. How do you use the java.nio.file.Path::normalize method in Java 11?

Answer:
The normalize method removes redundant elements from a path, making it more concise and easier to work with.

Code Snippet:

Path path = Paths.get("/usr/local/../bin").normalize();

Explanation:
In this example, the normalize method simplifies the path by removing the redundant local/...

Learn more about java.nio.file.Path::normalize


11. How do you use the java.util.Optional::isEmpty method introduced in Java 11?

Answer:
The isEmpty method checks if an Optional instance is empty (contains no value).

Code Snippet:

Optional<String> opt = Optional.empty();
boolean empty = opt.isEmpty(); // true

Explanation:
In this example, isEmpty returns true because opt is empty.

Learn more about java.util.Optional::isEmpty


12. What is the purpose of the java.lang.StackWalker class introduced in Java 9 and enhanced in Java 11?

Answer:
StackWalker provides a more efficient and controlled way to access the stack trace. It allows filtering and walking over frames, making it useful for debugging and profiling.

Code Snippet:

StackWalker walker = StackWalker.getInstance();
walker.forEach(System.out::println);

Explanation:
This code snippet prints the stack frames.

Learn more about java.lang.StackWalker


13. How do you use the java.lang.ProcessHandle::onExit method introduced in Java 9 and enhanced in Java 11?

Answer:
The onExit method allows you to perform actions when a process exits.

Code Snippet:

ProcessBuilder pb = new ProcessBuilder("notepad.exe");
Process process = pb.start();
ProcessHandle handle = process.toHandle();
handle.onExit().thenRun(() -> System.out.println("Process exited"));

Explanation:
In this example, when the Notepad process exits, it prints a message.

Learn more about java.lang.ProcessHandle::onExit


14. What is the purpose of the java.util.concurrent.atomic.VarHandle introduced in Java 9 and enhanced in Java 11?

Answer:
VarHandle provides a way to perform atomic operations on variables, arrays, and memory locations. It’s a low-level mechanism for fine-grained concurrency control.

Code Snippet:

VarHandle handle = MethodHandles.lookup().in(Object.class).findVarHandle(
    MyClass.class, "myField", int.class);
handle.get(myObject);

Explanation:
This code snippet demonstrates using a VarHandle to get the value of a field.

Learn more about java.util.concurrent.atomic.VarHandle


15. How do you use the java.lang.constant.Constable interface introduced in Java 11?

Answer:
Constable is an interface that represents values that can be constants. It’s used for compile-time constant folding.

Code Snippet:

String literal = "hello".strip();
boolean isConst = Constable.class.isAssignableFrom(literal.getClass()); // true

Explanation:
In this example, isConst is true because the string literal can be a constant.

Learn more about java.lang.constant.Constable


16. What is the purpose of the java.util.stream.Collectors::teeing method introduced in Java 12?

Answer:
teeing is a collector that performs two separate collecting operations and then applies a binary operator to their results.

Code Snippet:

Map<String, Integer> result = Stream.of(1, 2, 3, 4)
    .collect(Collectors.teeing(
            Collectors.counting(),
            Collectors.summingInt(Integer::intValue),
            (count, sum) -> Map.of("count", count, "sum", sum)
    ));

Explanation:
This code snippet counts the elements and calculates their sum concurrently.

Learn more about java.util.stream.Collectors::teeing


17. What is the purpose of the java.lang.String::transform method introduced in Java 12?

Answer:
The transform method applies a function to the string, returning a new string with the result.

Code Snippet:

String original = "hello";
String transformed = original.transform(s -> s.toUpperCase());

Explanation:
In this example, transform is used to convert the string to uppercase.

Learn more about java.lang.String::transform


18. How do you use the java.util.stream.Collectors::mapping method introduced in Java 9?

Answer:
The mapping collector transforms the elements before applying another collector.

Code Snippet:

List<String> names = List.of("John", "Jane", "Bob");
Map<String, Integer> nameLengths = names.stream()
        .collect(Collectors.groupingBy(Function.identity(),
                Collectors.mapping(String::length, Collectors.summingInt(Integer::intValue))));

Explanation:
This code snippet groups names by identity and maps them to their lengths.

Learn more about java.util.stream.Collectors::mapping


19. What is the purpose of the java.util.stream.Stream::dropWhile method introduced in Java 9?

Answer:
The dropWhile method discards elements from the stream until a condition becomes false.

Code Snippet:

List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<Integer> result = numbers.stream()
        .dropWhile(n -> n < 3)
        .collect(Collectors.toList());

Explanation:
In this example, elements less than 3 are dropped, resulting in [3, 4, 5].

Learn more about java.util.stream.Stream::dropWhile


20. How do you use the java.util.stream.Stream::takeWhile method introduced in Java 9?

Answer:
The takeWhile method returns elements from the stream as long as a condition is true.

Code Snippet:

List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<Integer> result = numbers.stream()
        .takeWhile(n -> n < 3)
        .collect(Collectors.toList());

Explanation:
In this example, elements less than 3 are taken, resulting in [1, 2].

Learn more about java.util.stream.Stream::takeWhile


21. What is the purpose of the java.util.stream.Stream::iterate method introduced in Java 9?

Answer:
The iterate method generates a stream by repeatedly applying a function to its previous result.

Code Snippet:

Stream<Integer> stream = Stream.iterate(1, n -> n * 2);
List<Integer> result = stream.limit(5).collect(Collectors.toList());

Explanation:
In this example, the stream will generate [1, 2, 4, 8, 16].

Learn more about java.util.stream.Stream::iterate


22. What is the purpose of the java.util.stream.Stream::ofNullable method introduced in Java 9?

Answer:
ofNullable creates a stream with a single element if the provided value is non-null, otherwise, it returns an empty stream.

Code Snippet:

String name = "John";
Stream<String> stream = Stream.ofNullable(name);

Explanation:
In this example, if name is non-null, the stream will contain “John”, otherwise, it will be empty.

Learn more about java.util.stream.Stream::ofNullable


23. How do you use the java.util.stream.IntStream::takeWhile method introduced in Java 9?

Answer:
IntStream.takeWhile operates on a stream of integers, returning elements as long as a condition is true.

Code Snippet:

int[] numbers = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(numbers);
IntStream result = stream.takeWhile(n -> n < 3);

Explanation:
In this example, elements less than 3 are taken, resulting in an IntStream containing [1, 2].

Learn more about java.util.stream.IntStream::takeWhile


24. What is the purpose of the java.util.stream.IntStream::dropWhile method introduced in Java 9?

Answer:
IntStream.dropWhile operates on a stream of integers, discarding elements until a condition becomes false.

Code Snippet:

int[] numbers = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(numbers);
IntStream result = stream.dropWhile(n -> n < 3);

Explanation:
In this example, elements less than 3 are dropped, resulting in an IntStream containing [3, 4, 5].

Learn more about java.util.stream.IntStream::dropWhile


25. How do you use the java.util.stream.LongStream::takeWhile method introduced in Java 9?

Answer:
LongStream.takeWhile operates on a stream of long values, returning elements as long as a condition is true.

Code Snippet:

long[] numbers = {1L, 2L, 3L, 4L, 5L};
LongStream stream = Arrays.stream(numbers);
LongStream result = stream.takeWhile(n -> n < 3L);

Explanation:
In this example, elements less than 3 are taken, resulting in a LongStream containing [1L, 2L].

Learn more about java.util.stream.LongStream::takeWhile


26. What is the purpose of the java.util.stream.LongStream::dropWhile method introduced in Java 9?

Answer:
LongStream.dropWhile operates on a stream of long values, discarding elements until a condition becomes false.

Code Snippet:

long[] numbers = {1L, 2L, 3L, 4L, 5L};
LongStream stream = Arrays.stream(numbers);
LongStream result = stream.dropWhile(n -> n < 3L);

Explanation:
In this example, elements less than 3 are dropped, resulting in a LongStream containing [3L, 4L, 5L].

Learn more about java.util.stream.LongStream::dropWhile


27. What is the purpose of the java.util.stream.DoubleStream::takeWhile method introduced in Java 9?

Answer:
DoubleStream.takeWhile operates on a stream of double values, returning elements as long as a condition is true.

Code Snippet:

double[] numbers = {1.0, 2.0, 3.0, 4.0, 5.0};
DoubleStream stream = Arrays.stream(numbers);
DoubleStream result = stream.takeWhile(n -> n < 3.0);

Explanation:
In this example, elements less than 3.0 are taken, resulting in a DoubleStream containing [1.0, 2.0].

Learn more about java.util.stream.DoubleStream::takeWhile


28. What is the purpose of the java.util.stream.DoubleStream::dropWhile method introduced in Java 9?

Answer:
DoubleStream.dropWhile operates on a stream of double values, discarding elements until a condition becomes false.

Code Snippet:

double[] numbers = {1.0, 2.0, 3.0, 4.0, 5.0};
DoubleStream stream = Arrays.stream(numbers);
DoubleStream result = stream.dropWhile(n -> n < 3.0);

Explanation:
In this example, elements less than 3.0 are dropped, resulting in a DoubleStream containing [3.0, 4.0, 5.0].

Learn more about java.util.stream.DoubleStream::dropWhile


29. What is the purpose of the java.util.Optional::stream method introduced in Java 9?

Answer:
Optional.stream converts an Optional containing at most one non-null element into a stream.

Code Snippet:

Optional<String> optional = Optional.of("Hello");
Stream<String> stream = optional.stream();

Explanation:
In this example, the Optional containing “Hello” is converted into a stream with a single element.

Learn more about java.util.Optional::stream


30. How does the java.util.Optional::or method work in Java 9?

Answer:
Optional.or returns the value inside the Optional if it is present, otherwise, it returns the result of the provided supplier function.

Code Snippet:

Optional<String> optional = Optional.empty();
String result = optional.or(() -> "Default Value");

Explanation:
In this example, since optional is empty, the result will be “Default Value”.

Learn more about java.util.Optional::or


31. What is the purpose of the java.util.Optional::ifPresentOrElse method introduced in Java 9?

Answer:
Optional.ifPresentOrElse takes two Runnable instances. The first one is executed if a value is present, and the second one is executed if the value is absent.

Code Snippet:

Optional<String> optional = Optional.of("Hello");
optional.ifPresentOrElse(
    value -> System.out.println("Value is present: " + value),
    () -> System.out.println("Value is absent")
);

Explanation:
In this example, since optional contains a value, the first Runnable is executed, resulting in “Value is present: Hello”.

Learn more about java.util.Optional::ifPresentOrElse


32. How does the java.util.Optional::stream method work in Java 9?

Answer:
Optional.stream converts an Optional containing at most one non-null element into a stream.

Code Snippet:

Optional<String> optional = Optional.of("Hello");
Stream<String> stream = optional.stream();

Explanation:
In this example, the Optional containing “Hello” is converted into a stream with a single element.

Learn more about java.util.Optional::stream


36. What are the improvements introduced in the java.util.Optional class in Java 9?

Answer:
Java 9 introduced several useful methods to the Optional class, enhancing its functionality:

  1. ifPresentOrElse: Executes a specific action depending on whether a value is present or not.
  2. or: Returns the value if present, otherwise returns the result of a provided supplier function.
  3. stream: Converts an Optional into a stream of at most one element.
  4. ifPresentOrElse for OptionalInt, OptionalLong, and OptionalDouble: Similar to ifPresentOrElse, but for these specific types.

These additions improve the versatility and usability of Optional.

Learn more about java.util.Optional in Java 9


37. How does the java.util.concurrent.Flow API improve handling of reactive streams in Java 9?

Answer:
Java 9 introduced the java.util.concurrent.Flow API, which defines the components necessary for supporting reactive streams. It includes interfaces like Publisher, Subscriber, and Subscription that facilitate the implementation of reactive programming. This API helps in handling asynchronous and non-blocking streams of data in a more efficient and manageable way.

Learn more about java.util.concurrent.Flow


38. What is the purpose of the java.util.concurrent.CompletableFuture::delayedExecutor method in Java 9?

Answer:
CompletableFuture.delayedExecutor returns an executor that waits for a given delay before executing tasks. This is useful for introducing delays in asynchronous tasks.

Code Snippet:

Executor delayedExecutor = CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    // Task to be executed
}, delayedExecutor);

Explanation:
In this example, the task inside runAsync will be executed after a delay of 3 seconds.

Learn more about java.util.concurrent.CompletableFuture::delayedExecutor


39. How does the java.util.concurrent.CompletableFuture::newIncompleteFuture method work in Java 9?

Answer:
CompletableFuture.newIncompleteFuture returns a new incomplete CompletableFuture. This is useful when creating custom asynchronous operations or when the completion of a future is determined by non-standard means.

Code Snippet:

CompletableFuture<String> future = new CompletableFuture<>();

Explanation:
In this example, future is a new incomplete CompletableFuture that can be completed manually.

Learn more about java.util.concurrent.CompletableFuture::newIncompleteFuture


40. What is the purpose of the java.util.concurrent.CompletableFuture::copy method introduced in Java 9?

Answer:
CompletableFuture.copy creates a new CompletableFuture with the same result or exception as the original. It can be used to create independent futures that can be handled separately.

Code Snippet:

CompletableFuture<String> originalFuture = CompletableFuture.completedFuture("Result");
CompletableFuture<String> copyFuture = originalFuture.copy();

Explanation:
In this example, copyFuture will have the same result (“Result”) as originalFuture.

Learn more about java.util.concurrent.CompletableFuture::copy


41. How does the java.util.concurrent.CompletableFuture::orTimeout method work in Java 9?

Answer:
CompletableFuture.orTimeout returns a new CompletableFuture that completes exceptionally with a TimeoutException if not completed within the given timeout duration.

Code Snippet:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // Task to be executed
    return "Result";
}).orTimeout(2, TimeUnit.SECONDS);

Explanation:
In this example, if the task does not complete within 2 seconds, the future will complete exceptionally with a TimeoutException.

Learn more about java.util.concurrent.CompletableFuture::orTimeout


42. What is the purpose of the java.util.concurrent.CompletableFuture::completeAsync method in Java 9?

Answer:
CompletableFuture.completeAsync returns a new CompletableFuture that is asynchronously completed by the given Supplier. This is useful when the completion depends on the result of a non-blocking operation.

Code Snippet:

CompletableFuture<String> future = CompletableFuture.completeAsync(() -> {
    // Asynchronous task to be executed
    return "Result";
});

Explanation:
In this example, the CompletableFuture is completed asynchronously by the provided supplier.

Learn more about java.util.concurrent.CompletableFuture::completeAsync


43. How does the java.util.concurrent.CompletableFuture::completeOnTimeout method in Java 9 work?

Answer:
CompletableFuture.completeOnTimeout completes the CompletableFuture with a specified value if it hasn’t already completed before the given timeout duration. Otherwise, it returns the original result.

Code Snippet:

CompletableFuture<String> future = new CompletableFuture<>();
future.completeOnTimeout("Default Value", 2, TimeUnit.SECONDS);

Explanation:
If future is not completed within 2 seconds, it will be completed with the value “Default Value”.

Learn more about java.util.concurrent.CompletableFuture::completeOnTimeout


44. What is the purpose of the java.util.concurrent.CompletableFuture::minimalCompletionStage method introduced in Java 9?

Answer:
CompletableFuture.minimalCompletionStage returns a CompletionStage view of a CompletableFuture. It allows for interaction with a CompletableFuture without exposing its full set of methods.

Code Snippet:

CompletableFuture<String> future = CompletableFuture.completedFuture("Result");
CompletionStage<String> stage = future.minimalCompletionStage();

Explanation:
stage can be used as a CompletionStage, but it doesn’t have access to methods that may modify the CompletableFuture.

Learn more about java.util.concurrent.CompletableFuture::minimalCompletionStage


45. What improvements were introduced to the java.util.concurrent.locks.StampedLock class in Java 8?

Answer:
Java 8 introduced the StampedLock class, which is a new type of lock providing more flexible read and write access. It features three modes: reading, writing, and optimistic reading.

Code Snippet (Usage):

StampedLock lock = new StampedLock();

long stamp = lock.readLock();
try {
    // Reading operation
} finally {
    lock.unlockRead(stamp);
}

long writeStamp = lock.writeLock();
try {
    // Writing operation
} finally {
    lock.unlockWrite(writeStamp);
}

Explanation:
StampedLock provides a way to perform optimistic reading without blocking, which can lead to improved performance in certain scenarios.

Learn more about java.util.concurrent.locks.StampedLock


46. What are the benefits of using java.util.concurrent.locks.StampedLock over traditional locks?

Answer:
StampedLock provides several advantages over traditional locks:

  1. Optimistic Reading: Allows multiple threads to read concurrently without locking if no write operation is in progress.
  2. Upgradeable Locks: Supports upgrading a read lock to a write lock atomically.
  3. No Deadlock Risk: Doesn’t suffer from deadlock since it doesn’t rely on a strict ownership protocol.
  4. Improved Concurrency: Can lead to better performance in read-heavy workloads.

These features make StampedLock a powerful tool for certain concurrency scenarios.

Learn more about the benefits of java.util.concurrent.locks.StampedLock


47. How does the java.util.concurrent.locks.StampedLock::tryOptimisticRead method work?

Answer:
tryOptimisticRead attempts an optimistic read, returning a stamp if the lock state is not write-locked at the time of the call. It’s useful for situations where a read operation can proceed without blocking.

Code Snippet:

long stamp = lock.tryOptimisticRead();
if (lock.validate(stamp)) {
    // Perform read operation
} else {
    // Handle lock contention
}

Explanation:
The method returns a stamp which should be checked with validate to ensure the lock state hasn’t changed before performing the read operation.

Learn more about java.util.concurrent.locks.StampedLock::tryOptimisticRead


48. What is the purpose of the java.util.concurrent.locks.StampedLock::tryConvertToWriteLock method?

Answer:
tryConvertToWriteLock attempts to atomically upgrade a read lock to a write lock if the current thread holds a read lock and no other thread holds a conflicting lock.

Code Snippet:

long stamp = lock.readLock();
if (lock.tryConvertToWriteLock(stamp)) {
    // Successfully upgraded to write lock
    // Perform write operation
} else {
    // Handle lock contention
    lock.unlockRead(stamp); // Release the read lock
}

Explanation:
If successful, the method returns a write lock stamp; otherwise, it returns zero, indicating that the lock couldn’t be upgraded.

Learn more about java.util.concurrent.locks.StampedLock::tryConvertToWriteLock


49. What are some considerations when using java.util.concurrent.locks.StampedLock?

Answer:

  1. Optimistic Reading: It’s suitable for situations where reads are frequent and writes are infrequent.
  2. Lock Downgrading: Be cautious when downgrading a write lock to a read lock to avoid potential deadlocks.
  3. Non-reentrant: Unlike ReentrantReadWriteLock, StampedLock is not reentrant. Trying to acquire a read lock while holding another will result in a deadlock.

Careful use of StampedLock can lead to improved performance in scenarios with high contention for read access. However, incorrect usage can result in subtle bugs and deadlocks. Always thoroughly test and validate concurrency code.

Learn more about considerations for using java.util.concurrent.locks.StampedLock


50. How does the java.util.concurrent.locks.StampedLock::tryConvertToOptimisticRead method function?

Answer:
tryConvertToOptimisticRead attempts to convert a write lock to an optimistic read lock if the current thread holds a write lock and no other thread holds a conflicting lock.

Code Snippet:

long stamp = lock.writeLock();
if (lock.tryConvertToOptimisticRead(stamp) != 0) {
    // Successfully converted to optimistic read
    // Perform read operation
} else {
    // Handle lock contention
    lock.unlockWrite(stamp); // Release the write lock
}

Explanation:
If successful, the method returns a stamp for the optimistic read lock. Otherwise, it returns zero, indicating that the conversion couldn’t be performed.

Learn more about java.util.concurrent.locks.StampedLock::tryConvertToOptimisticRead


51. What are some potential pitfalls to be aware of when using java.util.concurrent.locks.StampedLock?

Answer:

  1. Potential for Write Starvation: In scenarios with frequent reads, write operations may be delayed.
  2. No Reentrancy: Unlike ReentrantReadWriteLock, StampedLock is not reentrant. Attempting to reacquire a lock you already hold will result in a deadlock.
  3. Lock Ordering: Be cautious when acquiring multiple locks in different orders to avoid potential deadlock situations.

It’s important to thoroughly understand the usage and behavior of StampedLock to avoid potential pitfalls in concurrent code.

Learn more about potential pitfalls when using java.util.concurrent.locks.StampedLock


52. How can you implement a ReadWrite lock pattern using java.util.concurrent.locks.StampedLock?

Answer:
To implement a ReadWrite lock pattern using StampedLock, you can use the following approach:

class CustomReadWriteLock {
    private final StampedLock lock = new StampedLock();

    public void acquireReadLock() {
        long stamp = lock.readLock();
        // Ensure stamp is valid before proceeding with the read operation
    }

    public void releaseReadLock(long stamp) {
        lock.unlockRead(stamp);
    }

    public void acquireWriteLock() {
        long stamp = lock.writeLock();
        // Ensure stamp is valid before proceeding with the write operation
    }

    public void releaseWriteLock(long stamp) {
        lock.unlockWrite(stamp);
    }
}

Explanation:
In this example, CustomReadWriteLock provides methods to acquire and release both read and write locks. It encapsulates the usage of StampedLock.

This pattern allows multiple threads to read simultaneously or a single thread to write exclusively.


53. When would you choose to use StampedLock over other locking mechanisms like ReentrantReadWriteLock?

Answer:
Use StampedLock when:

  1. Optimistic Reads are Advantageous: In scenarios where reads heavily outnumber writes, and optimistic reads can avoid blocking.
  2. Lock Downgrading is Necessary: If you need to upgrade a read lock to a write lock without releasing the lock entirely.
  3. Low Contention: In situations where lock contention is low, StampedLock can provide better performance due to its optimistic read feature.

Consider using ReentrantReadWriteLock in cases where strict ownership of the lock is required, or in scenarios with higher contention for write access.

Learn more about when to choose StampedLock over ReentrantReadWriteLock


56. How can you handle lock contention in java.util.concurrent.locks.StampedLock?

Answer:
In case of lock contention, you can employ strategies like:

  1. Retrying the Lock: Use a loop to retry acquiring the lock after a short delay.
  2. Fallback to Pessimistic Lock: If an optimistic read or conversion fails, fallback to acquiring a pessimistic lock.
  3. Implementing Timeout: Use tryXXX methods with timeouts to avoid indefinite waiting.

Each of these strategies addresses lock contention differently, allowing for smoother execution in concurrent scenarios.


57. What is the role of the java.util.concurrent.locks.StampedLock::asReadWriteLock method?

Answer:
asReadWriteLock returns a view of the StampedLock as an instance of java.util.concurrent.locks.ReadWriteLock.

Code Snippet:

ReadWriteLock rwLock = stampedLock.asReadWriteLock();

Explanation:
This method provides compatibility with existing code that expects a ReadWriteLock. The view allows for the use of familiar read and write lock interfaces.

Learn more about java.util.concurrent.locks.StampedLock::asReadWriteLock


58. What is the significance of the java.util.concurrent.locks.StampedLock::isWriteLocked method?

Answer:
isWriteLocked checks if the lock is currently held by a thread in write mode.

Code Snippet:

boolean isWriteLocked = lock.isWriteLocked();

Explanation:
This method is useful for determining if a write lock is currently held. It can be employed to make decisions based on the current lock state.

Learn more about java.util.concurrent.locks.StampedLock::isWriteLocked


59. How does the java.nio.file.Files::copy method work for copying files in Java?

Answer:
Files.copy is used to copy a file from a source to a target location. It handles both regular files and directories.

Code Snippet:

Path source = Paths.get("sourceFile.txt");
Path target = Paths.get("targetFile.txt");

try {
    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
    e.printStackTrace(); // Handle exception
}

Explanation:
This method requires the source Path and the target Path. The StandardCopyOption.REPLACE_EXISTING ensures that if the target file already exists, it will be replaced.

Learn more about java.nio.file.Files::copy


60. What is the purpose of java.nio.file.Path::resolve?

Answer:
resolve is used to combine two Path instances, creating a new Path that represents their concatenation.

Code Snippet:

Path base = Paths.get("baseDir");
Path child = Paths.get("subDir/file.txt");

Path result = base.resolve(child);

Explanation:
In this example, result will be a Path representing "baseDir/subDir/file.txt". It’s a handy method for building paths dynamically.

Learn more about java.nio.file.Path::resolve


61. How can you read a file line by line in Java?

Answer:
You can use a BufferedReader along with Files.newBufferedReader for efficient line-by-line reading.

Code Snippet:

Path filePath = Paths.get("file.txt");

try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) {
    String line;
    while ((line = reader.readLine()) != null) {
        // Process each line
    }
} catch (IOException e) {
    e.printStackTrace(); // Handle exception
}

Explanation:
This code snippet opens a BufferedReader for a file specified by its Path. It then reads the file line by line, processing each line within the loop.

Learn more about reading files in Java


62. What is the purpose of the java.util.regex.Pattern class in Java?

Answer:
Pattern is used to represent a compiled regular expression. It provides various methods for pattern matching and manipulation.

Code Snippet:

Pattern pattern = Pattern.compile("\\d{3}-\\d{2}-\\d{4}");
Matcher matcher = pattern.matcher("123-45-6789");

if (matcher.matches()) {
    // Pattern matched
} else {
    // Pattern didn't match
}

Explanation:
In this example, the pattern \\d{3}-\\d{2}-\\d{4} is a regular expression for a social security number. The matcher.matches() method checks if the provided string matches the pattern.

Learn more about java.util.regex.Pattern


63. How can you handle concurrent access to shared resources in Java?

Answer:
Java provides mechanisms like synchronized blocks and locks to ensure that only one thread accesses a shared resource at a time, preventing race conditions.

Code Snippet (Using synchronized block):

public class SharedResource {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
}

Explanation:
In this example, the synchronized keyword ensures that only one thread can execute the increment method at a time, preventing concurrent access issues.

Learn more about synchronization in Java


64. How can you create and start a new thread in Java?

Answer:
You can create a new thread by extending the Thread class or implementing the Runnable interface, and then calling the start method.

Code Snippet (Extending Thread class):

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

// Creating and starting the thread
MyThread thread = new MyThread();
thread.start();

Code Snippet (Implementing Runnable interface):

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

// Creating and starting the thread
Thread thread = new Thread(new MyRunnable());
thread.start();

Explanation:
Both examples create a new thread that prints a message when started.

Learn more about threads in Java


65. What is the purpose of the volatile keyword in Java?

Answer:
The volatile keyword is used to declare a variable as volatile, which ensures that any read or write operation on that variable is directly performed on the main memory rather than in the thread’s local cache.

Code Snippet:

public class SharedResource {
    private volatile int count = 0;

    public void increment() {
        count++;
    }
}

Explanation:
In this example, the volatile keyword is used to indicate that the count variable may be modified by multiple threads and should not be cached locally.

Learn more about volatile keyword


66. What is the purpose of the java.util.concurrent package?

Answer:
The java.util.concurrent package provides a set of high-level concurrency utilities that facilitate the execution of concurrent tasks and improve thread management.

Example:

ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(new MyRunnable());
executor.shutdown();

Explanation:
In this example, an ExecutorService is created to manage a pool of threads. It executes a Runnable task and then shuts down after completion.

Learn more about java.util.concurrent


67. How does garbage collection work in Java?

Answer:
Garbage collection in Java automatically reclaims memory that is no longer in use. It identifies and deletes objects that are no longer referenced by any part of the program.

Explanation:

  • When an object is created, it is allocated memory on the heap.
  • If the object is no longer reachable (i.e., no live thread holds a reference to it), it becomes eligible for garbage collection.
  • The garbage collector runs periodically, identifying and reclaiming memory occupied by unreachable objects.

Learn more about garbage collection in Java


68. What are the advantages of using an ArrayList over a regular array in Java?

Answer:
ArrayList provides dynamic resizing, making it more flexible than regular arrays. It allows for easy addition and removal of elements, making it suitable for situations where the size of the collection may change.

Code Snippet (Creating an ArrayList):

ArrayList<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");

Explanation:
In this example, we create an ArrayList of strings and add two names to it. The ArrayList can dynamically resize to accommodate more elements.

Learn more about ArrayList in Java


69. How does exception handling work in Java?

Answer:
In Java, exceptions are objects that represent errors or exceptional situations. When an exception occurs, it can be caught and handled using try-catch blocks.

Code Snippet (Exception Handling):

try {
    // Code that may throw an exception
    int result = 10 / 0;
} catch (ArithmeticException e) {
    // Handling the exception
    System.out.println("Error: " + e.getMessage());
}

Explanation:
In this example, the code attempts to divide by zero, which throws an ArithmeticException. It is caught in the catch block, allowing for graceful handling of the error.

Learn more about exception handling in Java


70. What is the purpose of the final keyword in Java?

Answer:
The final keyword is used to restrict certain actions on classes, methods, and variables.

  • For variables, it makes them constants that cannot be reassigned.
  • For methods, it prevents them from being overridden by subclasses.
  • For classes, it prevents them from being subclassed.

Code Snippet (Final Variable):

final int MAX_SIZE = 100;

Explanation:
In this example, MAX_SIZE is declared as a constant and cannot be changed after initialization.

Learn more about the final keyword


71. What is the difference between String, StringBuilder, and StringBuffer in Java?

Answer:

  • String is immutable, meaning its value cannot be changed after it’s created. Each modification creates a new String object.
  • StringBuilder and StringBuffer are mutable and can be modified in place. They are more efficient for frequent string manipulations.
  • StringBuilder is not thread-safe, while StringBuffer is, making it suitable for multithreaded environments.

Code Snippet (Using StringBuilder):

StringBuilder str = new StringBuilder("Hello");
str.append(" World");

Explanation:
In this example, str is a StringBuilder object. The append method modifies the existing object, resulting in “Hello World”.

Learn more about String vs StringBuilder vs StringBuffer


72. How does method overloading work in Java?

Answer:
Method overloading allows a class to have multiple methods with the same name but different parameters. The compiler determines which method to call based on the number or type of arguments.

Code Snippet (Method Overloading):

int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

Explanation:
In this example, there are two add methods with different parameter types (int and double).

Learn more about method overloading


73. Explain the concept of inheritance in Java.

Answer:
Inheritance allows one class (subclass) to inherit the fields and methods of another class (superclass). This promotes code reusability and allows for the creation of specialized classes.

Code Snippet (Inheritance):

class Animal {
    void sound() {
        System.out.println("Some generic sound");
    }
}

class Dog extends Animal {
    void sound() {
        System.out.println("Bark");
    }
}

Explanation:
In this example, Dog is a subclass of Animal and inherits the sound method. It provides its own implementation.

Learn more about inheritance in Java


74. What is the purpose of the super keyword in Java?

Answer:
The super keyword is used to refer to the superclass of a subclass. It can be used to access superclass variables, methods, and constructors.

Code Snippet (Using super):

class Animal {
    String type = "Generic Animal";
}

class Dog extends Animal {
    String type = "Canine";
    void display() {
        System.out.println(super.type); // Refers to type in Animal
    }
}

Explanation:
In this example, super.type refers to the type variable in the superclass Animal.

Learn more about the super keyword


75. What is the purpose of an interface in Java?

Answer:
An interface is a contract that defines a set of methods without implementation. Classes that implement an interface must provide implementations for all the defined methods.

Code Snippet (Interface):

interface Shape {
    double area(); // Method without implementation
}

Explanation:
In this example, Shape is an interface with a method area. Any class implementing Shape must provide an implementation for area.

Learn more about interfaces in Java


76. What is the difference between an abstract class and an interface in Java?

Answer:

  • An abstract class can have both abstract and non-abstract methods, while an interface can only have abstract methods.
  • A class can extend only one abstract class, but it can implement multiple interfaces.
  • Abstract classes can have instance variables, constructors, and non-abstract methods with implementations, while interfaces cannot.

Code Snippet (Abstract Class vs Interface):

abstract class Shape {
    abstract double area(); // Abstract method
    double perimeter() {
        return 0; // Non-abstract method with implementation
    }
}

interface Drawable {
    void draw(); // Abstract method
}

Explanation:
In this example, Shape is an abstract class with both abstract and non-abstract methods. Drawable is an interface with an abstract method draw.

Learn more about abstract classes and interfaces


77. What is the use of the final keyword in Java?

Answer:
The final keyword can be applied to classes, methods, and variables.

  • A final class cannot be subclassed.
  • A final method cannot be overridden by subclasses.
  • A final variable cannot be reassigned after initialization.

Code Snippet (Using final):

final class FinalClass { // Cannot be subclassed
    final int VALUE = 10; // Cannot be reassigned
    final void display() { // Cannot be overridden
        System.out.println("Final method");
    }
}

Explanation:
In this example, FinalClass is a final class with a final variable VALUE and a final method display.

Learn more about the final keyword


78. What is a static method in Java?

Answer:
A static method belongs to the class rather than an instance of the class. It can be called using the class name and is shared among all instances of the class.

Code Snippet (Static Method):

class MathOperations {
    static int add(int a, int b) {
        return a + b;
    }
}

Explanation:
In this example, add is a static method of the class MathOperations and can be called using MathOperations.add(5, 3).

Learn more about static methods


79. What is a singleton pattern in Java?

Answer:
The singleton pattern ensures that a class has only one instance and provides a global point of access to that instance.

Code Snippet (Singleton Pattern):

class Singleton {
    private static Singleton instance;

    private Singleton() {} // Private constructor

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Explanation:
In this example, the Singleton class has a private constructor and a static method getInstance that returns the singleton instance.

Learn more about singleton pattern


80. How does exception handling work in Java?

Answer:
Exception handling in Java allows us to deal with unexpected events or errors that occur during program execution. It involves the use of try, catch, and finally blocks.

Code Snippet (Exception Handling):

try {
    // Code that may throw an exception
} catch (ExceptionType e) {
    // Code to handle the exception
} finally {
    // Code that executes regardless of an exception
}

Explanation:
In this example, the code in the try block is monitored for exceptions. If an exception occurs, it is caught by the corresponding catch block. The finally block contains code that always executes, whether or not an exception occurred.

Learn more about exception handling in Java


81. What is polymorphism in Java?

Answer:
Polymorphism is the ability of a class to take on multiple forms. In Java, it is achieved through method overloading and method overriding.

Code Snippet (Polymorphism):

class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

Explanation:
In this example, Shape is a base class with a draw method. Circle is a subclass that overrides the draw method to provide a specific implementation.

Learn more about polymorphism


82. What is the difference between ArrayList and LinkedList in Java?

Answer:

  • ArrayList is implemented as a dynamic array, allowing fast random access but slower insertion and deletion operations.
  • LinkedList is implemented as a doubly linked list, allowing fast insertion and deletion but slower random access.

Code Snippet (ArrayList vs LinkedList):

ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();

Explanation:
In this example, arrayList is an instance of ArrayList, while linkedList is an instance of LinkedList. The choice between them depends on the specific requirements of the application.

Learn more about ArrayList | Learn more about LinkedList


83. How does multithreading work in Java?

Answer:
Multithreading allows a program to perform multiple tasks concurrently. It involves creating multiple threads of execution that share the same memory space.

Code Snippet (Multithreading):

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

Explanation:
In this example, a class MyThread extends Thread and overrides the run method to define the behavior of the thread.

Learn more about multithreading in Java


84. How can you achieve synchronization in Java?

Answer:
Synchronization in Java is achieved using the synchronized keyword. It ensures that only one thread can access a synchronized block or method at a time.

Code Snippet (Synchronization):

class Counter {
    private int count = 0;

    synchronized void increment() {
        count++;
    }
}

Explanation:
In this example, the increment method is synchronized, so only one thread can execute it at a time, preventing concurrent access issues.

Learn more about synchronization in Java


85. What are the advantages of using Java for enterprise-level applications?

Answer:

  1. Platform Independence: Java code can run on any device that has the Java Virtual Machine (JVM) installed, making it highly portable.
  2. Strong Standard Library: Java has a vast standard library that provides pre-built functionality for common tasks, reducing development time.
  3. Robustness and Reliability: Java’s strong type system, exception handling, and memory management contribute to robust and reliable code.
  4. Security: Java applications run inside a secured environment provided by the JVM, which protects against many common security threats.
  5. Multi-threading Support: Java provides built-in support for multithreading, enabling the development of concurrent, high-performance applications.
  6. Scalability: Java applications can easily be scaled to handle increased workloads by distributing them across multiple servers.
  7. Enterprise-level Tools: Java has a rich ecosystem of tools and frameworks for building, testing, and deploying enterprise applications.
  8. Community and Support: Java has a large and active developer community, which means a wealth of resources and support is available.
  9. Compatibility and Longevity: Java applications written in older versions can still run on newer JVMs, ensuring backward compatibility.

Learn more about Java for enterprise applications


86. What is the purpose of the transient keyword in Java?

Answer:
The transient keyword is used to indicate that a variable should not be serialized during object serialization. This means the value of the variable will not be persisted when the object is written to a file or sent over a network.

Code Snippet (transient variable):

class MyClass implements Serializable {
    transient int sensitiveData; // This variable will not be serialized
}

Explanation:
In this example, sensitiveData is marked as transient, so it won’t be included in the serialized form of MyClass.

Learn more about serialization in Java


87. How does garbage collection work in Java?

Answer:
Garbage collection in Java automatically deallocates memory that is no longer reachable by the program. It identifies and removes objects that are no longer in use.

Code Snippet (Garbage Collection):

Object obj = new Object(); // Create an object
obj = null; // Set reference to null

Explanation:
In this example, once obj is set to null, the object it was referencing becomes eligible for garbage collection.

Learn more about garbage collection in Java


88. What is the use of the this keyword in Java?

Answer:
The this keyword in Java is a reference to the current instance of a class. It is often used to differentiate between instance variables and method parameters with the same name.

Code Snippet (Using this):

class Person {
    String name;

    void setName(String name) {
        this.name = name; // Assign value to instance variable
    }
}

Explanation:
In this example, this.name refers to the instance variable name, while name refers to the method parameter.

Learn more about the this keyword in Java


89. Explain the concept of method overloading in Java.

Answer:
Method overloading is the ability to define multiple methods in a class with the same name but different parameter lists. The methods must have different types or numbers of parameters. Java determines which overloaded method to call based on the arguments provided during the method invocation.

Code Snippet (Method Overloading):

class Calculator {
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }
}

Explanation:
In this example, there are two add methods in the Calculator class. One accepts two integers, and the other accepts two doubles. Java will determine which method to call based on the argument types.

Learn more about method overloading in Java


90. What is the purpose of the static keyword in Java?

Answer:
The static keyword in Java is used to create variables or methods that belong to the class rather than to any specific instance. A static variable is shared among all instances of a class, while a static method can be called without an instance of the class.

Code Snippet (Static Variable and Method):

class Counter {
    static int count = 0; // Static variable

    static void increment() { // Static method
        count++;
    }
}

Explanation:
In this example, count is a static variable shared among all instances of the Counter class. The increment method is also static and can be called without creating an instance of Counter.

Learn more about static members in Java


91. What is a constructor in Java?

Answer:
A constructor in Java is a special method that is used to initialize an object of a class. It has the same name as the class and is automatically called when an object of the class is created using the new keyword.

Code Snippet (Constructor):

class Person {
    String name;

    Person(String n) { // Constructor
        name = n;
    }
}

Explanation:
In this example, Person is a class with a constructor that takes a String parameter n and assigns it to the name variable.

Learn more about constructors in Java


92. What is the difference between == and .equals() in Java?

Answer:
The == operator in Java is used to compare the memory addresses of two objects, checking if they refer to the same instance.

The .equals() method is used to compare the contents or values of two objects to determine if they are considered equal based on their internal state.

Code Snippet (Using == and .equals()):

String str1 = "Hello";
String str2 = "Hello";
boolean isEqual = (str1 == str2); // true (same memory address)
boolean contentEqual = str1.equals(str2); // true (same content)

Explanation:
In this example, str1 and str2 have the same content, so equals() returns true. The == operator also returns true because string literals are interned in Java.

Learn more about == and .equals() in Java


93. How does exception handling work in Java?

Answer:
Exception handling in Java is done using try, catch, and finally blocks. Code that might throw an exception is placed inside a try block. If an exception occurs, it is caught by an appropriate catch block.

Code Snippet (Exception Handling):

try {
    // Code that might throw an exception
    int result = 10 / 0; // This will throw an ArithmeticException
} catch (ArithmeticException e) {
    // Code to handle the exception
    System.out.println("An arithmetic error occurred.");
} finally {
    // Code that always executes, regardless of whether an exception occurred
    System.out.println("Execution completed.");
}

Explanation:
In this example, an ArithmeticException is caught by the catch block and an error message is printed. The finally block is always executed.

Learn more about exception handling in Java


94. What are abstract classes and interfaces in Java?

Answer:
An abstract class is a class that cannot be instantiated and is typically used as a base for other classes to inherit from. It may contain abstract methods that must be implemented by its subclasses.

An interface is a contract that defines a set of methods that a class implementing the interface must provide. It is similar to an abstract class but can be implemented by multiple classes.

Code Snippet (Abstract Class and Interface):

abstract class Shape {
    int sides;
    abstract void calculateArea(); // Abstract method
}

interface Drawable {
    void draw(); // Method in an interface
}

Explanation:
In this example, Shape is an abstract class with an abstract method calculateArea(). Drawable is an interface with a method draw().

Learn more about abstract classes and interfaces in Java


95. What is the purpose of the super keyword in Java?

Answer:
The super keyword in Java is used to refer to the immediate parent class of a subclass. It is often used to access or call methods, variables, or constructors of the parent class.

Code Snippet (Using super):

class Parent {
    int num = 10;
    void display() {
        System.out.println("Parent class");
    }
}

class Child extends Parent {
    int num = 20;
    void display() {
        System.out.println(super.num); // Access parent class variable
        super.display(); // Call parent class method
    }
}

Explanation:
In this example, super.num refers to the num variable in the parent class. super.display() calls the display() method of the parent class.

Learn more about the super keyword in Java


96. What is the use of the this keyword in Java?

Answer:
The this keyword in Java is a reference to the current instance of the class. It can be used to refer to instance variables and methods of the current object. It is often used to disambiguate between instance variables and parameters with the same name.

Code Snippet (Using this):

class Person {
    String name;

    Person(String name) {
        this.name = name; // Using this to refer to the instance variable
    }

    void displayName() {
        System.out.println(this.name); // Using this to refer to the instance variable
    }
}

Explanation:
In this example, this.name refers to the name variable of the current instance. It is used to distinguish between the parameter name and the instance variable name.

Learn more about the this keyword in Java


97. What is a package in Java?

Answer:
A package in Java is a way to organize related classes, interfaces, and sub-packages. It helps in avoiding naming conflicts and provides a hierarchical structure to the code. Packages are specified at the beginning of a Java file.

Code Snippet (Using a Package):

package com.example.myapp; // Package declaration

public class MyClass {
    // Class code
}

Explanation:
In this example, com.example.myapp is a package. The class MyClass belongs to this package.

Learn more about packages in Java


98. What are access modifiers in Java?

Answer:
Access modifiers in Java are keywords that define the accessibility or visibility of classes, methods, and variables. There are four types of access modifiers: public, protected, default (package-private), and private.

  • public: Accessible from any class.
  • protected: Accessible within the same package or subclasses.
  • default (package-private): Accessible within the same package.
  • private: Accessible only within the same class.

Code Snippet (Using Access Modifiers):

public class MyClass { // Public class
    private int num; // Private variable

    protected void myMethod() { // Protected method
        // Code here
    }

    void anotherMethod() { // Default (package-private) method
        // Code here
    }
}

Explanation:
In this example, num is a private variable, myMethod() is a protected method, and anotherMethod() has default (package-private) visibility.

Learn more about access modifiers in Java


99. What is method overriding in Java?

Answer:
Method overriding in Java occurs when a subclass provides a specific implementation for a method that is already defined in its parent class. The method in the subclass must have the same name, return type, and parameter list as the method in the parent class.

Code Snippet (Method Overriding):

class Animal {
    void makeSound() {
        System.out.println("Generic Animal Sound");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Meow");
    }
}

Explanation:
In this example, Cat overrides the makeSound() method defined in Animal.

Learn more about method overriding in Java


100. What is the purpose of the final keyword in Java?

Answer:
In Java, the final keyword is used to restrict the modification of classes, methods, and variables.

  • When applied to a class, it prevents the class from being subclassed.
  • When applied to a method, it prevents the method from being overridden in subclasses.
  • When applied to a variable, it makes the variable a constant that cannot be reassigned.

Code Snippet (Using final):

final class FinalClass { // Final class
    final int MAX_VALUE = 100; // Final variable

    final void myMethod() { // Final method
        // Code here
    }
}

Explanation:
In this example, FinalClass is a final class, MAX_VALUE is a final variable, and myMethod() is a final method.

Learn more about the final keyword in Java