1. Why is there a need for multi-threading?
Multi-threading allows your program to execute logic in parallel. For example: if you are tasked to develop an API endpoint to download a file, read from the database, run calculations, call another API, then this will be an expensive task in terms of resources and time.
As you can see, it will take 5+ seconds with the best-case scenario. This isn’t too bad but still, users expect a faster response than 5+ seconds. If we use multi-threading to execute these steps in parallel then we can decrease the response time significantly.
Now instead of 5+ seconds, our new response time is 3 seconds.
2. What is multi-threading?
Multi-threading is executing a series of logic in parallel. Example: a web server is using multi-threading to execute multiple requests from clients(web browsers or mobile apps) at the same time.
3. What is a thread?
A thread is an independent path of execution within a program. Many threads can run concurrently within a program, either asynchronously or synchronously.
4. What are the differences between a thread and a process?
Threads share memory among themselves. A process does not share memory.
Threads are lightweight compared to processes.
Context switching between threads is usually less expensive than between processes.
The cost of thread intercommunication is relatively low compared to that of process intercommunication.
Threads allow different tasks to be performed concurrently.
5. How can you create a thread?
There are two ways you can create a thread. You can extend the Thread class or implement the Runnable interface. Implementing the Runnable interface is preferred by many because it allows you to implement other interfaces or extend another class.
Using the Thread class
public class MemberThread extends Thread { @Override public void run() { super.run(); // coding to execute System.out.println("run MemberThread..."); } }
Using the Runnable interface
public class UserRunnable implements Runnable { public UserRunnable() { super(); System.out.println("UserRunnable"); } @Override public void run() { // code to execute System.out.println("running UserRunnable.."); } }
public class ThreadCreationDemo { public static void main(String[] args) { Thread userThread = new Thread(new UserRunnable()); userThread.start(); MemberThread memberThread = new MemberThread(); memberThread.start(); } }
Result
UserRunnable running UserRunnable.. start MemberThread... run MemberThread...
6. What are the different statuses of a thread?
a. NEW – a new Thread instance that was not yet started via Thread.start().
b. RUNNABLE – a running thread. It is called runnable because at any given time it could be either running or waiting for the next quantum of time from the thread scheduler. A NEW thread enters the RUNNABLE state when you call Thread.start() on it.
c. RUNNING – In this state, the thread scheduler picks the thread from the ready state, and the thread is running.
c. BLOCKED – a running thread becomes blocked if it needs to enter a synchronized section but cannot do that due to another thread holding the monitor of this section.
d. WAITING – a thread enters this state if it waits for another thread to perform a particular action. For instance, a thread enters this state upon calling the Object.wait() method on a monitor it holds, or the Thread.join() method on another thread.
e. TIMED_WAITING – same as the above, but a thread enters this state after calling timed versions of Thread.sleep(), Object.wait(), Thread.join() and some other methods.
f. TERMINATED – a thread has completed the execution of its Runnable.run() method and terminated.
The state of a Thread can be checked using the Thread.getState() method.
7. What is the difference between the Runnable interface and the Callable interface?
The Runnable interface does not have a return value or to throw unchecked exceptions.
The Callable interface has a return value. It can also throw exceptions. Callable is generally used in ExecutorService instances to start an asynchronous task and then call the returned Future instance to get its value.
FutureTask<Integer> futureTask = new FutureTask<Integer>(new CustomerCallable()); Thread customerCallableStart = new Thread(futureTask); customerCallableStart.start(); try { int result = futureTask.get(); System.out.println("result: " + result); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); }
8. What is context-switching?
In Context switching, the state of the thread or process is stored so that it can be restored and execution can be resumed from the same point later. Context switching enables multiple threads or processes to share the same CPU.
9. What is the difference between preemptive scheduling and time slicing?
Under preemptive scheduling, the highest priority task executes until it enters the waiting or dead states or a higher priority task comes into existence.
Under time slicing, a task executes for a predefined slice of time and then reenters the pool of ready tasks. The scheduler then determines which task should execute next, based on priority and other factors.
10. What is the difference between the start() method and the run() method?
The start() method is used to start a newly created thread, while start() internally calls run() method.
When you invoke run() directly, the execution will run on the main thread. It won’t create a new thread for you.
11. What is the difference between user threads and daemon threads?
When we create a Thread in java program, it’s known as user thread. A daemon thread runs in the background and doesn’t prevent JVM from terminating. When there are no user threads running, JVM shutdown the program and quits. A child thread created from daemon thread is also a daemon thread.
12. How can we pause the execution of a Thread for a specific time?
We can use the Thread class sleep() method to pause the execution of a thread for a duration of time. Note that this will not stop the processing of the thread, once the thread is awake from sleep, it states gets changed to runnable and based on thread scheduling, it gets executed.
13. What do you understand about Thread Priority?
Every thread has a priority, usually higher priority thread gets precedence in execution but it depends on Thread Scheduler implementation that is OS-dependent. We can specify the priority of thread but it doesn’t guarantee that higher priority thread will get executed before lower priority thread. Thread priority is an int whose value varies from 1 to 10 where 1 is the lowest priority thread and 10 is the highest priority thread.
14. How can we make sure that the main thread is the last thread to finish in Java Program?
We can use Thread join() method to make sure all the threads created by the program is dead before finishing the main function
15. How does thread communicate with each other?
When threads share resources, communication between Threads is important to coordinate their efforts. Object class wait(), notify() and notifyAll() methods allow threads to communicate about the lock status of a resource.
16. What is the difference between wait() and sleep() method?
The wait() method releases the lock but the sleep() method doesn’t.
The wait() method is defined in Object class but the sleep() method is from the Thread class.
17. Is it possible to start a thread twice?
No, we cannot restart the thread, as once a thread started and executed, it goes to the Dead state. Therefore, if we try to start a thread twice, it will give a runtime Exception “java.lang.IllegalThreadStateException”.
18. What are daemon threads?
Daemon threads are low priority threads that provide the background support and services to the user threads. Daemon thread gets automatically terminated by the JVM if the program remains with the daemon thread only, and all other user threads are ended/died. We can make a user thread a daemon thread by calling the setDaemon() method. We can only do this before the thread is starting otherwise it will throw an exception. There are two methods for daemon thread available in the Thread class.
19. Why Thread sleep() and yield() methods are static?
Thread sleep() and yield() methods work on the currently executing thread. So there is no point in invoking these methods on some other threads that are in a wait state. That’s why these methods are made static so that when this method is called statically, it works on the currently executing thread and avoid confusion to the programmers who might think that they can invoke these methods on some non-running threads.
20. How can we achieve thread-safety in Java?
There are several ways to achieve thread-safety in java – synchronization, atomic concurrent classes, implementing concurrent Lock interface, using the volatile keyword, using immutable classes and Thread-safe classes.
21. What is the volatile keyword in Java
It is used to mark a variable as “being stored in main memory”. More precisely that means, that every read of a volatile variable will be read from the computer’s main memory, and not from the CPU cache and that every a write happens to a volatile variable will be written to main memory, and not just to the CPU cache.
A change in a volatile variable is visible to all other threads so one variable can be used by one thread at a time.
In a multithreaded application where the threads operate on non-volatile variables, each thread may copy variables from main memory into a CPU cache while working on them, for performance reasons. If your computer contains more than one CPU, each thread may run on a different CPU. That means, that each thread may copy the variables into the CPU cache of different CPUs.
With non-volatile variables, there are no guarantees about when the Java Virtual Machine (JVM) reads data from the main memory into CPU caches or writes data from CPU caches to the main memory. This can cause problems.
Using volatile is sometimes not enough. It is recommended to use synchronized to guarantee that the reading and writing of the variable are atomic.
22. Which way is more preferred – Synchronized method or Synchronized block?
The synchronized block is the more preferred way because it doesn’t lock the Object, synchronized methods lock the Object and if there are multiple synchronization blocks in the class, even though they are not related, it will stop them from execution and put them in wait state to get the lock on Object.
23. Can you synchronize a static method?
Yes, if you do you will be synchronizing the class so only one thread can enter into a synchronized static method.
24. What is Threadlocal?
The Threadlocal class enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to the same Threadlocal variable, the two threads cannot see each other’s Threadlocal variables.
If we want to use an ExecutorService and submit a Runnable to it, using ThreadLocal will yield non-deterministic results – because we do not have a guarantee that every Runnable action for a given userId will be handled by the same thread every time it is executed.
Use it when you have some object that is not thread-safe, but you want to avoid synchronizing access to that object.
public class UserThreadLocal extends Thread { private static final AtomicInteger id = new AtomicInteger(0); ThreadLocal<String> privateName = ThreadLocal.withInitial(() -> " John--" + id.incrementAndGet()); @Override public void run() { super.run(); System.out.println("run..." + privateName.get()); } }
25. What is Java Thread Dump, How can we get Java Thread dump of a Program?
A thread dump is a list of all the threads active in the JVM, thread dumps are very helpful in analyzing bottlenecks in the application and analyzing deadlock situations. There are many ways using which we can generate Thread dump – Using Profiler, Kill -3 command, jstack tool, etc. I prefer jstack tool to generate thread dump of a program because it’s easy to use and comes with JDK installation. Since it’s a terminal-based tool, we can create a script to generate thread dump at regular intervals to analyze it later on.
26. 30 commonly asked interview questions related to Java concurrency
Question: What is concurrency in Java? Answer: Concurrency is the ability of a program to execute multiple tasks concurrently. It allows for efficient utilization of system resources and improved program performance.
Question: What is a thread in Java? Answer: A thread is a lightweight unit of execution within a program. It allows multiple parts of a program to execute concurrently.
Question: How can you create a thread in Java? Answer: There are two ways to create a thread in Java: by extending the Thread
class or by implementing the Runnable
interface.
Question: What is the difference between the start()
and run()
methods of a thread? Answer: The start()
method is used to start a new thread and internally calls the run()
method, which contains the code that will be executed by the thread.
Question: What is thread synchronization? Answer: Thread synchronization is the coordination of multiple threads to ensure their safe and orderly execution. It is used to prevent race conditions and ensure data consistency.
Question: How can you synchronize a block of code in Java? Answer: You can use the synchronized
keyword to synchronize a block of code by enclosing it within a synchronized block or by declaring a synchronized method.
Question: What is the purpose of the volatile
keyword in Java? Answer: The volatile
keyword is used to declare a variable whose value may be modified by multiple threads. It ensures that changes to the variable are immediately visible to other threads.
Question: What is a race condition? Answer: A race condition occurs when multiple threads access and modify shared data concurrently, leading to unpredictable results. It can be resolved using synchronization mechanisms.
Question: What are the differences between wait()
and sleep()
methods in Java? Answer: The wait()
method is used for inter-thread communication, allowing a thread to wait until another thread notifies it. The sleep()
method is used to pause the execution of a thread for a specified amount of time.
Question: What is a deadlock? Answer: A deadlock occurs when two or more threads are blocked forever, each waiting for a resource that the other thread holds. Deadlocks can be avoided by careful resource allocation and proper synchronization.
Question: Explain the concept of thread pooling. Answer: Thread pooling involves creating a pool of reusable threads to execute tasks. It reduces the overhead of creating and destroying threads for each task, resulting in improved performance.
Question: What is the Executor
framework in Java? Answer: The Executor
framework provides a higher-level abstraction for managing and executing threads. It decouples task submission from execution policies.
Question: What is the purpose of the Callable
interface in Java? Answer: The Callable
interface is similar to the Runnable
interface, but it can return a result and throw checked exceptions. It is used with the ExecutorService
to execute tasks and retrieve results.
Question: What is the Java Memory Model (JMM)? Answer: The Java Memory Model defines the rules and guarantees for the interaction of threads and memory. It ensures visibility and ordering of memory operations across multiple threads.
Question: Explain the concept of atomic operations in Java. Answer: Atomic operations are indivisible operations that are performed as a single unit of execution. They ensure that operations on shared data are thread-safe and free from race conditions.
Question: What is a semaphore in Java concurrency? Answer: A semaphore is a synchronization primitive that controls access to a shared resource. It allows aContinuing from the previous response, here are more Java concurrency interview questions along with their answers:
Question: What is the purpose of the CountDownLatch
class in Java? Answer: The CountDownLatch
class is used to synchronize threads by allowing them to wait until a certain number of operations or events have occurred before proceeding.
Question: What is the purpose of the CyclicBarrier
class in Java? Answer: The CyclicBarrier
class is used to synchronize multiple threads by making them wait at a barrier until all threads have reached it. Once all threads have arrived, they can proceed simultaneously.
Question: What is the purpose of the ReentrantLock
class in Java? Answer: The ReentrantLock
class provides a more advanced locking mechanism than the synchronized
keyword. It allows for finer-grained control over locking and supports features like fairness and interruptible locks.
Question: What is the purpose of the ReadWriteLock
interface in Java? Answer: The ReadWriteLock
interface provides a way to have multiple threads simultaneously read from a shared resource, while only allowing one thread to write to it at a time. It improves concurrency in scenarios with frequent reads and infrequent writes.
Question: What is the purpose of the BlockingQueue
interface in Java? Answer: The BlockingQueue
interface provides a thread-safe queue implementation that supports blocking operations, such as waiting for elements to become available or waiting for space to become available for adding elements.
Question: What is the purpose of the ThreadLocal
class in Java? Answer: The ThreadLocal
class provides a way to create thread-local variables, where each thread has its own copy of the variable. It is useful for maintaining thread-specific data.
Question: What is the purpose of the volatile
keyword in relation to multi-threading? Answer: The volatile
keyword ensures that a variable’s value is always read from and written to main memory, rather than being cached in a thread’s local cache. It guarantees visibility of the variable’s latest value across multiple threads.
Question: What is the purpose of the join()
method in Java? Answer: The join()
method is used to make a calling thread wait until a target thread completes its execution. It is often used to ensure that the main thread waits for all worker threads to finish before proceeding.
Question: What is the purpose of the notify()
and notifyAll()
methods in Java? Answer: The notify()
method is used to wake up a single thread that is waiting on the same object’s monitor, while the notifyAll()
method wakes up all threads waiting on the object’s monitor. These methods are used for inter-thread communication.
Question: Explain the concept of thread starvation and how it can be avoided. Answer: Thread starvation occurs when a thread is perpetually denied access to the CPU or resources it needs. It can be avoided by implementing proper thread scheduling, fairness policies, and resource management.
Question: Explain the concept of thread starvation and how it can be avoided. Answer: Thread starvation occurs when a thread is perpetually denied access to the CPU or resources it needs. It can be avoided by implementing proper thread scheduling, fairness policies, and resource management.
Question: What is the purpose of the ForkJoinPool
class in Java? Answer: The ForkJoinPool
class is used for parallelizing tasks that can be divided into subtasks and executed concurrently. It is based on the divide-and-conContinuing from the previous response, here are more Java concurrency interview questions along with their answers:
Question: What is the purpose of the CompletableFuture
class in Java? Answer: The CompletableFuture
class provides a way to handle asynchronous computations and compose them in a non-blocking manner. It allows for chaining and combining asynchronous operations.
Question: Explain the concept of non-blocking and asynchronous programming in Java. Answer: Non-blocking and asynchronous programming techniques allow for concurrent execution of tasks without blocking the calling thread. Non-blocking operations return immediately, and the result is delivered at a later time, often through callbacks or promises.
1.What is Object-oriented Programming?
Object-oriented programming is a programming model or approach where the programs you create are organized around objects rather than logic and functions. The states and behaviors of an object are represented as member variables and methods. This approach is ideal for the programs that are large and complex and need to be actively updated or maintained. Here below is an example of OOP where this little piece is focused on Person. There can be other entities like payment method, Account, etc. Programs are organized into entities.
2. What are the advantages of OOPs?
Simplicity: Domain models or entities are modeled after real-world objects. It is easier to understand and to relate to. The program structure is also easier to comprehend.
Modularity: Each object is decoupled from other objects of the system.
Modifiability: It is easy to make minor changes in the data or the functionalities in an OO program. Changes inside a class do not affect any other part of a program since the only public interface that the external world has to a class is through the use of methods.
Extensibility: Adding new features or responding to changing operating environments can be solved by introducing a few new objects and modifying some existing ones.
Maintainability: Objects can be maintained separately, making locating and fixing problems easier.
Reusability: Objects can be reused in different programs.
3. What is the difference between procedural programming and OOPs?
4. What are the core concepts of OOPs?
Classes and Objects:
Encapsulation:
Inheritance:
Polymorphism:
Abstraction:
5. What is the difference between Abstraction and Encapsulation?
Abstraction:
Encapsulation:
Abstraction focuses on representing complex entities as simplified models, while encapsulation focuses on bundling data and methods within a class, controlling access to the data, and hiding the implementation details. Abstraction provides a higher-level view, emphasizing what an object does, while encapsulation provides information hiding and modular code organization. Both concepts are crucial for building robust and maintainable object-oriented programs.
6. What is the diamond problem in inheritance?
In the case of multiple inheritances, suppose class A has two subclasses B and C, and class D has two superclasses B and C. If a method present in A is overridden by both B and C but not by D then from which class D will inherit that method B or C? This problem is known as the diamond problem.
7. Why Java does not support multiple inheritances?
Java was designed to be a simple language and multiple inheritances introduce complexities like the diamond problem. Inheriting states or behaviors from two different types of classes is a case which in reality very rare and it can be achieved easily through an object association.
8. What is Static Binding and Dynamic Binding?
Static or early binding is resolved at compile time. Method overloading is an example of static binding. Static binding is faster than dynamic binding.
Dynamic or late or virtual binding is resolved at run time. Method overriding is an example of dynamic binding. This decision making during runtime makes Dynamic binding slower than static binding.
9. What is the meaning of the “IS-A” and “HAS-A” relationship?
“IS-A” relationship implies inheritance. A subclass object is said to have an “IS-A” relationship with the superclass or interface. If class A extends B then A “IS-A” B. It is transitive, that is, if class A extends B and class B extends C then A “IS-A” C. The “instance of” operator in java determines the “IS-A” relationship.
When a class A has a member reference variable of type B then A “HAS-A” B. It is also known as Aggregation.
10. What is an Association?
Association is a relationship between two objects with multiplicity.
11. What is Aggregation?
Aggregation is also known as “HAS-A” relationship. When class Car has a member reference variable of type Wheel then the relationship between the classes Car and Wheel is known as Aggregation. Aggregation can be understood as “whole to its parts” relationship.
Car is the whole and wheel is part. The wheel can exist without the Car. Aggregation is a weak association.
12. What is Composition?
Composition is a special form of Aggregation where the part cannot exist without the whole. Composition is a strong Association. Composition relationship is represented like aggregation with one difference that the diamond shape is filled.
13. What is Dependency?
When one class depends on another because it uses that class at some point in time then this relationship is known as Dependency. One class depends on another if the independent class is a parameter variable or local variable of a method of the dependent class. A Dependency is drawn as a dotted line from the dependent class to the independent class with an open arrowhead pointing to the independent class.
14. What is the difference between Association and Dependency?
The main difference between Association and Dependency is in case of Association one class has an attribute or member variable of the other class type but in case of Dependency a method takes an argument of the other class type or a method has a local variable of the other class type.
15. 30 commonly asked interview questions related to Object-Oriented Programming (OOP) in Java
Question: What is the difference between a class and an object in Java? Answer: A class is a blueprint or template that defines the structure and behavior of objects, while an object is an instance of a class. A class represents a general concept, while an object represents a specific instance of that concept.
Question: Explain the concept of inheritance in Java. Answer: Inheritance allows a class to inherit the properties (fields and methods) of another class, known as the superclass or parent class. It promotes code reuse and allows for the creation of specialized classes from a general superclass. Example: A Car
class can inherit common properties and methods from a Vehicle
class.
Question: What is the difference between method overloading and method overriding? Answer: Method overloading is the process of defining multiple methods with the same name but different parameters within the same class. Method overriding, on the other hand, occurs when a subclass provides a different implementation of a method that is already defined in its superclass.
Question: What is the purpose of the super
keyword in Java? Answer: The super
keyword is used to refer to the immediate parent class’s members (fields and methods) from within a subclass. It is often used to call the superclass’s constructor or to access overridden methods or hidden fields.
Question: What is the concept of polymorphism in Java? Answer: Polymorphism allows objects of different classes to be treated as objects of a common superclass, enabling them to respond to the same method invocation in different ways. Polymorphism is achieved through method overriding (runtime polymorphism) and method overloading (compile-time polymorphism).
Question: Explain the concept of encapsulation in Java. Answer: Encapsulation is the process of bundling data (attributes/fields) and methods that operate on the data within a single unit, i.e., a class. It provides data hiding, where the internal implementation details of a class are hidden from the outside world, and access to the data is controlled through methods.
Question: What is an abstract class in Java? How is it different from an interface? Answer: An abstract class is a class that cannot be instantiated but can be used as a base class for subclasses. It can have both abstract methods (without implementation) and concrete methods. An interface, on the other hand, defines a contract of methods that a class must implement. Unlike an abstract class, an interface cannot contain implementation details.
Question: What is the purpose of the final
keyword in Java? Answer: The final
keyword is used to restrict the behavior of classes, methods, and variables. A final class cannot be subclassed, a final method cannot be overridden, and a final variable cannot be reassigned once initialized.
Question: What is the concept of method overriding in Java? Answer: Method overriding occurs when a subclass provides a different implementation of a method that is already defined in its superclass. The overridden method in the subclass must have the same signature (name, return type, and parameters) as the method in the superclass.
Question: What is the purpose of the this
keyword in Java? Answer: The this
keyword refers to the current instance of a class. It is often used to differentiate between instance variables and method parameters or to invoke constructors within a class.
Question: What is the difference between composition and inheritance? Answer: Composition represents a “has-a” relationship, where one class contains references to objects of another class. Inheritance, onContinuing from the previous response, here are more interview questions related to Object-Oriented Programming (OOP) in Java:
Question: What is the concept of method overloading in Java? Answer: Method overloading is the process of defining multiple methods with the same name but different parameters within the same class. The compiler determines which method to invoke based on the number, types, and order of the arguments passed.
Question: What is the difference between abstract classes and interfaces in Java? Answer: Abstract classes can have both abstract and concrete methods, while interfaces can only have abstract methods. A class can implement multiple interfaces, but it can only extend one abstract class.
Question: What is the significance of the static
keyword in Java? Answer: The static
keyword is used to define class-level members that are shared among all instances of a class. static
methods and variables can be accessed without creating an instance of the class.
Question: What is the purpose of the final
keyword for variables in Java? Answer: The final
keyword for variables makes them constants, meaning their values cannot be changed once assigned. It is used to create immutable variables.
Question: What is the concept of method hiding in Java? Answer: Method hiding occurs when a subclass defines a static method with the same name and signature as a static method in its superclass. The subclass’s static method hides the superclass’s static method.
Question: What is the difference between shallow copy and deep copy? Answer: Shallow copy creates a new object that references the same memory as the original object, while deep copy creates a new object with its own memory, copying all the values of the original object.
Question: How does Java support multiple inheritance? Answer: Java doesn’t support multiple inheritance of classes, but it supports multiple inheritance of interfaces. By implementing multiple interfaces, a class can inherit multiple sets of behavior.
Question: What are access modifiers in Java, and what is their significance? Answer: Access modifiers control the visibility and accessibility of classes, methods, and variables. They include public
, protected
, private
, and default (no modifier). They ensure proper encapsulation and provide control over the accessibility of code.
Question: What is a static initializer block in Java? Answer: A static initializer block is a block of code that is executed when a class is loaded into memory. It is used to initialize static variables or perform one-time setup tasks for the class.
Question: What is the purpose of the instanceof
operator in Java? Answer: The instanceof
operator is used to check if an object is an instance of a particular class or implements a specific interface. It returns a boolean value indicating the result of the check.
Question: What are accessors and mutators (getters and setters) in Java? Answer: Accessors (getters) are methods used to retrieve the values of private fields, while mutators (setters) are methods used to modify the values of private fields. They ensure controlled access to the object’s state.
Question: What is the purpose of the clone()
method in Java? Answer: The clone()
method is used to create a copy of an object. It performs a shallow copy by default, but it can be overridden to perform a deep copy if necessary.
Question: What is the equals()
method in Java used for? Answer: The equals()
method is used to compare the equality of two objects. It is typically overridden to provide a custom implementation for object comparison based on specific criteria.
Question: What is the difference between String
,Continuing from the previous response, here are more interview questions related to Object-Oriented Programming (OOP) in Java:
Question: What is the difference between String
, StringBuilder
, and StringBuffer
in Java? Answer:
String
is an immutable class, meaning its value cannot be changed once created. It is suitable for situations where the value needs to remain constant.StringBuilder
and StringBuffer
are mutable classes that can be used to manipulate strings. StringBuilder
is not thread-safe, while StringBuffer
is thread-safe due to its synchronized methods.Question: What is method hiding in Java, and how does it differ from method overriding? Answer: Method hiding occurs when a subclass defines a static method with the same name and signature as a static method in its superclass. The subclass’s static method hides the superclass’s static method. Method overriding, on the other hand, occurs when a subclass provides a different implementation of a method that is already defined in its superclass.
Question: What is the difference between the throw
and throws
keywords in Java? Answer:
throw
keyword is used to explicitly throw an exception within a method or block of code.throws
keyword is used in a method signature to indicate that the method may throw one or more exceptions. It is used for checked exceptions.Question: What is the finalize()
method in Java used for? Answer: The finalize()
method is a method of the Object
class that is called by the garbage collector when it determines that there are no more references to the object. It can be overridden to perform cleanup tasks before the object is garbage collected.
Question: What is the difference between the ArrayList
and LinkedList
classes in Java? Answer:
ArrayList
is implemented as a dynamic array, providing fast random access and iteration. It is suitable for scenarios where frequent element access and modification are required.LinkedList
is implemented as a doubly-linked list, providing fast insertion and deletion at both ends. It is suitable for scenarios where frequent insertions and deletions are required.
1. What is a Collection?
A Collection is a group of individual objects represented as a single unit. Java provides Collection Framework which defines several classes and interfaces to represent a group of objects as a single unit.
2. Why do we need Collection?
Arrays are not dynamic. Once an array of a particular size is declared, the size cannot be changed. When it’s full and you need to add a new element, a new array has to be created with a bigger size and all the elements from the old array have to be copied to the new array.
Collections are used in situations where data is dynamic. Collections allow adding an element, deleting an element, and other operations. There are a number of Collections in Java but you need to know how to choose the right Collection for the right context.
3. Advantages of Collection?
Dynamic Size: Collections provide dynamic sizing, allowing you to add, remove, or modify elements without worrying about managing the underlying data structure’s size manually. This flexibility is especially useful when the number of elements is unknown or may change over time.
Data Organization: Collections offer various data structures, such as lists, sets, maps, queues, etc., that can organize and store data in different ways to meet specific requirements. For example, ArrayList maintains an ordered collection of elements, HashSet ensures uniqueness, and HashMap provides key-value pair storage.
Type Safety: Collections in Java provide type safety by enforcing type constraints at compile-time. Generics allow you to specify the type of elements that a collection can hold, preventing runtime errors caused by incompatible data types.
3. What are the important methods in the Collection interface?
The most important methods declared in the Collection interface are the methods to add and remove an element. add method allows adding an element to a collection and delete method allows deleting an element from a collection.
size() method returns the number of elements in the collection. Other important methods defined as part of the collection interface are shown below.
interface Collection<E> extends Iterable<E> { boolean add(E paramE); boolean remove(Object paramObject); int size(); boolean isEmpty(); void clear(); boolean contains(Object paramObject); boolean containsAll(Collection<?> paramCollection); boolean addAll(Collection<? extends E> paramCollection); boolean removeAll(Collection<?> paramCollection); boolean retainAll(Collection<?> paramCollection); Iterator<E> iterator(); //A NUMBER OF OTHER METHODS AS WELL.. }
4. Can you explain the List interface?
List interface extends Collection interface. So, it contains all methods defined in the Collection interface. In addition, the List interface allows operation specifying the position of the element in the Collection.
The most important thing to remember about a List interface – any implementation of the List interface would maintain the insertion order. When an element A is inserted into a List (without specifying position) and then another element B is inserted, A is stored before B in the List.
When a new element is inserted without specifying a position, it is inserted at the end of the list of elements.
However, We can also use the void add(int position, E param E); method to insert an element at a specific position.
Listed below are some of the important methods in the List interface (other than those inherited from Collection interface):
interface List<E> extends Collection<E> { boolean addAll(int paramInt, Collection<? extends E> paramCollection); E get(int paramInt); E set(int paramInt, E paramE); void add(int paramInt, E paramE); E remove(int paramInt); int indexOf(Object paramObject); int lastIndexOf(Object paramObject); ListIterator<E> listIterator(); ListIterator<E> listIterator(int paramInt); List<E> subList(int paramInt1, int paramInt2); }
5. Can you explain the Map interface?
First and foremost, the Map interface does not extend the Collection interface. So, it does not inherit any of the methods from the Collection interface.
A Map interface supports Collections that use a key-value pair. A key-value pair is a set of linked data items: a key, which is a unique identifier for some item of data, and the value, which is either the data or a pointer to the data. Key-value pairs are used in lookup tables, hash tables and configuration files. A key-value pair in a Map interface is called an Entry.
Put method allows to add a key, value pair to the Map.
V put(K paramK, V paramV);
Get method allows to get a value from the Map based on the key.
V get(Object paramObject);Other important methods in Map Inteface are shown below
interface Map<K, V> { int size(); boolean isEmpty(); boolean containsKey(Object paramObject); boolean containsValue(Object paramObject); V get(Object paramObject); V put(K paramK, V paramV); V remove(Object paramObject); void putAll(Map<? extends K, ? extends V> paramMap); void clear(); Set<K> keySet(); Collection<V> values(); Set<Entry<K, V>> entrySet(); boolean equals(Object paramObject); int hashCode(); public static abstract interface Entry<K, V> { K getKey(); V getValue(); V setValue(V paramV); boolean equals(Object paramObject); int hashCode(); } }
6. What is the difference between Set and SortedSet?
SortedSet Interface extends the Set Interface. Both Set and SortedSet do not allow duplicate elements.
The main difference between Set and SortedSet is – an implementation of SortedSet interface maintains its elements in a sorted order. Set interface does not guarantee any Order. For example, If elements 4,5,3 are inserted into an implementation of Set interface, it might store the elements in any order. However, if we use SortedSet, the elements are sorted. The SortedSet implementation would give an output 3,4,5.
Important Operations in the SortedSet interface which are not present in the Set Interface are listed below:
public interface SortedSet<E> extends Set<E> { SortedSet<E> subSet(E fromElement, E toElement); SortedSet<E> headSet(E toElement); SortedSet<E> tailSet(E fromElement); E first(); E last(); Comparator<? super E> comparator(); }
7. What is HashSet?
HashSet implements the Set interface. So, HashSet does not allow duplicates. However, HashSet does not support ordering. The order in which elements are inserted is not maintained.
Set<String> hashset = new HashSet<String>(); hashset.add("Sachin"); System.out.println(hashset);//[Sachin] hashset.add("Dravid"); System.out.println(hashset);//[Sachin, Dravid]
Let’s try to add Sachin to the Set now. Sachin is Duplicate. So will not be added. returns false.
hashset.add("Sachin");//returns false since element is not added System.out.println(hashset);//[Sachin, Dravid]
8. What is a LinkedHashSet? How is it different from HashSet?
LinkedHashSet implements the Set interface and exposes similar operations to a HashSet. The difference is that LinkedHashSet maintains the insertion order. When we iterate a LinkedHashSet, we would get the elements back in the order in which they were inserted.
9. What is TreeSet? How is it different from HashSet?
TreeSet implements Set, SortedSet and NavigableSet interfaces. TreeSet is similar to HashSet except that it stores element’s in Sorted Order. The ordering of the elements is maintained by a set using their natural ordering whether or not an explicit comparator is provided.
Set<String> treeSet = new TreeSet<String>(); treeSet.add("Sachin"); System.out.println(treeSet);//[Sachin] Notice that the list is sorted after inserting Dravid. //Alphabetical order treeSet.add("Dravid"); System.out.println(treeSet);//[Dravid, Sachin] Notice that the list is sorted after inserting Ganguly. treeSet.add("Ganguly"); System.out.println(treeSet);//[Dravid, Ganguly, Sachin] Sachin is Duplicate. So will not be added. returns false. treeSet.add("Sachin");//returns false since element is not added System.out.println(treeSet);//[Dravid, Ganguly, Sachin]
10. What is the difference between Map and SortedMap?
SortedMap interface extends the Map interface. In addition, an implementation of SortedMap interface maintains keys in a sorted order.
Methods are available in the interface to get a ranges of values based on their keys.
public interface SortedMap<K, V> extends Map<K, V> { Comparator<? super K> comparator(); SortedMap<K, V> subMap(K fromKey, K toKey); SortedMap<K, V> headMap(K toKey); SortedMap<K, V> tailMap(K fromKey); K firstKey(); K lastKey(); }
11. Explain the Queue interface
Queue Interface extends Collection interface. Queue Interface is typically used for implementation holding elements in order for some processing. Queue interface offers methods peek() and poll() which get the element at head of the queue. The difference is that poll() method removes the head from queue also. peek() would keep head of the queue unchanged.
interface Queue<E> extends Collection<E> { boolean offer(E paramE); E remove(); E poll(); E element(); E peek(); }
12. Explain the Iterator interface?
Iterator interface enables us to iterate (loop around) a collection. All collections define a method iterator() that gets an iterator of the collection.
hasNext() checks if there is another element in the collection being iterated. next() gets the next element.
public interface Iterator<E> { boolean hasNext(); E next(); }
13. Explain ArrayList?
ArrayList implements the list interface. So, ArrayList stores the elements in insertion order (by default). Elements can be inserted into and removed from ArrayList based on their position.
Let’s look at how to instantiate an ArrayList of integers.
List<Integer> integers = new ArrayList<Integer>();
Code like below is permitted because of auto boxing. 5 is auto boxed into Integer object and stored in ArrayList.Add method (by default) adds the element at the end of the
list.integers.add(5);//new Integer(5)
ArrayList can have duplicates.
//Iterate an ArrayList using Iterator. Iterator<String> arraylistIterator = arraylist.iterator(); while (arraylistIterator.hasNext()) { String str = arraylistIterator.next(); System.out.println(str);//Prints the 4 names in the list on separate lines. }
Sort an ArrayList
List<String> numbers = new ArrayList<String>(); numbers.add("one"); numbers.add("two"); numbers.add("three"); numbers.add("four"); System.out.println(numbers);//[one, two, three, four] //Strings - By Default - are sorted alphabetically Collections.sort(numbers); System.out.println(numbers);//[four, one, three, two]
//Sort and ArrayList using Comparable class Cricketer implements Comparable<Cricketer> { int runs; String name; public Cricketer(String name, int runs) { super(); this.name = name; this.runs = runs; } @Override public String toString() { return name + " " + runs; } @Override public int compareTo(Cricketer that) { if (this.runs > that.runs) { return 1; } if (this.runs < that.runs) { return -1; } return 0; } } List<Cricketer> cricketers = new ArrayList<Cricketer>(); cricketers.add(new Cricketer("Bradman", 9996)); cricketers.add(new Cricketer("Sachin", 14000)); cricketers.add(new Cricketer("Dravid", 12000)); cricketers.add(new Cricketer("Ponting", 11000)); System.out.println(cricketers); //[Bradman 9996, Sachin 14000, Dravid 12000, Ponting 11000] Collections.sort(cricketers); System.out.println(cricketers); //[Bradman 9996, Ponting 11000, Dravid 12000, Sachin 14000]
Sort and ArrayList using Comparator
class DescendingSorter implements Comparator<Cricketer> { //compareTo returns -1 if cricketer1 < cricketer2 // 1 if cricketer1 > cricketer2 // 0 if cricketer1 = cricketer2 //Since we want to sort in descending order, //we should return -1 when runs are more @Override public int compare(Cricketer cricketer1, Cricketer cricketer2) { if (cricketer1.runs > cricketer2.runs) { return -1; } if (cricketer1.runs < cricketer2.runs) { return 1; } return 0; } } Collections .sort(cricketers, new DescendingSorter()); System.out.println(cricketers); //[Sachin 14000, Dravid 12000, Ponting 11000, Bradman 9996]
14. Convert Array to List
String values[] = { "value1", "value2", "value3" }; List<String> valuesList = Arrays.asList(values); System.out.println(valuesList);//[value1, value2, value3]
15. Convert List to Array
List<String> list = Arrays.asList("C", "C++", "Java"); String[] array = list.toArray(new String[list.size()]); System.out.println(Arrays.toString(array));
List<String> list = Arrays.asList("C", "C++", "Java"); String[] array = list.stream().toArray(String[]::new); System.out.println(Arrays.toString(array)); // or List<String> list = Arrays.asList("C", "C++", "Java"); String[] array = list.stream().toArray(n -> new String[n]); System.out.println(Arrays.toString(array));
16. What is Vector? How is it different from List?
Vector has the same operations as an ArrayList. However, all methods in Vector are synchronized. So, we can use Vector if we share a list between two threads and we would want them synchronized.
17. What is LinkedList? How is it different from ArrayList?
Linked List extends List and Queue. Other than operations exposed by the Queue interface, LinkedList has the same operations as an ArrayList. However, the underlying implementation of Linked List is different from that of an ArrayList.
ArrayList uses an Array kind of structure to store elements. So, inserting and deleting from an ArrayList are expensive operations. However, searching in an ArrayList is faster than LinkedList.
LinkedList uses a linked representation. Each object holds a link to the next element. Hence, insertion and deletion are faster than ArrayList. But searching is slower.
18. What are the important methods in the NavigableSet interface?
//Find the highest number which is lower than 25 System.out.println(numbersTreeSet.lower(25));//5 //Find the highest number which is lower than or equal to 25 System.out.println(numbersTreeSet.floor(25));//25 //Find the lowest number higher than 25 System.out.println(numbersTreeSet.higher(25));//35 //Find the lowest number higher than or equal to 25 System.out.println(numbersTreeSet.ceiling(25));//25
19. What the different implementations in the Map interface?
20. What is HashMap?
HashMap implements Map interface – thereby supporting key-value pairs. Let’s look at an example.
Map<String, Cricketer> hashmap = new HashMap<String, Cricketer>(); hashmap.put("sachin", new Cricketer("Sachin", 14000)); hashmap.put("dravid", new Cricketer("Dravid", 12000)); hashmap.put("ponting", new Cricketer("Ponting", 11500)); hashmap.put("bradman", new Cricketer("Bradman", 9996)); get method gets the value of the matching key. System.out.println(hashmap.get("ponting"));//Ponting 11500 //if key is not found, returns null. System.out.println(hashmap.get("lara"));//null If existing key is reused, it would replace existing value with the new value passed in. //In the example below, an entry with key "ponting" is already present. //Runs are updated to 11800. hashmap.put("ponting", new Cricketer("Ponting", 11800)); //gets the recently updated value System.out.println(hashmap.get("ponting"));//Ponting 11800
21. What is TreeMap? How is different from HashMap?
TreeMap is similar to HashMap except that it stores keys in sorted order. It implements the NavigableMap interface and SortedMap interfaces along with the Map interface.
Map<String, Cricketer> treemap = new TreeMap<String, Cricketer>(); treemap.put("sachin", new Cricketer("Sachin", 14000)); System.out.println(treemap); //{sachin=Sachin 14000} We will now insert a Cricketer with key dravid. In sorted order,dravid comes before sachin. So, the value with key dravid is inserted at the start of the Map. treemap.put("dravid", new Cricketer("Dravid", 12000)); System.out.println(treemap); //{dravid=Dravid 12000, sachin=Sachin 14000} We will now insert a Cricketer with key ponting. In sorted order, ponting fits in between dravid and sachin. treemap.put("ponting", new Cricketer("Ponting", 11500)); System.out.println(treemap); //{dravid=Dravid 12000, ponting=Ponting 11500, sachin=Sachin 14000} treemap.put("bradman", new Cricketer("Bradman", 9996)); System.out.println(treemap); //{bradman=Bradman 9996, dravid=Dravid 12000, ponting=Ponting 11500, sachin=Sachin 14000}
22. What is a PriorityQueue?
A PriorityQueue is used when the objects are supposed to be processed based on the priority. It is known that a queue follows First-In-First-Out algorithm, but sometimes the elements of the queue are needed to be processed according to the priority, that’s when the PriorityQueue comes into play. The PriorityQueue is based on the priority heap. The elements of the priority queue are ordered according to the natural ordering, or by a Comparator provided at queue construction time, depending on which constructor is used.
PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>(); priorityQueue.offer(24); priorityQueue.offer(15); priorityQueue.offer(9); priorityQueue.offer(45); System.out.println(priorityQueue);//[9, 24, 15, 45] Peek method examples //peek method get the element with highest priority. System.out.println(priorityQueue.peek());//9 //peek method does not change the queue System.out.println(priorityQueue);//[9, 24, 15, 45] //poll method gets the element with highest priority. System.out.println(priorityQueue.poll());//9 //peek method removes the highest priority element from the queue. System.out.println(priorityQueue);//[24, 15, 45] //This comparator gives high priority to the biggest number. Comparator reverseComparator = new Comparator<Integer>() { public int compare(Integer paramT1, Integer paramT2) { return paramT2 - paramT1; } };
23. What is the Collections class?
This class consists exclusively of static methods that operate on or return collections. It contains polymorphic algorithms that operate on collections, “wrappers”, which return a new collection backed by a specified collection, and a few other odds and ends.
The java.util.Collections
class is a utility class in Java that provides various static methods for working with collections (interfaces and classes that implement the java.util.Collection
interface). It contains methods to perform operations such as searching, sorting, shuffling, reversing, and synchronizing collections. The methods in the Collections
class operate on the collection itself and do not modify the original collection; instead, they return modified views or create new collections.
The methods of this class all throw a NullPointerException if the collections or class objects provided to them are null.
24. What are the differences between synchronized and concurrent collections?
Synchronized collections are implemented using synchronized methods and synchronized blocks. Only one thread can executing any of the synchronized code at a given point in time. This places severe restrictions on the concurrency of threads – thereby affecting performance of the application. All the pre Java 5 synchronized collections (HashTable & Vector, for example) use this approach.
Post Java 5, collections using new approaches to synchronization are available in Java. These are called concurrent collections. More details below.
25. What is the initial capacity of Collection?
An instance of HashMap has two parameters that affect its performance: initial capacity and load factor. The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.
As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put).
The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations.
List doubles its size by 50%.
26. When does Collection throw UnSupportedOperationException?
All Java Collections extend Collection interface. So, they have to implement all the methods in the Collection interface. However, certain Java collections are optimized to be used in specific conditions and do not support all the Collection operations (methods). When an unsupported operation is called on a Collection, the Collection Implementation would throw an UnsupportedOperationException.
Arrays.asList returns a fixed-size list backed by the specified array. When an attempt is made to add or remove from this collection an UnsupportedOperationException is thrown. Below code throws UnsupportedOperationException. List<String> list=Arrays.asList(new String[]{"ac","bddefe"}); list.remove();//throws UnsupportedOperationException
27. What is the difference between fail-fast and fail-safe iterators?
Fail Fast Iterators throw a ConcurrentModificationException if there is a modification to the underlying collection is modified. This was the default behavior of the synchronized collections of pre Java 5 age.
Fail Safe Iterators do not throw exceptions even when there are changes in the collection. This is the default behavior of the concurrent collections, introduced since Java 5.
28. Explain about the stream API?
Streams are introduced in Java 8. In combination with Lambda expressions, they attempt to bring some of the important functional programming concepts to Java.
A stream is a sequence of elements supporting sequential and parallel aggregate operations. Consider the example code below. Following steps are done:
Arrays.stream(new String[] { "Ram", "Robert", "Rahim" }) .filter(s - > s.startsWith("Ro")) .map(String::toLowerCase) .sorted() .forEach(System.out::println);
In general any use of streams involves
Intermediate Operations are of two kinds
29. What are the atomic operations in Java?
Atomic Access Java Tutorial states “In programming, an atomic action is one that effectively happens all at once. An atomic action cannot stop in the middle: it either happens completely, or it doesn’t happen at all. No side effects of an atomic action are visible until the action is complete”.
Let’s assume we are writing a multi threaded program. Let’s create an int variable i. Even a small operation, like i++ (increment), is not thread safe. i++ operation involves three steps.
In a multi-threaded environment, there can be unexpected results. For example, if thread1 is reading the value (step 1) and immediately after thread2 stores the value (step 3).
To prevent these, Java provides atomic operations. Atomic operations are performed as a single unit without interference from other threads ensuring data consistency.
A good example is AtomicInteger. To increment a value of AtomicInteger, we use the incrementAndGet() method. Java ensures this operation is Atomic.
30. What is BlockedQueue?
BlockedQueue interface is introduced in Java specifically to address specific needs of some Producer Consumer scenarios. BlockedQueue allows the consumer to wait (for a specified time or infinitely) for an element to become available.
31. Comparator vs Comparable
The method returns a number indicating whether the object being compared is less than, equal to or greater than the object being passed as an argument.
Comparable is used for default sorting. You have a default sorting that you can’t change. Once you set it, it’s there and you can change it at runtime.
Comparable:
compareTo(Object o)
. This method compares the current object with the specified object and returns a negative integer, zero, or a positive integer to indicate the object’s relative order.Collections.sort()
or Arrays.sort()
.public class Person implements Comparable<Person> { private String name; private int age; // Constructor and other methods @Override public int compareTo(Person other) { return this.name.compareTo(other.name); } }
@Override public int compareTo(Player otherPlayer) { return (this.getRanking() - otherPlayer.getRanking()); }
Order depending on the comparison. Pay attention here to the comparison.(this.getRanking() - otherPlayer.getRanking());// ascending
(
otherPlayer.getRanking() – this
.getRanking());// descending
Comparator:
compare(Object o1, Object o2)
. This method compares two objects and returns a negative integer, zero, or a positive integer to indicate the objects’ relative order.public class PersonAgeComparator implements Comparator<Person> { @Override public int compare(Person p1, Person p2) { return Integer.compare(p1.getAge(), p2.getAge()); } }
Comparator
public class PlayerRankingComparator implements Comparator<Player> { @Override public int compare(Player firstPlayer, Player secondPlayer) { return (firstPlayer.getRanking() - secondPlayer.getRanking()); } }
You can Create different comparators(sortings) and use them according to your needs. With comparable you are stuck to one type of sorting.
In most real-life scenarios, we want sorting based on different parameters. For example, as a CEO, I would like to sort the employees based on Salary, an HR would like to sort them based on age. This is the situation where we need to use Java Comparator interface because Comparable.compareTo(Object o) method implementation can provide default sorting and we can’t change it dynamically. Whereas with Comparator, we can define multiple methods with different ways of sorting and then chose the sorting method based on our requirements.
java.lang
package whereas Comparator interface is present in java.util
package.Arrays.sort()
or Collection.sort()
methods automatically uses the compareTo()
method of the class. For Comparator, client needs to provide the Comparator class to use in compare() method.Comparable is used to define the natural ordering of objects within a class, while Comparator is used to define custom ordering or multiple comparison rules for objects. If a class implements Comparable, its natural ordering is used by default for sorting. If a custom ordering or multiple sorting options are needed, a Comparator can be implemented and passed explicitly to sorting methods.
32. How to sort by multiple fields?
public int compare(Member a, Member b){ // sort by age int order = a.getAge() - b.getAge(); if(order==0){ // if ages are the same, compare name order = a.getName().compareTo(b.getName()); } if(order==0){ // if ages and names are the same, compare gender order = a.getGender().compareTo(a.getGender()); } return order; }
33. What is the importance of hashCode() and equals() methods ?
hashCode() and equals() are used for object comparison, hashing, and indexing purposes.
The hashCode()
and equals()
methods are closely related and must be implemented consistently. When overriding equals()
, you should also override hashCode()
to ensure that equal objects have the same hash code. This is crucial when using objects in hash-based collections to maintain data integrity and retrieve objects correctly based on equality.
hashCode()
Method:
hashCode()
method returns an integer value, known as the hash code, which represents the object’s internal address or identity.equals()
method must have the same hash code. However, objects with the same hash code are not necessarily equal according to equals()
.hashCode()
method when overriding the equals()
method to ensure consistency between the two methods. This is necessary to maintain the contract between equality and hash-based collections.hashCode()
method should be implemented in a way that distributes hash codes evenly across different objects to avoid collisions and improve the performance of hash-based data structures.
equals()
Method:
The equals()
method is used to compare the equality of two objects. It determines whether two objects have the same content or state.
The default implementation of equals()
in the Object
class compares object references for identity equality, which checks if two object references point to the same memory location.
By overriding the equals()
method, you can provide your own implementation to define equality based on specific criteria, such as comparing the values of certain attributes.
The equals()
method must satisfy the following properties:
x.equals(x)
should return true).x.equals(y)
returns true, then y.equals(x)
should also return true.x.equals(y)
and y.equals(z)
both return true, then x.equals(z)
should also return true.equals()
on the same objects should consistently return true or false, provided that the object’s state doesn’t change.x.equals(null)
should return false, and it should not throw an exception.It is recommended to override the equals()
method whenever a custom class defines its notion of equality based on attribute values.
equals(Object otherObject)
– As method name suggests, is used to simply verify the equality of two objects. It’s default implementation simply check the object references of two objects to verify their equality. By default, two objects are equal if and only if they are stored in the same memory address.hashcode()
– Returns a unique integer value for the object in runtime. By default, integer value is mostly derived from memory address of the object in heap (but it’s not mandatory always).Contract
It is generally necessary to override the hashCode()
method whenever equals()
method is overridden, so as to maintain the general contract for the hashCode()
method, which states that equal objects must have equal hash codes.
hashCode
method must consistently return the same integer, provided no information used in equals
comparisons on the object is modified.equals(Object)
method, then calling the hashCode
method on each of the two objects must produce the same integer result.equals(java.lang.Object)
method, then calling the hashCode
method on each of the two objects must produce distinct integer results.hashCode() and equals() is used to compare two objects to determine whether they are the same or equal or not.
In HashMap, hashCode() is used to calculate the bucket and therefore calculate the index.
HashMap uses equals() to compare the key whether the are equal or not. If equals() method return true, they are equal otherwise not equal.
A HashMap in Java uses the hashCode and equals methods to determine the index of the key-value pair. These methods are also used when we request the value of a specific key. If these methods are not implemented correctly, two different keys might produce the same hash value and thus, will be considered as equal by the collection. Furthermore, these methods are also used to detect duplicates. Thus, the implementation of both methods is crucial to the accuracy and correctness of the HashMap.
1.What modifiers are allowed for methods in an interface?
Public: Interface methods are implicitly public, meaning they are accessible from anywhere.
Abstract: Interface methods are implicitly abstract, indicating that they do not have an implementation in the interface itself.
Default: Starting from Java 8, interfaces can have default methods, which provide a default implementation for the method. Default methods are declared using the default
keyword and can be overridden by implementing classes if needed.
Static: Interfaces can have static methods, which are defined using the static
keyword. Static methods in interfaces are not inherited and can be called directly using the interface name.
It’s important to note that in Java 17 and earlier versions, interface methods cannot have the private
, protected
, or final
modifiers. These modifiers are not allowed for interface methods until Java 18, which introduced the private
and protected
modifiers for interface methods.
2. What is a local, member, and a class variable?
Variables declared within a method are local. Variables declared within a class but outside of methods are member variables. Variables within a class that are static are called class variables.
A local variable is a variable declared inside a method, constructor, or a block of code, such as a loop or conditional statement. It is accessible only within its enclosing scope and is not visible outside of that scope. Local variables are used for temporary storage and hold data that is relevant only within a specific block of code. Local variables must be initialized before they can be used.
public void process() { int num = 10; // Local variable declaration and initialization // ... }
In the above example, num
is a local variable declared inside the process()
method. It is accessible only within the method and is not visible outside of it.
Member variables, also known as instance variables, are declared within a class but outside of any method. They are associated with instances (objects) of the class and each instance of the class has its own copy of these variables. Member variables have default values if not explicitly initialized. They are accessible within the entire class, including its methods and constructors.
public class User { private String name; // Member variable declaration public void setName(String value) { name = value; // Accessing member variable within a method } }
In the above example, name
is a member variable declared within the User
class. It is accessible in all methods and constructors of the class, and each instance of User
will have its own copy of this variable.
Class variables, also known as static variables, are declared within a class with the static
modifier. Unlike member variables, class variables are associated with the class itself rather than with instances of the class. There is only one copy of a class variable shared by all instances of the class. Class variables are initialized only once when the class is loaded into memory and retain their values throughout the program execution.
public class User { private static int time; // Class variable declaration public static void setTime(int value) { time = value; // Accessing class variable within a static method } }
In the above example, time
is a class variable declared within the User
class. It is shared among all instances of the class, and its value can be accessed and modified through static methods or by directly referencing the class name (User.time
).
It’s important to note that local variables are temporary and exist only within the scope of a method or block, member variables belong to instances of a class, and class variables are associated with the class itself and are shared among all instances of the class.
3. What are Serialization and Deserialization?
Serialization is the process of saving/writing the state of an object to a byte stream.
Deserialization is the process of restoring a serialized object.
4. Can you have an inner class within a method and what variables can you access?
It is possible to have an inner class within a method. These inner classes are called local inner classes or method-local inner classes. They are defined within a method or a block of code and have their own scope limited to that method or block. Local inner classes have access to variables declared within the method/block, as well as to the method’s/block’s parameters and any final or effectively final variables.
public class OuterClass { public void outerMethod() { int outerVariable = 10; class LocalInnerClass { public void innerMethod() { System.out.println("Accessing outer variable: " + outerVariable); } } LocalInnerClass innerObj = new LocalInnerClass(); innerObj.innerMethod(); } }
5. What is the clonable interface?
The clonable interface is a marker interface. The Cloneable
interface is a marker interface that indicates a class’s ability to be cloned using the clone()
method. It serves as a marker for objects that can support cloning, allowing you to create a copy of an object with the same state.
The Cloneable
interface does not contain any methods. It acts as a flag, notifying the clone()
method that the object can be cloned without throwing a CloneNotSupportedException
. If a class implements Cloneable
, it indicates that instances of that class can be cloned.
To make a class cloneable, you need to follow these steps:
public class MyClass implements Cloneable { // class members and methods @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
The clone()
method is declared in the Object
class and is protected, so you need to provide a public implementation in your class to make it accessible.
When cloning an object, you call the clone()
method on an instance of the class, which creates and returns a shallow copy of the object. It is important to note that the clone()
method performs a shallow copy by default, meaning that only the object’s references are copied, not the referenced objects themselves.
In a shallow copy, only the references of the fields are copied from the original object to the cloned object. Both the original and cloned objects will point to the same referenced objects in memory. In other words, changes made to the referenced objects in one object will be reflected in the other object as well.
If you need a deep copy (i.e., copies of the referenced objects as well), you need to implement a custom cloning mechanism within the clone()
method. To deep copy an object you ensure that all the referenced objects in the class also implement the Cloneable
interface and override their clone()
methods.
6. What is the difference between Integer and int?
Integer is a wrapper class for the primitive int. Integer can be used for generic like List<Integer> list. It cannot be List<int> list.
int is the primitive.
7. What is an inner class and an anonymous class?
An inner class is any class defined in another class even an inner class within a method.
An anonymous class is a class defined inside a method. This class does not have a name. It is instantiated and declared in the same place. It can’t have explicit constructors.
An anonymous class is a specific type of inner class that does not have a name. It is declared and instantiated in a single expression, usually at the point of use. Anonymous classes are commonly used to implement interfaces, extend classes, or define event handlers.
Here’s an example of an anonymous class implementing an interface:
interface MyInterface { void doSomething(); } public class MyClass { public void performAction() { MyInterface myInterface = new MyInterface() { public void doSomething() { System.out.println("Doing something..."); } }; myInterface.doSomething(); } }
8. What modifiers can a top-class have?
public, abstract, and final.
9. What is the difference between a superclass and a subclass?
A superclass is a class that is inherited.
A subclass is a class that does the inheriting.
10. What is the difference between overloading and overriding?
Overloading is a relationship between different methods within a class.
Overloading methods have the same name with different method signatures.
Overloading:
public class Calculator { public int add(int a, int b) { return a + b; } public double add(double a, double b) { return a + b; } }
Overriding is a relationship between a superclass and a subclass.
Overriding methods must have the same method signatures.
Overriding:
public class Animal { public void makeSound() { System.out.println("Animal makes a sound."); } } public class Dog extends Animal { @Override public void makeSound() { System.out.println("Dog barks."); } }
11. What is final, finalize(), and finally?
final: a final class can’t be extended. a final method can’t be overridden. a final variable can be changed from its initial value.
finalize(): this method is called just be an object is garbage collected.
finally: a finally block a block which is part of a try or try and catch block. This block runs regardless of an exception is thrown or not.
12. What are the different types of access modifiers in Java?
public: can be accessed from everywhere.
private: can be accessed outside of the class in which private is used.
protected: can be accessed from the same package or subclasses from different packages.
Default modifier: can be accessed only from the same package.
13. What do static methods mean?
Static methods can be called using just the class name. Static methods belong to class not an object of the class. You don’t have to create an object to access static methods.
14. What does it mean that a method or a field is static?
Static variables and methods are instantiated only once per class. If you change the value of a static variable, it will change for all instances of that class.
15. What is the common usage of serialization?
Serialization in Java refers to the process of converting an object into a byte stream, which can be saved to a file, sent over a network, or stored in a database. Deserialization is the reverse process, where the byte stream is converted back into an object.
When an object(and its state) is to be saved somewhere and be retrieved for later use then serialization comes into the picture. When you cache an object using a cache manager(Redis) the object must be serialized.
Caching: Serialization can be used for caching objects in memory or on disk. By serializing objects, they can be stored in a cache and quickly retrieved when needed. This helps improve performance by reducing the need to recreate objects from scratch.
Network Communication: Serialization enables objects to be transmitted across a network or between distributed systems. By serializing an object and sending it over the network, the receiving end can deserialize it to obtain the original object. This is commonly used in client-server architectures, remote procedure calls (RPC), distributed computing, and messaging systems.
Persistence: Serialization allows objects to be stored persistently in files or databases. By serializing an object, its state can be saved, and later, the object can be deserialized to recreate the exact state. This is useful for saving and loading application data, configuration settings, user preferences, and more.
import java.io.*; public class SerializationExample { public static void main(String[] args) { // Create an object to serialize Person person = new Person("John Doe", 30); // Serialize the object to a file serializeObject(person, "person.ser"); // Deserialize the object from the file Person deserializedPerson = deserializeObject("person.ser"); // Print the deserialized object System.out.println("Deserialized Person: " + deserializedPerson); } public static void serializeObject(Object obj, String fileName) { try { // Create a FileOutputStream to write object data to a file FileOutputStream fileOut = new FileOutputStream(fileName); // Create an ObjectOutputStream to serialize the object ObjectOutputStream objectOut = new ObjectOutputStream(fileOut); // Write the object to the ObjectOutputStream objectOut.writeObject(obj); // Close the streams objectOut.close(); fileOut.close(); System.out.println("Object serialized and saved to " + fileName); } catch (IOException e) { e.printStackTrace(); } } public static <T> T deserializeObject(String fileName) { T obj = null; try { // Create a FileInputStream to read object data from a file FileInputStream fileIn = new FileInputStream(fileName); // Create an ObjectInputStream to deserialize the object ObjectInputStream objectIn = new ObjectInputStream(fileIn); // Read the object from the ObjectInputStream obj = (T) objectIn.readObject(); // Close the streams objectIn.close(); fileIn.close(); System.out.println("Object deserialized from " + fileName); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return obj; } } class Person implements Serializable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } }
16. What is java String Pool?
The string pool is a memory area in the Java heap where String literals are stored. The string pool is a way of conserving memory by reusing existing String objects instead of creating new ones with the same content. Whenever a new string object is created, String pool first checks whether the object is already present in the pool or not. If it is present, then the same reference is returned to the variable else new object will be created in the String pool and the respective reference will be returned.
17. What are the differences between this() and super()?
this() | super() |
1. this() represents the current instance of a class | 1. super() represents the current instance of a parent/base class |
2. Used to call the default constructor of the same class | 2. Used to call the default constructor of the parent/base class |
3. Used to access methods of the current class | 3. Used to access methods of the base class |
4. Used for pointing the current class instance | 4. Used for pointing the superclass instance |
5. Must be the first line of a block | 5. Must be the first line of a block |
18. What are the differences between String, String Builder, and String Buffer?
Factor | String | String Builder | String Buffer |
Storage Area | Constant String Pool | Heap Area | Heap Area |
Mutability | Immutable | Mutable | Mutable |
Thread Safety | Yes | No | Yes |
Performance | Fast | Fast | Slow |
19. What is constructor chaining?
Constructor chaining is the process of calling a constructor from another constructor. This is done using this() keyword.
It’s the process of calling one constructor from another constructor within the same class or between parent and child classes. It allows constructors to invoke other constructors to perform common initialization tasks or to provide different options for object creation.
Within the Same Class:
this()
keyword, a constructor can call another constructor in the same class.this()
must be the first statement in the constructor body.public class MyClass { private int value; public MyClass() { this(0); // Calls the parameterized constructor with value 0 } public MyClass(int value) { this.value = value; } }
Between Parent and Child Classes:
super()
keyword.super()
call must be the first statement in the subclass constructor.public class Animal { protected String name; public Animal(String name) { this.name = name; } } public class Dog extends Animal { private String breed; public Dog(String name, String breed) { super(name); // Calls the constructor of the superclass (Animal) this.breed = breed; } }
Constructor chaining allows for code reuse and helps maintain a clean and modular design by centralizing common initialization logic in one place. It enables constructors to be flexible and provide different ways to construct objects based on the available parameters.
20. Why do we need constructor chaining?
Constructor chaining is useful when we want to perform multiple tasks in a single constructor rather than creating code for each task in a single constructor. We create a separate constructor for each task and make it a chain that makes the program more readable.
21. Why is String immutable?
In Java, string objects are immutable in nature which simply means once the String object is created its state cannot be modified. Whenever you try to update the value of that string, Java creates a new string object instead of updating the values of that particular string. Java String objects are immutable as String objects are generally cached in the String pool. Since String literals are usually shared between multiple clients, action from one client might affect the rest. It enhances security, caching, synchronization, and performance of the application.
22. What are the differences between Array and ArrayList?
Array | ArrayList |
---|---|
Cannot contain values of different data types | It can contain values of different data types. |
Size must be defined at the time of declaration | Size can be dynamically changed |
Need to specify the index in order to add data | No need to specify the index |
Arrays are not type parameterized | ArrayList are type |
Arrays can contain primitive data types as well as objects | ArrayList can contain only objects, no primitive data types are allowed |
23. What is pass by value?
You are passing the values copied. Java is passed by value when you pass primitive data types and passed by reference when you pass custom object data types.
24. What is pass by reference?
You are passing the memory address of the variables you are passing.
25. What is an interface?
An interface is similar to a class but it is an abstract class completely. An interface has abstract methods that its subclasses have to implement. When we talk about an interface we are talking about its capabilities. We are not even talking about how these capabilities are formed, just what they are.
26. 30 commonly asked Java interview questions
Question: Explain the difference between JDK, JRE, and JVM. Answer:
Question: What is the difference between a class and an object in Java? Answer: A class is a blueprint or template that defines the structure and behavior of objects, while an object is an instance of a class.
Question: What is the difference between the ==
operator and the equals()
method in Java? Answer: The ==
operator is used to compare the references of two objects, while the equals()
method is used to compare the content or value of two objects. The equals()
method should be overridden in classes to define custom equality.
Question: What is the difference between checked and unchecked exceptions in Java? Answer: Checked exceptions are checked at compile-time and must be handled explicitly using try-catch blocks or declared in the method signature using the throws
keyword. Unchecked exceptions, also known as runtime exceptions, do not require explicit handling or declaration.
Question: What are access modifiers in Java? Explain their significance. Answer: Access modifiers control the visibility and accessibility of classes, methods, and variables. They include public
, protected
, private
, and default (no modifier). Access modifiers ensure proper encapsulation and provide control over the accessibility of code.
Question: What is the static
keyword in Java used for? Answer: The static
keyword is used to define class-level members that are shared among all instances of a class. static
methods and variables can be accessed without creating an instance of the class.
Question: What is the purpose of the final
keyword in Java? Answer: The final
keyword is used to restrict the behavior of classes, methods, and variables. A final class cannot be subclassed, a final method cannot be overridden, and a final variable cannot be reassigned once initialized.
Question: What is the difference between method overloading and method overriding? Answer: Method overloading is the process of defining multiple methods with the same name but different parameters within the same class. Method overriding occurs when a subclass provides a different implementation of a method that is already defined in its superclass.
Question: Explain the concept of inheritance in Java. Answer: Inheritance allows a class to inherit the properties (fields and methods) of another class, known as the superclass or parent class. It promotes code reuse and allows for the creation of specialized classes from a general superclass.
Question: What is the this
keyword in Java used for? Answer: The this
keyword refers to the current instance of a class. It is often used to differentiate between instance variables and method parameters or to invoke constructors within a class.
Question: What is the purpose ofContinuing from the previous response, here are more Java interview questions along with their answers:
Question: What are abstract classes and interfaces in Java? Answer: Abstract classes are classes that cannot be instantiated but can be used as base classes for subclasses. They can have abstract methods (without implementation) and concrete methods. Interfaces, on the other hand, define a contract of methods that a class must implement. They cannot contain implementation details.
Question: What is method overriding in Java? Answer: Method overriding occurs when a subclass provides a different implementation of a method that is already defined in its superclass. The overridden method in the subclass must have the same signature (name, return type, and parameters) as the method in the superclass.
Question: What is the difference between checked and unchecked exceptions in Java? Answer: Checked exceptions are checked at compile-time and must be handled explicitly using try-catch blocks or declared in the method signature using the throws
keyword. Unchecked exceptions, also known as runtime exceptions, do not require explicit handling or declaration.
Question: What is the purpose of the StringBuilder
class in Java? Answer: The StringBuilder
class is used to create and manipulate mutable strings. It provides methods for appending, inserting, and modifying strings efficiently.
Question: Explain the concept of autoboxing and unboxing in Java. Answer: Autoboxing is the automatic conversion of primitive types to their corresponding wrapper classes, while unboxing is the automatic conversion of wrapper classes back to primitive types. This conversion is done by the compiler.
Question: What is the difference between String
, StringBuilder
, and StringBuffer
in Java? Answer:
String
is an immutable class, meaning its value cannot be changed once created. It is suitable for situations where the value needs to remain constant.StringBuilder
and StringBuffer
are mutable classes that can be used to manipulate strings. StringBuilder
is not thread-safe, while StringBuffer
is thread-safe due to its synchronized methods.Question: What is the purpose of the Collections
class in Java? Answer: The Collections
class provides utility methods for working with collections (lists, sets, etc.) in Java. It includes methods for sorting, searching, and modifying collections.
Question: What is the purpose of the equals()
method in Java? Answer: The equals()
method is used to compare the equality of two objects. It is typically overridden to provide a custom implementation for object comparison based on specific criteria.
Question: Explain the concept of serialization in Java. Answer: Serialization is the process of converting an object into a byte stream to be stored in memory, sent over a network, or persisted to a file. Deserialization is the reverse process of reconstructing the object from the byte stream.
Question: What is the purpose of the try-catch-finally
block in Java? Answer: The try-catch-finally
block is used for exception handling. The try
block contains the code that may throw an exception, the catch
block handles the exception, and the finally
block is executed regardless of whether an exception occurs or not.
Question: What is the difference between ArrayList
and LinkedList
in Java? Answer:
ArrayList
is implemented as a dynamic array, providing fast random access and iteration. It is suitable for scenarios where frequent element access and modification are required.LinkedList
is implemented as a doubly-linked list, providing fast insertion and deletion at both ends. It is suitable for scenarios where frequent insertions and deletions are required.Question:Continuing from the previous response, here are more Java interview questions along with their answers:
Question: What is the difference between the throw
and throws
keywords in Java? Answer:
throw
keyword is used to explicitly throw an exception within a method or block of code.throws
keyword is used in a method signature to indicate that the method may throw one or more exceptions. It is used for checked exceptions.Question: What is the difference between HashMap
and HashTable
in Java? Answer:
HashMap
is not synchronized and allows null values and keys, while HashTable
is synchronized and does not allow null values or keys.HashMap
is generally preferred over HashTable
for better performance unless thread-safety is required.Question: What is the purpose of the finalize()
method in Java? Answer: The finalize()
method is a method of the Object
class that is called by the garbage collector before reclaiming an object’s memory. It can be overridden to perform cleanup tasks before the object is garbage collected.
Question: What is the difference between shallow copy and deep copy? Answer:
Question: What is the purpose of the static
initializer block in Java? Answer: The static
initializer block is a block of code that is executed only once when the class is loaded into memory. It is used to initialize static variables or perform one-time setup tasks for the class.
Question: What is the purpose of the System.gc()
method in Java? Answer: The System.gc()
method is used to suggest to the JVM that it should run the garbage collector to free up memory. However, it does not guarantee immediate garbage collection.
Alert function
The alert() method displays an alert box with a specified message and an OK button. An alert box is often used if you want to make sure information comes through to the user.The alert box takes the focus away from the current window, and forces the browser to read the message. Do not overuse this method, as it prevents the user from accessing other parts of the page until the box is closed. It does not return a value.
<div class="row"> <div class="col-3"> Alert </div> <div class="col-4"> <button onclick="showAlert()" type="button" class="btn btn-outline-primary btn-block">Click Alert</button> </div> </div> <script> function showAlert(){ alert("This is an alert"); } </script>
Prompt function
The prompt() method displays a dialog box that prompts the visitor for input. A prompt box is often used if you want the user to input a value before entering a page. When a prompt box pops up, the user will have to click either “OK” or “Cancel” to proceed after entering an input value. Do not overuse this method, as it prevents the user from accessing other parts of the page until the box is closed. The prompt() method returns the input value if the user clicks “OK”. If the user clicks “cancel” the method returns null.
<div class="row"> <div class="col-3"> Prompt </div> <div class="col-4"> <button onclick="showPrompt()" type="button" class="btn btn-outline-primary btn-block">Click Prompt</button> </div> <div class="col-5" id="promptResponse"> </div> </div> <script> function showPrompt(){ // message, defaultValue or defaultAnswer let name = prompt("What's your name?","John Doe"); document.getElementById("promptResponse").innerHTML = "Welcome "+name; } </script>
Confirm function
The confirm() method displays a dialog box with a specified message, along with an OK and a Cancel button. A confirm box is often used if you want the user to verify or accept something. The confirm box takes the focus away from the current window, and forces the browser to read the message. Do not overuse this method, as it prevents the user from accessing other parts of the page until the box is closed. The confirm() method returns true if the user clicked “OK”, and false otherwise.
<div class="row"> <div class="col-3"> Confirmation </div> <div class="col-4"> <button onclick="showConfirmation()" type="button" class="btn btn-outline-primary btn-block">Click Confirmation</button> </div> <div class="col-5" id="confirmationResponse"> </div> </div> <script> function showConfirmation(){ let confirmed = confirm("Delete this post?"); document.getElementById("confirmationResponse").innerHTML = "You said "+(confirmed ? "yes" : "no")+" to deleting the post."; } </script>