All Java Interview Questions

What is encapsulation in Java?

Encapsulation is hiding the data of a class and allowing access only through methods. You make the fields private and write public getters and setters, which can check the values.

class Account {
    private double balance;

    public double getBalance() { return balance; }

    public void deposit(double amount) {
        if (amount <= 0) throw new IllegalArgumentException("Amount must be positive");
        balance += amount;
    }
}

public class Main {
    public static void main(String[] args) {
        Account a = new Account();
        a.deposit(500);
        System.out.println(a.getBalance());
    }
}
Output

500.0

Read Java Encapsulation and Access Modifiers.

What are the access modifiers in Java?

ModifierSame classSame packageSubclassOther packages
privateyesnonono
default (no word)yesyesnono
protectedyesyesyesno
publicyesyesyesyes

Use the most restricted level which works. Fields are usually private, and the methods which others must use are public. See Encapsulation.

What is the difference between an array and an ArrayList in Java?

PointArrayArrayList
SizeFixedDynamic
TypesPrimitives and objectsObjects only (use wrappers)
Lengtharr.lengthlist.size()
Add or removeNot possibleadd(), remove()
GenericsNoYes
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[3];
        List<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(20);
        System.out.println(arr.length + " " + list.size());
    }
}
Output

3 2

See Java Arrays and Java ArrayList.

Why is the main method public static void in Java?

The JVM starts a program by calling public static void main(String[] args).

  • public: the JVM is outside your class, so the method must be visible.
  • static: the JVM calls it before any object exists.
  • void: it does not return a value to the JVM.
  • String[] args: the command line arguments.

Since Java 25 you can write a short form for small programs, with no class and no public static:

void main() {
    IO.println("Hello from a compact source file");
}
Output

Hello from a compact source file

See Your First Java Program.

What is garbage collection in Java?

In Java you create objects with new but you never delete them. The garbage collector of the JVM finds the objects that no variable can reach anymore, and frees their memory.

public class Main {
    public static void main(String[] args) {
        Object o = new Object();
        o = null;                  // now nothing points to the first object
        System.gc();               // only a request; the JVM decides
        System.out.println("Done");
    }
}
Output

Done

  • You can not force garbage collection. System.gc() is only a hint.
  • Memory leaks can still happen, for example when a static list keeps growing.

What is a package in Java?

A package groups related classes and interfaces, like folders group files. The first line of the file is package com.shop; and the folder must be com/shop. Packages avoid name clashes and give package level access.

  • java.lang is imported automatically (String, Math).
  • Other packages need an import, like import java.util.List;.

See Java Packages and Imports for a tested example with javac -d.

What is an exception in Java? What are checked and unchecked exceptions?

An exception is an event which stops the normal flow of the program. Java gives an object of the exception, and you can catch it with try and catch.

TypeMust handle?Example
CheckedYes, the compiler forces itIOException, SQLException
Unchecked (RuntimeException)NoNullPointerException, ArithmeticException
ErrorNo, do not catchOutOfMemoryError
public class Main {
    public static void main(String[] args) {
        try {
            System.out.println(10 / 0);
        } catch (ArithmeticException e) {
            System.out.println("Caught: " + e.getMessage());
        } finally {
            System.out.println("finally runs always");
        }
    }
}
Output

Caught: / by zero
finally runs always

See Java Exceptions.

What are autoboxing and unboxing in Java?

Each primitive has a wrapper class: int – Integer, double – Double, boolean – Boolean. Java converts between them by itself:

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Integer boxed = 5;                // autoboxing
        int plain = boxed;                // unboxing

        List<Integer> list = new ArrayList<>();
        list.add(10);                     // autoboxing
        int first = list.get(0);          // unboxing
        System.out.println(boxed + plain + first);

        Integer a = 127, b = 127, c = 1000, d = 1000;
        System.out.println(a == b);       // true: small values are cached
        System.out.println(c == d);       // false: different objects
        System.out.println(c.equals(d));
    }
}
Output

20
true
false
true

Compare wrapper objects with equals(), not with ==. Unboxing a null gives a NullPointerException.

What is a JAR file in Java and how to create one?

A JAR (Java ARchive) file is a ZIP file which holds compiled .class files, resources and a manifest. It is the normal way to share a Java library or an application.

public class Hello {
    public static void main(String[] args) {
        System.out.println("Running from a JAR");
    }
}
Terminal

$ javac Hello.java
$ jar cfe app.jar Hello Hello.class
$ java -jar app.jar
Running from a JAR
$ jar tf app.jar
META-INF/
META-INF/MANIFEST.MF
Hello.class

  • c create, f file name, e entry point (the class with main).
  • jar tf lists the content of a JAR.

Real projects use Maven or Gradle to build the JAR.

How does HashMap work internally in Java?

