If you’re preparing for a Java job interview, you’ll likely be asked a variety of questions about your experience and skills. In this blog post, we’ll go over 20 common Java interview questions and answers to help you prepare for your upcoming interview.
By reviewing these questions and answers, you’ll gain a better understanding of what to expect in your Java job interview and feel more confident in your ability to answer any questions that come your way. Let’s get started!
What is the difference between an interface and an abstract class?
An interface is a contract that defines a set of methods that a class must implement. An interface cannot contain any implementation details, and all methods are implicitly abstract. An abstract class is a class that cannot be instantiated and is typically used to define a common base class that provides some implementation details while leaving other methods to be implemented by subclasses.
// example of an interface
public interface Comparable<T> {
int compareTo(T o);
}
// example of an abstract class
public abstract class AbstractList<E> implements List<E> {
// common implementation details
...
// abstract methods to be implemented by subclasses
public abstract E get(int index);
public abstract int size();
}
What is the difference between overloading and overriding?
Overloading is the practice of defining multiple methods with the same name but different signatures in the same class. Overloading allows you to provide multiple implementations for a method depending on the number and types of arguments. Overriding is the practice of defining a method in a subclass with the same name and signature as a method in the superclass. Overriding allows you to provide a different implementation for a method in the subclass.
// example of overloading
public class Calculator {
public int add(int x, int y) {
return x + y;
}
public double add(double x, double y) {
return x + y;
}
}
// example of overriding
public class Shape {
public void draw() {
// default implementation
}
}
public class Circle extends Shape {
@Override
public void draw() {
// custom implementation for drawing a circle
}
}
Can you explain the difference between checked and unchecked exceptions?
Checked exceptions are exceptions that are checked at compile time and require the programmer to handle them explicitly in the code. Unchecked exceptions are exceptions that are not checked at compile time and do not require the programmer to handle them explicitly in the code. Unchecked exceptions are typically used for programming errors, such as null pointer exceptions, whereas checked exceptions are typically used for recoverable errors, such as input/output errors.
// example of a checked exception
public void readFile(String filename) throws IOException {
FileReader reader = new FileReader(filename);
// handle the exception
}
// example of an unchecked exception
public void divide(int x, int y) {
if (y == 0) {
throw new ArithmeticException("Division by zero");
}
// no need to handle the exception
}
Can you describe the difference between a stack and a queue?
A stack is a data structure that follows the Last In First Out (LIFO) principle, where elements are added to and removed from the top of the stack. A queue is a data structure that follows the First In First Out (FIFO) principle, where elements are added to the end of the queue and removed from the front of the queue. Stacks are commonly used for undo/redo operations and function calls, whereas queues are commonly used for scheduling tasks and processing data in a first-come-first-served manner.
// example of a stack
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
stack.push(3);
stack.pop(); // returns 3
stack.pop(); // returns 2
stack.pop(); // returns 1
// example of a queue
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
queue.add(3);
queue.poll(); // returns 1
queue.poll(); // returns 2
queue.poll(); // returns 3
What is the difference between a final variable and a constant?
A final variable is a variable that cannot be reassigned after it is initialized. A constant is a variable that is declared with the static final
modifier and is typically used to represent a value that never changes, such as a mathematical constant.
// example of a final variable
final int maxAttempts = 3;
// example of a constant
static final double PI = 3.14159265358979323846;
What is the difference between a primitive type and a reference type?
A primitive type is a type that represents a single value, such as a number or a boolean. Primitive types are built-in to the language and are not objects. A reference type is a type that represents a reference to an object, rather than the object itself. Reference types are defined by the programmer and are implemented as classes.
// example of a primitive type
int x = 5;
// example of a reference type
String str = "hello";
Can you explain the difference between a shallow and a deep copy?
A shallow copy is a copy of an object that includes only the values of the object’s properties, without copying the objects that the properties reference. A deep copy is a copy of an object that includes the values of the object’s properties and also creates new objects
// example of a shallow copy
class Point {
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Line {
Point start, end;
public Line(Point start, Point end) {
this.start = start;
this.end = end;
}
public Line shallowCopy() {
return new Line(start, end);
}
}
// create a line with start and end points
Point p1 = new Point(1, 2);
Point p2 = new Point(3, 4);
Line line = new Line(p1, p2);
// create a shallow copy of the line
Line shallowLine = line.shallowCopy();
// modify the original line
line.start.x = 5;
line.end.y = 6;
// the shallow copy is also modified
System.out.println(shallowLine.start.x); // prints 5
System.out.println(shallowLine.end.y); // prints 6
// example of a deep copy
class Line {
Point start, end;
public Line(Point start, Point end) {
this.start = start;
this.end = end;
}
public Line deepCopy() {
return new Line(new Point(start.x, start.y), new Point(end.x, end.y));
}
}
// create a line with start and end points
Point p1 = new Point(1, 2);
Point p2 = new Point(3, 4);
Line line = new Line(p1, p2);
// create a deep copy of the line
Line deepLine = line.deepCopy();
// modify the original line
line.start.x = 5;
line.end.y = 6;
// the deep copy is not modified
System.out.println(deepLine.start.x); // prints 1
System.out.println(deepLine.end.y); // prints 4
What is the difference between a static and a non-static inner class?
A static inner class is a class that is defined within another class and is marked with the static
modifier. A static inner class can access only static members of the outer class and does not have a reference to an instance of the outer class. A non-static inner class, also known as an inner class or an inner object, is a class that is defined within another class and does not have the static
modifier. An inner class has a reference to an instance of the outer class and can access both static and non-static members of the outer class.
// example of a static inner class
class Outer {
static class Inner {
// can access only static members of Outer
}
}
// example of a non-static inner class
class Outer {
class Inner {
// can access both static and non-static members of Outer
}
}
Can you explain the difference between a weak reference and a soft reference?
A weak reference is a reference to an object that does not prevent the object from being garbage collected. A weak reference is typically used to reference objects that are only needed in certain situations but can be safely discarded if the memory is needed by other objects. A soft reference is a reference to an object that is less strongly reachable than a normal reference. A soft reference is typically used to reference objects that are expensive to construct or that are needed by the application but can be discarded if the memory is needed by other objects.
// example of a weak reference
public class Image {
// the object can be garbage collected even if it has a weak reference
WeakReference<Object> data;
public Image(Object data) {
this.data = new WeakReference<>(data);
}
}
// example of a soft reference
public class Cache {
// the object can be garbage collected if it has only soft references
SoftReference<Object> data;
public Cache(Object data) {
this.data = new SoftReference<>(data);
}
}
What is the difference between a tree and a graph data structure?
A tree is a data structure that consists of nodes that are connected by edges. Each node has a parent node, except for the root node, which has no parent. Nodes that have the same parent are called siblings. Nodes can have zero or more child nodes. Trees have a hierarchical structure, where each node can have only one parent and one or more children. Trees are commonly used to represent hierarchical data, such as a file system or a family tree.
A graph is a data structure that consists of vertices (or nodes) that are connected by edges. Graphs do not have a hierarchical structure and can have arbitrary relationships between the vertices. A graph can be directed, where the edges have a specific direction, or undirected, where the edges do not have a specific direction. Graphs are commonly used to represent networks, such as social networks or transportation networks.
// example of a tree
class Node {
String data;
Node parent;
List<Node> children;
public Node(String data, Node parent) {
this.data = data;
this.parent = parent;
this.children = new ArrayList<>();
}
}
// example of a graph
class Vertex {
String data;
List<Vertex> neighbors;
public Vertex(String data) {
this.data = data;
this.neighbors = new ArrayList<>();
}
}
What is the difference between a synchronized block and a synchronized method?
A synchronized block is a block of code that is surrounded by the synchronized
keyword and a mutex object. A synchronized block ensures that only one thread can execute the code at a time, by acquiring the lock on the mutex object. A synchronized method is a method that is marked with the synchronized
keyword. A synchronized method ensures that only one thread can execute the method at a time, by acquiring the lock on the this
object.
// example of a synchronized block
public class Counter {
private int count = 0;
private final Object mutex = new Object();
public void increment() {
synchronized (mutex) {
count++;
}
}
}
// example of a synchronized method
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
}
Can you explain the difference between an Executor and an ExecutorService?
An Executor
is an interface in the java.util.concurrent
package that represents an object that can execute a Runnable
or a Callable
task. An Executor
provides a way to decouple task submission from the mechanics of how each task will be run, including the details of thread use and management. An ExecutorService
is an interface that extends the Executor
interface and adds features that help manage the lifecycle, both of the individual tasks and of the executor itself. An ExecutorService
provides methods to manage termination and methods that can produce a Future
for tracking progress of one or more asynchronous tasks.
// example of an Executor
Executor executor = Executors.newFixedThreadPool(10);
// submit a Runnable task
executor.execute(() -> {
// perform some work
});
// submit a Callable task
Future<Integer> future = executor.submit(() -> {
// perform some work and return a result
return 1;
});
// example of an ExecutorService
ExecutorService executorService = Executors.newFixedThreadPool(10);
// submit a Runnable task
executorService.execute(() -> {
// perform some work
});
// submit a Callable task
Future<Integer> future = executorService.submit(() -> {
// perform some work and return a result
return 1;
});
// check if the executor has been shut down
executorService.isShutdown();
// shut down the executor
executorService.shutdown();
What is the difference between a HashMap and a Hashtable?
A HashMap
is a class that implements the Map
interface and uses a hash table to store the map entries. A HashMap
provides an unordered collection of key-value pairs, where keys are unique and can be null. A HashMap
is not synchronized, which means that it is not thread-safe and must be externally synchronized when used in a multithreaded environment. A Hashtable
is a legacy class that implements the Map
interface and provides an unordered collection of key-value pairs, where keys are unique and cannot be null. A Hashtable
is synchronized, which
Can you describe the difference between a BlockingQueue and a LinkedBlockingQueue?
A BlockingQueue
is an interface in the java.util.concurrent
package that represents a queue that supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element. A BlockingQueue
provides a thread-safe way to transfer and exchange data between threads. A LinkedBlockingQueue
is a class that implements the BlockingQueue
interface and is based on linked nodes. A LinkedBlockingQueue
has an optional capacity, which defines the maximum number of elements that the queue can hold. A LinkedBlockingQueue
is an unbounded queue, unless a capacity is specified.
// example of a BlockingQueue
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// add an element to the queue, waiting if necessary for space to become available
queue.put("hello");
// retrieve and remove the head of the queue, waiting if necessary for an element to become available
String s = queue.take();
What is the difference between the Serializable and Externalizable interfaces?
The Serializable
interface is a marker interface in the java.io
package that is used to indicate that an object can be serialized to a byte stream and deserialized back into an object. The Serializable
interface does not define any methods and is implemented by a class to indicate that its instances can be serialized and deserialized. The Externalizable
interface is a subinterface of the Serializable
interface and provides a more control over the process of serialization and deserialization. The Externalizable
interface defines two methods: writeExternal
and readExternal
, which allows a class to save and restore the state of its instances.
// example of a class that implements the Serializable interface
public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// example of a class that implements the Externalizable interface
public class Person implements Externalizable {
private String name;
private int age;
public Person() {
// default constructor
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// implement the writeExternal method
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(age);
}
// implement the readExternal method
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = in.readUTF();
age = in.readInt();
}
}
Can you explain the difference between a StringBuffer and a StringBuilder?
A StringBuffer
is a class that is used to represent a mutable sequence of characters. A StringBuffer
is similar to a String
, but it can be modified after it is created. A StringBuffer
provides methods to append, insert, delete, and replace characters in the character sequence. A StringBuffer
is thread-safe, because it has synchronized methods that can be accessed by multiple threads without causing a race condition. A StringBuilder
is a class that is similar to a StringBuffer
, but it is not thread-safe. A StringBuilder
provides the same methods as a StringBuffer
, but its methods are not synchronized. A StringBuilder
is faster than a StringBuffer
, but it is not safe to use in a multi-threaded environment.
// example of a StringBuffer
StringBuffer buffer = new StringBuffer("hello");
// append a string to the buffer
buffer.append(" world");
// convert the buffer to a String
String s = buffer.toString();
// example of a StringBuilder
StringBuilder builder = new StringBuilder("hello");
// append a string to the builder
builder.append(" world");
// convert the builder to a String
String s = builder.toString();
What is the difference between a transient variable and a volatile variable?
A transient
variable is a variable that is marked with the transient
keyword and is not serialized when an object containing the variable is serialized. A transient
variable is not part of the persistent state of an object and its value is lost when the object is serialized and deserialized. A volatile
variable is a variable that is marked with the volatile
keyword and is accessed by multiple threads. A volatile
variable ensures that the value of the variable is always up-to-date and visible to all threads, by preventing the compiler from reordering or caching the variable.
// example of a transient variable
public class Person implements Serializable {
private String name;
private transient int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// example of a volatile variable
public class Counter {
private volatile int count = 0;
public void increment() {
count++;
}
}
Can you describe the difference between a LinkedList and an ArrayList?
A LinkedList
is a class that implements the List
interface and is based on linked nodes. A LinkedList
provides a doubly-linked list data structure, where each element is stored in a node that contains a reference to the previous and next element in the list. A LinkedList
provides constant-time insertions and deletions at the beginning and end of the list, but linear-time insertions and deletions in the middle of the list. An ArrayList
is a class that implements the List
interface and is based on an array. An ArrayList
provides a resizable-array data structure, where each element is stored in a contiguous block of memory. An ArrayList
provides constant-time insertions and deletions at the end of the list, but linear-time insertions and deletions in the middle of the list.
// example of a LinkedList
LinkedList<String> list = new LinkedList<>();
// add an element to the beginning of the list
list.add("hello");
// retrieve an element from the list
String s = list.get(0);
// example of an ArrayList
ArrayList<String> array = new ArrayList<>();
// add an element to the array
array.add("hello");
// retrieve an element from the array
String s = array.get(0);
What is the difference between a CopyOnWriteArrayList and a Vector?
A CopyOnWriteArrayList
is a thread-safe implementation of the List
interface that uses copy-on-write semantics. A CopyOnWriteArrayList
is a list that is backed by an array, but the array is never modified. When an element is added to or removed from a CopyOnWriteArrayList
, a new array is created with the updated elements and the reference to the array is atomically updated. A CopyOnWriteArrayList
provides constant-time performance for reads, but linear-time performance for writes. A Vector
is a legacy class that provides a thread-safe implementation of the List
interface that is similar to an ArrayList
, but all of its methods are synchronized. A Vector
is a list that is backed by an array, and the array is modified when elements are added to or removed from the list. A Vector
provides constant-time performance for reads and writes, but its synchronized methods incur a performance overhead.
// example of a CopyOnWriteArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// add an element to the list
list.add("hello");
// retrieve an element from the list
String s = list.get(0);
// example of a Vector
Vector<String> vector = new Vector<>();
// add an element to the vector
vector.add("hello");
// retrieve an element from the vector
String s = vector.get(0);
Can you explain the difference between a TreeSet and a HashSet?
A TreeSet
is a class that implements the Set
interface and is based on a tree data structure. A TreeSet
provides an ordered set of elements, where the elements are sorted according to their natural ordering or according to a Comparator
provided at the time of creation. A TreeSet
does not allow duplicate elements and does not guarantee constant-time performance for the basic operations, such as add
, remove
, and contains
. A HashSet
is a class that implements the Set
interface and is based on a hash table. A HashSet
provides an unordered set of elements, where the elements are hashed according to their hash code and are stored in the hash table using the calculated hash value as the index. A HashSet
does not allow duplicate elements and provides constant-time performance for the basic operations, assuming a good hash function.
// example of a TreeSet
TreeSet<String> set = new TreeSet<>();
// add an element to the set
set.add("hello");
// check if the set contains an element
boolean b = set.contains("hello");
// example of a HashSet
HashSet<String> set = new HashSet<>();
// add an element to the set
set.add("hello");
// check if the set contains an element
boolean b = set.contains("hello");