A HashMap is an array of buckets. When you call put(key, value):

  1. Java calls key.hashCode() and spreads the bits of the hash.
  2. The bucket index is found from the hash and the array length (the default size is 16).
  3. If the bucket is empty, the entry is stored there. If not, Java walks the bucket and uses equals() to find the same key. If it finds one, the value is replaced, if not the new entry is added.
  4. When the number of entries goes above capacity x load factor (0.75), the array is doubled and the entries are moved (rehashing).
  5. When one bucket gets long (8 or more entries, and the table has 64 or more buckets), the linked list becomes a balanced tree, so the search stays fast.

So the keys need a good hashCode() and a matching equals(). Even with a very bad hash code the map still gives right answers, only slow:

import java.util.HashMap;
import java.util.Map;

public class Main {
    static class BadKey {
        final int id;
        BadKey(int id) { this.id = id; }
        @Override public int hashCode() { return 1; }                     // all keys in one bucket
        @Override public boolean equals(Object o) { return o instanceof BadKey b && b.id == id; }
    }

    public static void main(String[] args) {
        Map<BadKey, String> map = new HashMap<>();
        for (int i = 0; i < 1000; i++) {
            map.put(new BadKey(i), "value" + i);
        }
        System.out.println(map.size());
        System.out.println(map.get(new BadKey(777)));
    }
}
Output

1000
value777

See Java HashMap.

What is the difference between HashMap, Hashtable and ConcurrentHashMap?

PointHashMapHashtableConcurrentHashMap
Thread safeNoYes (locks the whole table)Yes (fine grained locks)
Null keyOne allowedNot allowedNot allowed
Null valuesAllowedNot allowedNot allowed
SpeedFastest (one thread)SlowFast with many threads
UseNormal codeOld code onlyShared data between threads
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Main {
    static void tryNull(String name, Map<String, String> map) {
        try {
            map.put(null, "x");
            System.out.println(name + ": null key allowed");
        } catch (NullPointerException e) {
            System.out.println(name + ": null key NOT allowed");
        }
    }

    public static void main(String[] args) {
        tryNull("HashMap", new HashMap<>());
        tryNull("Hashtable", new Hashtable<>());
        tryNull("ConcurrentHashMap", new ConcurrentHashMap<>());
    }
}
Output

HashMap: null key allowed
Hashtable: null key NOT allowed
ConcurrentHashMap: null key NOT allowed

Why must you override both equals() and hashCode() in Java?

The contract: equal objects must have the same hash code. If you override equals() but not hashCode(), two equal objects get different hash codes, and a HashSet keeps both:

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class Main {
    static class Bad {
        final String name;
        Bad(String name) { this.name = name; }
        @Override public boolean equals(Object o) { return o instanceof Bad b && b.name.equals(name); }
    }

    static class Good {
        final String name;
        Good(String name) { this.name = name; }
        @Override public boolean equals(Object o) { return o instanceof Good g && g.name.equals(name); }
        @Override public int hashCode() { return Objects.hash(name); }
    }

    public static void main(String[] args) {
        Set<Bad> bad = new HashSet<>();
        bad.add(new Bad("Riya"));
        bad.add(new Bad("Riya"));
        System.out.println("Without hashCode: " + bad.size());     // wrong: 2

        Set<Good> good = new HashSet<>();
        good.add(new Good("Riya"));
        good.add(new Good("Riya"));
        System.out.println("With hashCode: " + good.size());       // right: 1
    }
}
Output

Without hashCode: 2
With hashCode: 1

The easy way: use a record, which writes both methods for you (Java Records).

How to create an immutable class in Java?

  1. Declare the class final (no subclass can break it).
  2. Make all fields private final.
  3. Do not write setters.
  4. Set all fields in the constructor.
  5. For mutable fields (like a list or a date) make a defensive copy when you get it and when you return it.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    static final class Team {
        private final String name;
        private final List<String> members;

        Team(String name, List<String> members) {
            this.name = name;
            this.members = List.copyOf(members);           // copy in
        }

        String name() { return name; }
        List<String> members() { return members; }          // List.copyOf is already unmodifiable
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("Riya", "Aman"));
        Team t = new Team("Java", list);
        list.add("Hacker");                                 // does not change the team
        System.out.println(t.members());
        try {
            t.members().add("Another");
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot change the members");
        }
    }
}
Output

[Riya, Aman]
Cannot change the members

A record is the shortest way, if you only need the data and you copy the mutable parts yourself. See Java Records.

What is the difference between final, finally and finalize in Java?

NameKindMeaning
finalKeywordA constant variable, a method which can not be overridden, a class which can not be extended
finallyBlockRuns after try and catch, with or without an exception. For cleaning
finalize()MethodCalled by the GC before it removes an object. Deprecated for removal, do not use it

Use try with resources or a Cleaner instead of finalize().

public class Main {
    static int test() {
        try {
            return 1;
        } finally {
            System.out.println("finally runs, even after return");
        }
    }

    public static void main(String[] args) {
        final int limit = 10;
        System.out.println(limit + " " + test());
    }
}
Output

finally runs, even after return
10 1

See Java Exceptions.

What is the difference between stack and heap memory in Java?

PointStackHeap
KeepsMethod calls, local variables, referencesObjects and arrays
PerOne stack for each threadOne heap shared by all threads
CleanedWhen the method endsBy the garbage collector
SizeSmallBig
Error when fullStackOverflowErrorOutOfMemoryError
public class Main {
    static void recurse(int n) {
        recurse(n + 1);
    }

    public static void main(String[] args) {
        int local = 5;                               // on the stack
        String s = new String("object");            // the object is on the heap, the reference s on the stack

        try {
            recurse(1);
        } catch (StackOverflowError e) {
            System.out.println("Stack is full: StackOverflowError");
        }
        System.out.println(local + " " + s);
    }
}
Output

Stack is full: StackOverflowError
5 object

Size options: -Xss for the stack and -Xmx for the maximum heap. See Java Recursion.

What is the string pool in Java and what does intern() do?

Equal string literals share one object from the string pool. A string made with new is a separate object on the heap. intern() returns the pooled version.

public class Main {
    public static void main(String[] args) {
        String a = "java";
        String b = "java";
        String c = new String("java");
        String d = c.intern();

        System.out.println(a == b);       // same pooled object
        System.out.println(a == c);       // c is a different object
        System.out.println(a == d);       // intern gives the pooled one
        System.out.println("ja" + "va" == a);     // joined at compile time: pooled
    }
}
Output

true
false
true
true

Always compare content with equals(). See Java Strings.

What is the difference between Comparable and Comparator in Java?

PointComparableComparator
Packagejava.langjava.util
MethodcompareTo(T other)compare(T a, T b)
WhereInside the classA separate object or lambda
OrdersOne natural orderMany orders
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
    record Student(String name, int marks) implements Comparable<Student> {
        @Override
        public int compareTo(Student other) {
            return this.name.compareTo(other.name);      // natural order: by name
        }
    }

    public static void main(String[] args) {
        List<Student> list = new ArrayList<>(List.of(new Student("Meera", 95), new Student("Aman", 72), new Student("Riya", 88)));

        java.util.Collections.sort(list);                        // uses compareTo
        System.out.println(list);

        list.sort(Comparator.comparingInt(Student::marks).reversed());   // another order
        System.out.println(list);
    }
}
Output

[Student[name=Aman, marks=72], Student[name=Meera, marks=95], Student[name=Riya, marks=88]]
[Student[name=Meera, marks=95], Student[name=Riya, marks=88], Student[name=Aman, marks=72]]

What is the difference between ArrayList and LinkedList in Java?

PointArrayListLinkedList
InsideResizable arrayDoubly linked nodes
Get by indexFast, O(1)Slow, O(n)
Add at the endFast (usually)Fast
Add or remove at the startSlow, O(n)Fast, O(1)
MemoryLessMore (each node has two links)
Also a DequeNoYes

In practice ArrayList is the better choice for almost all cases, because of its simple memory layout. For a queue or a stack use ArrayDeque. See Java HashSet and LinkedList.

What is the difference between fail-fast and fail-safe iterators?

Fail-fast iterators (ArrayList, HashMap) check a modification counter and throw ConcurrentModificationException when the collection is changed in the loop. Fail-safe (weakly consistent) iterators, like those of CopyOnWriteArrayList and ConcurrentHashMap, do not throw.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class Main {
    public static void main(String[] args) {
        List<Integer> failFast = new ArrayList<>(List.of(1, 2, 3, 4));
        try {
            for (Integer n : failFast) {
                if (n == 1) failFast.add(99);
            }
        } catch (java.util.ConcurrentModificationException e) {
            System.out.println("ArrayList: ConcurrentModificationException");
        }

        List<Integer> failSafe = new CopyOnWriteArrayList<>(List.of(1, 2, 3, 4));
        for (Integer n : failSafe) {
            if (n == 1) failSafe.add(99);
        }
        System.out.println("CopyOnWriteArrayList: " + failSafe);
    }
}
Output

ArrayList: ConcurrentModificationException
CopyOnWriteArrayList: [1, 2, 3, 4, 99]

To remove items while looping, use removeIf() or the remove() of the iterator.

What is type erasure in Java generics?

Generics are checked by the compiler, and then the type arguments are erased. At run time a List<String> is only a List. This keeps old code working, but it has effects:

  • You can not write new T(), T.class or instanceof List<String>.
  • You can not make an array of a generic type: new List<String>[10].
  • Primitives are not allowed as type arguments.
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> strings = new ArrayList<>();
        List<Integer> numbers = new ArrayList<>();
        System.out.println(strings.getClass() == numbers.getClass());
        System.out.println(strings.getClass().getName());
    }
}
Output

true
java.util.ArrayList

See Java Generics.