// Java Interview โ€” Senior Level

โ˜• PART 1: Java Basics & Fundamentals (Q1โ€“45)

Core Java concepts, OOP fundamentals, memory model, and language basics every Java developer must know.

59 Questions
2 Basic
31 Mid
2 Advanced
10 Expert
01 What are the main features of Java? EXPERT

Java is built around several core design goals:

Platform Independence โ€“ Write Once, Run Anywhere (WORA). Java compiles to bytecode which runs on any JVM regardless of OS/hardware.

Object-Oriented โ€“ Everything (except primitives) is an object. Supports encapsulation, inheritance, polymorphism, abstraction.

Strongly Typed โ€“ Every variable must be declared with a type; no implicit type coercion between incompatible types.

Automatic Memory Management โ€“ Garbage Collector handles heap memory; developers don't call free().

Multi-threaded โ€“ Built-in thread support via java.lang.Thread and java.util.concurrent.

Robust โ€“ Exception handling, null safety (to an extent), array bounds checking prevent common bugs.

Secure โ€“ No pointer arithmetic, bytecode verification, SecurityManager (deprecated in Java 17+), sandboxed classloading.

Distributed โ€“ RMI, sockets, networking APIs built-in.

High Performance โ€“ JIT compilation optimizes hot code paths at runtime (C1/C2 compilers).

Interpreted + Compiled โ€“ Bytecode is interpreted by JVM, but JIT compiles hotspots to native code.

At senior/10-year level, you should also mention Java's ecosystem maturity: Spring, Maven/Gradle, vast library support, LTS releases, corporate backing (Oracle + OpenJDK community).

02 Why is Java platform-independent? EXPERT

Java source code (.java) is compiled by javac into bytecode (.class files), not into native machine code. Bytecode is a low-level, intermediate representation that is architecture-neutral.

The JVM (Java Virtual Machine) is platform-specific โ€“ there are different JVM implementations for Windows, Linux, macOS, ARM, x86. The JVM is the abstraction layer that interprets or JIT-compiles bytecode into native instructions specific to that platform.

So:

  • Source code โ†’ bytecode (platform-independent)
  • Bytecode โ†’ native code (done by JVM at runtime, platform-specific)

Important nuance at senior level: The JVM itself is NOT platform-independent โ€“ it's written in C/C++ and compiled per platform. It's the bytecode that is portable. Also, native code (via JNI/JNA) breaks this portability.

03 What is the difference between JDK, JRE, and JVM? EXPERT

JVM (Java Virtual Machine)

  • Abstract computing machine that executes bytecode
  • Manages memory (heap, stack, metaspace), GC, JIT compilation
  • Just an execution engine; it cannot compile Java source code

JRE (Java Runtime Environment)

  • JVM + standard class libraries (java.lang, java.util, java.io, etc.)
  • Everything needed to run a Java application
  • Does NOT include compiler (javac)
  • In Java 9+, modular JRE concept; separate JRE distributions are largely deprecated in favor of custom runtimes with jlink

JDK (Java Development Kit)

  • JRE + development tools: javac, javadoc, jdb, jar, jshell, profilers, etc.
  • Everything needed to develop and run Java applications
  • What developers install

Hierarchy: JDK โŠƒ JRE โŠƒ JVM

Note: In Java 9+, the JDK no longer ships a separate JRE folder. The distinction is more conceptual.

04 Explain bytecode. EXPERT

Bytecode is the compiled output of Java source code, stored in .class files. It is:

  • A set of instructions for the Java Virtual Machine (not for any physical CPU)
  • Binary format (not human-readable, but disassemblable with javap -c)
  • Platform-neutral: the same .class file runs on Windows, Linux, macOS
  • More compact and faster to execute than re-interpreting source code

When the JVM starts:

  1. ClassLoader loads .class files
  2. Bytecode verifier checks for safety (no illegal operations, type violations)
  3. JVM interprets bytecode OR the JIT compiler compiles frequently-executed ("hot") methods to native machine code

Example: javap -c HelloWorld.class shows bytecode instructions like invokevirtual, getstatic, ldc, iload, iadd.

Bytecode also enables tools like AspectJ (weaving), byte-buddy, ASM to modify class behavior at load time or build time.

05 What is the Java execution flow? EXPERT
1. Write: HelloWorld.java
2. Compile: javac HelloWorld.java โ†’ HelloWorld.class (bytecode)
3. Classloading: JVM's ClassLoader loads .class file
4. Bytecode Verification: Verifier checks legality
5. Execution:
   a. Interpreter: JVM interprets bytecode line by line (slow at start)
   b. JIT Compilation: HotSpot detects hot methods โ†’ C1 (client) โ†’ C2 (server) compilation
   c. Optimized native code runs directly on CPU
6. GC: Manages heap objects throughout lifetime
7. JVM shutdown: Runtime.getRuntime().addShutdownHook() callbacks, finalizers (deprecated)

At senior level: mention tiered compilation (Java 8+). Methods start interpreted, promoted to C1 (fast compile, limited optimization), then C2 (slow compile, heavy optimization) based on profiling counters.

06 Why is Java strongly typed? MID

Java is strongly typed because:

  • Every variable, parameter, return value must have a declared type
  • The compiler enforces type correctness at compile time
  • No implicit coercions between unrelated types (e.g., you can't assign a String to an int without explicit conversion)

Benefits:

  • Early error detection: type errors caught at compile time, not runtime
  • IDE support: autocomplete, refactoring, find usages all rely on type info
  • Performance: JVM can optimize knowing exact types
  • Readability: types serve as documentation

Java is NOT perfectly type-safe โ€“ raw types (pre-generics), casts, and reflection can bypass type checking. That's why generics were added in Java 5 and @SuppressWarnings("unchecked") exists.

Strong vs Static: Java is both. Strongly typed = strict enforcement. Statically typed = types known at compile time (vs dynamically typed like Python where types are checked at runtime).

07 What are access modifiers? BASIC

Access modifiers control visibility of classes, fields, methods, constructors.

ModifierSame ClassSame PackageSubclass (diff pkg)Everywhere
privateโœ…โŒโŒโŒ
defaultโœ…โœ…โŒโŒ
protectedโœ…โœ…โœ…โŒ
publicโœ…โœ…โœ…โœ…

Key senior points:

  • Default (package-private) is often the right choice for internal implementation classes
  • protected is primarily for inheritance โ€“ use sparingly (violates encapsulation)
  • Outer classes can only be public or default; inner classes can be any
  • Java modules (Java 9+) add another layer: exports in module-info.java controls which packages are accessible even if public
08 Difference between public, protected, default, and private? MID

See table above. Key distinctions:

private: Tightest scope. Used for fields to enforce encapsulation. Inner classes can access outer class private members.

default (package-private): No keyword. Useful for classes/methods meant to be used only within a package. Common in well-structured libraries.

protected: Confusing for beginners. Allows subclass access, but only to the subclass's own inherited members, not to other instances of the parent class in a different package.

// In different package:
class Child extends Parent {
    void method(Parent p, Child c) {
        p.protectedField; // ILLEGAL - different package, p is not 'this'
        c.protectedField; // LEGAL - c is a Child instance
        this.protectedField; // LEGAL
    }
}

public: API surface. Think carefully before making anything public โ€“ it becomes a contract.

09 What is a package? MID

A package is a namespace that organizes related classes and interfaces. It maps to a directory structure on the filesystem.

package com.company.service;

Packages serve to:

  1. Organize code logically (domain, layer, feature)
  2. Prevent naming conflicts โ€“ two classes can have the same name if in different packages
  3. Control access โ€“ package-private (default) access
  4. Enable selective imports

Naming convention: reverse domain name (com.google.guava, org.springframework.core).

In Java 9+, packages are further organized into modules (module-info.java). A module controls which packages it exports.

10 Why use packages? MID
  • Modularity: group related functionality
  • Encapsulation at package level: package-private classes/methods hide implementation details
  • Avoid name collisions: com.company.util.StringUtils vs org.apache.commons.lang3.StringUtils
  • Build tools: Maven/Gradle use package structure to organize compilation units
  • Javadoc: packages are the unit of documentation
  • Java modules (9+): packages are the unit of module export

Design principle: packages should be cohesive (related classes together) and loosely coupled (minimal cross-package dependencies). Tools like JDepend, ArchUnit can validate this.

11 What is classpath? EXPERT

The classpath tells the JVM where to look for .class files and JARs at runtime (and javac at compile time).

java -cp ".:./lib/*:./build/classes" com.example.Main

Classpath elements:

  • Directories containing .class files
  • JAR files
  • ZIP files

In modern development, build tools (Maven, Gradle) manage the classpath automatically. Spring Boot's fat JAR bundles all dependencies with a custom classloader.

Issues with classpath:

  • Classpath hell: multiple JARs with same class โ€“ first one on classpath wins
  • ClassNotFoundException: class not found on classpath
  • NoClassDefFoundError: class was present at compile time but missing at runtime

Java 9+ modules replace classpath with the module path, providing stronger isolation.

12 What is an object? MID

An object is an instance of a class โ€“ a runtime entity that has:

  • State (fields/instance variables)
  • Behavior (methods)
  • Identity (unique reference/address in heap memory)
Person person = new Person("Alice", 30);
// person -> reference (on stack or as field)
// Person object -> lives on heap

Under the hood: new allocates memory on the heap, calls the constructor, returns a reference. The reference is stored on the stack (for local variables) or in another heap object (for fields).

Object layout in JVM (HotSpot):

  • Mark word (8 bytes): GC info, lock state, hash code
  • Class pointer (4-8 bytes): points to Class metadata
  • Instance fields: actual field values
  • Padding: alignment to 8-byte boundaries
13 Difference between class and object? MID
ClassObject
Blueprint/templateInstance of a class
Defined at compile timeCreated at runtime
Exists once (per ClassLoader)Can have many instances
Stored in MetaspaceStored in Heap
class Person {}new Person()

A class defines what an object is (structure, behavior). An object is an actual thing with actual data.

Class itself is an object in Java: Person.class is a java.lang.Class instance, also stored in Metaspace.

14 What is encapsulation? ADVANCED

Encapsulation is the bundling of data (fields) and methods that operate on that data within a class, while hiding the internal state from outside access.

Implementation:

  • Fields are private
  • Access via public getters/setters (with validation if needed)
  • Internal implementation can change without affecting callers
public class BankAccount {
    private double balance; // hidden
    
    public void deposit(double amount) {
        if (amount <= 0) throw new IllegalArgumentException();
        this.balance += amount;
    }
    
    public double getBalance() { return balance; }
}

Benefits:

  1. Control: validate data before setting (no account.balance = -1000)
  2. Flexibility: change internal representation without breaking API
  3. Maintainability: localized changes

Senior note: Records (Java 16+) are immutable data carriers โ€“ they encapsulate data without traditional setters. Lombok's @Value achieves similar. Encapsulation doesn't always mean getter/setter โ€“ it means controlled access.

15 What is inheritance? MID

Inheritance allows a class (subclass/child) to acquire properties and behaviors of another class (superclass/parent).

public class Vehicle {
    protected String brand;
    public void start() { System.out.println("Starting " + brand); }
}

public class Car extends Vehicle {
    private int doors;
    
    @Override
    public void start() {
        super.start();
        System.out.println("Car started with " + doors + " doors");
    }
}

Java supports single inheritance for classes (unlike C++), but multiple inheritance for interfaces.

Types in Java:

  • Single: A extends B
  • Multilevel: A extends B, B extends C
  • Hierarchical: B extends A, C extends A
  • No multiple class inheritance (diamond problem avoided)

When NOT to use inheritance: "Is-A" relationship must be genuine. Stack extends Vector in Java is a famous mistake (a Stack is NOT a Vector from behavioral standpoint). Prefer composition.

IS-A test: Can you substitute subclass wherever superclass is expected? (Liskov Substitution Principle)

16 What is polymorphism? MID

Polymorphism means "many forms" โ€“ the ability of a reference to behave differently based on the actual object it points to.

Compile-time polymorphism (static dispatch): Method overloading

void print(int x) {}
void print(String s) {}
// Resolved at compile time based on argument types

Runtime polymorphism (dynamic dispatch): Method overriding

Animal animal = new Dog(); // Animal reference, Dog object
animal.speak(); // calls Dog.speak(), not Animal.speak()
// Resolved at runtime via virtual method table (vtable)

Under the hood: JVM uses virtual method tables (vtable). Each object has a pointer to its class's vtable, which maps method signatures to actual implementations.

Polymorphism enables Open/Closed Principle: add new behavior (new subclass) without modifying existing code that works with the base type.

Covariant return types (Java 5+): overriding method can return a subtype.

17 What is abstraction? MID

Abstraction means hiding implementation complexity and exposing only essential features.

Two mechanisms in Java:

  1. Abstract classes (0โ€“100% abstract)
  2. Interfaces (100% abstract pre-Java 8; can have defaults now)
// Abstract class
public abstract class Shape {
    abstract double area(); // must be implemented
    
    void printArea() { // concrete method
        System.out.println("Area: " + area());
    }
}

// Interface
public interface Drawable {
    void draw(); // abstract
    default void drawWithBorder() { draw(); } // default
}

Abstraction at design level: programming to interfaces, not implementations. List<String> list = new ArrayList<>() โ€“ caller doesn't need to know it's an ArrayList.

Abstraction is about "what" not "how". Encapsulation is about hiding "how".

18 Difference between method overloading and overriding? MID
AspectOverloadingOverriding
DefinitionSame name, different parametersSame signature in subclass
ResolutionCompile time (static dispatch)Runtime (dynamic dispatch)
InheritanceNot requiredRequired
Return typeCan differMust be same or covariant
Access modifierCan differ freelyCan't be more restrictive
Static methodsCan be overloadedCannot be overridden (hidden)
ExceptionNo restrictionCan't add new checked exceptions

Overloading pitfall: Widening + autoboxing + varargs precedence rules are complex:

void test(long x) {}
void test(Integer x) {}
test(5); // calls test(long) - widening takes priority over autoboxing

Overriding rules:

  • @Override annotation is highly recommended (compile-time check)
  • private, static, final methods cannot be overridden
  • Overriding method can't throw broader checked exceptions
  • Covariant return types allowed (return subtype)
19 What is static keyword? MID

static means the member belongs to the class, not to any instance.

Static fields: Shared across all instances; one copy per class

public class Counter {
    private static int count = 0; // class-level
    public Counter() { count++; }
    public static int getCount() { return count; }
}

Static methods: Can be called without instance; can only access static members directly

Static blocks: Run once when class is loaded

Static inner classes: No reference to outer class instance

Static imports: import static java.lang.Math.PI;

Memory: Static fields stored in Metaspace (Java 8+), not heap. (In Java 7 and earlier, in PermGen.)

Use cases: utility methods (Math, Collections), constants, factory methods, Singleton pattern, counters.

Pitfalls: Static state is shared globally โ†’ thread safety issues, harder to test (can't inject mock), memory leaks (static collections holding references).

20 Can a static method be overridden? BASIC

No. Static methods cannot be overridden โ€“ they can only be hidden.

class Parent {
    static void greet() { System.out.println("Parent"); }
}
class Child extends Parent {
    static void greet() { System.out.println("Child"); } // HIDING, not overriding
}

Parent p = new Child();
p.greet(); // Prints "Parent" -- resolved at compile time based on reference type

This is method hiding, not overriding. Static methods are resolved at compile time based on the reference type, not at runtime based on the object type.

@Override on a static method causes a compile error.

Why? Runtime polymorphism (dynamic dispatch) requires a vtable lookup based on the object's actual class. Static methods are bound to the class, not the object โ€“ there's no vtable involvement.

21 Why is main() static? EXPERT

main() is static so the JVM can invoke it without creating an instance of the class.

When the JVM starts, it:

  1. Loads the class
  2. Calls public static void main(String[] args) directly

If main() were an instance method, the JVM would need to instantiate the class first โ€“ but which constructor to call? What arguments? By making it static, this bootstrapping problem is avoided.

Note (Java 21+): With unnamed classes (JEP 445, preview), you can write:

void main() {
    System.out.println("Hello");
}

The JVM handles the static entrypoint transparently. But in standard Java, public static void main(String[] args) is required.

22 What is a constructor? MID

A constructor is a special method used to initialize an object when it is created with new.

Properties:

  • Same name as the class
  • No return type (not even void)
  • Called automatically by new
  • Can be overloaded (multiple constructors)
  • Can call other constructors with this() or super() (must be first statement)
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Delegating constructor
    public Person(String name) {
        this(name, 0); // calls above constructor
    }
}

If no constructor is defined, the compiler adds a default no-arg constructor. If any constructor is defined, the default is NOT added.

Constructors are NOT inherited. Subclass constructor must call super(...) explicitly or the compiler inserts super() (which requires a no-arg parent constructor).

23 Constructor vs method? MID
ConstructorMethod
Same name as classAny valid name
No return typeMust have return type
Called by newCalled on object/class
Used for initializationUsed for behavior
Not inheritedInherited (if not private)
Not called on existing objectCalled on existing object
this()/super() allowedNot applicable

Constructors ARE methods in bytecode terms (they appear as <init> in the class file). The JVM invokes them via invokespecial.

Static initializer blocks (static {}) run before the constructor, at class loading time.

24 Types of constructors? MID
  1. Default constructor: No-arg, inserted by compiler if none defined
class Foo {} // compiler adds: Foo() { super(); }
  1. No-arg constructor: Explicitly written with no parameters
class Foo { public Foo() { init(); } }
  1. Parameterized constructor: Takes arguments
class Foo { public Foo(String name, int value) {} }
  1. Copy constructor: Takes an instance of the same class
class Foo {
    String data;
    public Foo(Foo other) { this.data = other.data; }
}

Java doesn't have built-in copy constructor support (unlike C++), but it's a common pattern.

  1. Private constructor: Prevents instantiation (Singleton, utility classes)
class MathUtils { private MathUtils() {} }
25 What is this keyword? MID

this refers to the current instance of the class.

Uses:

  1. Disambiguate field vs parameter:
public Person(String name) { this.name = name; }
  1. Call another constructor (this() โ€“ must be first statement):
public Person() { this("Unknown", 0); }
  1. Pass current instance to another method/constructor:
EventBus.register(this);
  1. Return current instance (method chaining / fluent API):
public Builder name(String n) { this.name = n; return this; }

this is implicit in all instance method calls and field accesses. It's a reference stored in the local variable slot 0 of every instance method.

this cannot be used in static context (no instance exists).

26 What is super keyword? MID

super refers to the parent class (immediate superclass).

Uses:

  1. Access parent class field (when shadowed by subclass):
class Parent { String name = "Parent"; }
class Child extends Parent {
    String name = "Child";
    void print() { System.out.println(super.name); } // "Parent"
}
  1. Call parent class method (when overridden):
@Override
public String toString() {
    return super.toString() + " [extended]";
}
  1. Call parent constructor (super() โ€“ must be first statement in constructor):
public Dog(String name) {
    super(name); // calls Animal(String name)
}

If subclass constructor doesn't call super(...), compiler inserts super() (no-arg) automatically. If parent has no no-arg constructor, compile error.

super cannot be used in static context.

27 What is a final variable? MID

A final variable can be assigned only once.

Types:

  1. final local variable: Must be assigned before use; can be assigned in any branch as long as it's assigned exactly once
  2. final instance variable: Must be assigned in constructor or initializer; effectively makes the reference constant (not the object it points to)
  3. final static variable (constant): public static final double PI = 3.14159;
final List<String> list = new ArrayList<>();
list.add("item"); // OK - modifying the object
list = new LinkedList<>(); // COMPILE ERROR - can't reassign reference

Blank final: private final int x; โ€“ assigned in constructor. Allows different values per instance while being immutable after construction.

JVM optimization: final fields get special treatment in Java Memory Model โ€“ their values are guaranteed to be visible to all threads without synchronization after the constructor completes (as long as this doesn't escape).

28 What happens if a class is final? MID

A final class cannot be subclassed.

public final class String { ... }
public final class Integer { ... }

Uses:

  1. Security: Prevents malicious subclassing (someone overriding sensitive methods)
  2. Immutability: String's immutability relies on it being final (can't subclass and add mutability)
  3. Performance: JVM can devirtualize method calls (no vtable lookup needed)
  4. API stability: Express that the class is a leaf in the hierarchy

All methods of a final class are implicitly final (they can't be overridden since there are no subclasses).

Sealed classes (Java 17+) are a more nuanced alternative: restrict which classes can extend, rather than completely prohibiting extension.

29 Can constructors be final? MID

No. Constructors cannot be final, static, or abstract.

Reasoning:

  • final prevents overriding, but constructors aren't inherited and can't be overridden anyway
  • static is meaningless since constructors are always tied to instance creation
  • abstract requires implementation in subclass, but constructors aren't inherited

If you want to prevent subclassing (which is what you might think final constructor achieves), make the class final.

If you want to prevent instantiation, make the constructor private.

30 What is an immutable object? MID

An immutable object's state cannot change after construction.

How to make a class immutable:

  1. Declare class final (prevent subclass from adding mutability)
  2. All fields private final
  3. No setters
  4. Constructor performs deep copy of mutable inputs
  5. Accessors return defensive copies of mutable fields
  6. Don't allow this to escape during construction
public final class Money {
    private final BigDecimal amount;
    private final Currency currency;
    
    public Money(BigDecimal amount, Currency currency) {
        this.amount = Objects.requireNonNull(amount);
        this.currency = Objects.requireNonNull(currency);
    }
    
    public BigDecimal getAmount() { return amount; }
    public Currency getCurrency() { return currency; }
    
    public Money add(Money other) {
        // Return new instance instead of modifying
        return new Money(this.amount.add(other.amount), this.currency);
    }
}

Benefits: inherently thread-safe, can be freely shared, safe as HashMap key, easier to reason about.

Java examples: String, Integer, BigDecimal, LocalDate, InetAddress.

Records (Java 16+) make immutable data carriers concise.

31 Why is String immutable? EXPERT

String immutability is a deliberate design decision with multiple motivations:

  1. String Pool optimization: JVM maintains a pool of String literals. If Strings were mutable, changing one reference's string would affect all references pointing to the same pool object.
  1. Thread safety: Immutable objects are inherently thread-safe. Strings are shared across threads constantly (class names, log messages, etc.).
  1. HashMap/HashSet keys: String's hashCode is cached. If String were mutable, changing a String key would make it un-findable in a HashMap (the bucket would be wrong).
  1. Security: Filenames, class names, network connections โ€“ if a String passed to a security check could be mutated, the check could be bypassed.
  1. ClassLoader integrity: Class names are Strings. Mutable class names could break the loading mechanism.

Implementation: String stores characters in a private final char[] (Java 8) or private final byte[] (Java 9+, compact strings). The array is private and never returned directly.

For mutable string operations: use StringBuilder (not thread-safe, faster) or StringBuffer (thread-safe, slower).

32 Difference between == and .equals()? MID

==: Compares references (memory addresses) for objects, or values for primitives.

String a = new String("hello");
String b = new String("hello");
a == b; // false - different objects on heap

.equals(): Compares logical equality (content), as defined by the class's equals() implementation.

a.equals(b); // true - same content

String pool trap:

String x = "hello"; // pool
String y = "hello"; // same pool object
x == y; // true (same reference, pool optimization)
x == new String("hello"); // false

Default Object.equals() is the same as ==. Classes must override it for meaningful equality.

null handling: "hello".equals(null) returns false (safe); null.equals("hello") throws NPE. Use Objects.equals(a, b) for null-safe comparison.

33 Why override hashCode() when overriding equals()? MID

The general contract (from java.lang.Object Javadoc):

  • If a.equals(b) is true, then a.hashCode() == b.hashCode() MUST be true
  • If a.hashCode() != b.hashCode(), then a.equals(b) MUST be false
  • Equal objects must produce the same hash code

What breaks if you don't?

HashMap, HashSet, Hashtable use hashCode() to find the bucket, then equals() to find the exact key:

Map<Person, String> map = new HashMap<>();
Person p1 = new Person("Alice", 30);
map.put(p1, "Engineer");

Person p2 = new Person("Alice", 30); // "equal" to p1
map.get(p2); // returns null if hashCode not overridden!
// p2.hashCode() != p1.hashCode() โ†’ different bucket โ†’ not found

Best practice for hashCode():

  • Use all fields used in equals()
  • Use Objects.hash(field1, field2, ...) (easy but slightly slower)
  • Or manual: 31 * result + field.hashCode() (31 is a prime, reduces collisions)
  • IDEs and Lombok can generate these
34 What are wrapper classes? MID

Wrapper classes wrap primitive types into objects.

PrimitiveWrapper
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

Why needed:

  1. Generics require objects (List<Integer>, not List<int>)
  2. Null value: primitives can't be null; wrappers can
  3. Utility methods: Integer.parseInt(), Integer.toBinaryString(), Double.isNaN()
  4. Collections: Only work with objects
  5. Reflection: Method parameters/return types use wrapper classes

Wrapper classes are immutable and have a cache:

  • Integer.valueOf(int) caches values from -128 to 127 (configurable via -XX:AutoBoxCacheMax)
  • Same for Byte, Short, Long, Character (0โ€“127)
  • Boolean.TRUE and Boolean.FALSE are singletons
Integer a = 127; Integer b = 127; a == b; // true (cached)
Integer c = 128; Integer d = 128; c == d; // false (not cached)
35 Autoboxing vs unboxing? MID

Autoboxing: Automatic conversion from primitive to wrapper by the compiler.

Integer x = 5; // compiler: Integer x = Integer.valueOf(5);
List<Integer> list = new ArrayList<>();
list.add(3); // compiler: list.add(Integer.valueOf(3));

Unboxing: Automatic conversion from wrapper to primitive.

Integer y = Integer.valueOf(10);
int z = y; // compiler: int z = y.intValue();
int sum = y + 5; // y is unboxed

Pitfalls:

  1. NullPointerException:
Integer value = null;
int result = value; // NPE at runtime during unboxing
  1. Performance: Autoboxing in loops creates many objects
Long sum = 0L; // wrapper
for (long i = 0; i < 1_000_000; i++) sum += i; // creates ~1M Long objects!
// Use: long sum = 0L;
  1. == comparison confusion:
Integer a = 1000, b = 1000;
a == b; // false (not cached), use a.equals(b)
  1. Overload resolution surprises: Autoboxing has lower priority than widening in overload selection.
36 Difference between primitive and object? MID
AspectPrimitiveObject
Types8 types (int, long, etc.)Any class
MemoryStack (local vars)Heap
Default value0, false, '\0'null
NullableNoYes
GenericsNot directlyYes
Method callsNoYes
PerformanceFasterSlower (heap alloc, GC)
SizeFixed (int=4 bytes)Variable (object header overhead)

Primitives are value types: when assigned/passed, the value is copied.

Objects are reference types: when assigned/passed, the reference is copied (both point to same object).

Java (pre-Valhalla) has no user-defined value types. Project Valhalla (Java 23+ preview) introduces value classes โ€“ user-defined types with primitive-like performance.

37 What is pass-by-value in Java? MID

Java is strictly pass-by-value. Always. No exceptions.

For primitives: The value is copied.

void modify(int x) { x = 99; }
int a = 5; modify(a); // a is still 5

For objects: The reference value (memory address) is copied. The method receives a copy of the reference, both pointing to the same object.

void modify(List<String> list) { list.add("new"); }
// This DOES modify the original list - same object is modified

void reassign(List<String> list) { list = new ArrayList<>(); }
// This does NOT affect the caller - local reference is reassigned

The confusion: because both references point to the same object, mutations via the reference are visible. But the reference itself is passed by value โ€“ you can't make the caller's reference point to a different object.

This is different from pass-by-reference (C++, C# ref), where you get a reference to the caller's variable.

38 Can Java simulate pass-by-reference? MID

Java cannot truly do pass-by-reference, but you can simulate effects:

  1. Return the modified value:
int increment(int x) { return x + 1; }
  1. Wrap in a mutable container (array trick):
void increment(int[] x) { x[0]++; }
int[] val = {5}; increment(val); // val[0] is now 6
  1. Use AtomicInteger or a holder class:
void increment(AtomicInteger x) { x.incrementAndGet(); }
  1. Return multiple values via a record/tuple:
record Pair(int a, int b) {}
Pair swap(int a, int b) { return new Pair(b, a); }

These are all workarounds โ€“ Java is fundamentally pass-by-value and this is by design (simpler, safer).

39 What is heap memory? EXPERT

The heap is the JVM's runtime memory area where all objects and arrays are allocated.

Structure (generational GC):

  • Young Generation: Newly created objects
  • Eden space: Where objects are born
  • Survivor spaces (S0, S1): Objects that survive minor GC
  • Old Generation (Tenured): Long-lived objects promoted from Young Gen
  • Metaspace (Java 8+): Class metadata (not technically heap, but JVM-managed)

Heap sizing:

-Xms512m  # initial heap size
-Xmx4g    # maximum heap size
-Xmn256m  # young generation size

Objects on heap are managed by the Garbage Collector. Heap is shared across all threads.

Heap tuning considerations: Large heap โ†’ long GC pauses (with stop-the-world collectors). Balance between heap size and GC pause time. G1/ZGC/Shenandoah designed to minimize pauses.

40 What is stack memory? MID

The stack holds method execution frames. Each thread has its own stack.

Each frame contains:

  • Local variables (including primitives and object references)
  • Operand stack (working area for computations)
  • Reference to runtime constant pool
  • Return address

Properties:

  • Thread-private: No sharing, no synchronization needed
  • LIFO: Frames pushed on method call, popped on return
  • Fixed size per thread: Default typically 256KBโ€“1MB (-Xss flag)
  • Fast: Allocation/deallocation is just pointer movement

StackOverflowError: Stack exhausted (deep/infinite recursion).

Objects themselves don't live on the stack. Only primitive values and object references live on the stack. However, escape analysis (JIT optimization) can allocate objects on the stack if they don't escape the method โ€“ called stack allocation or scalar replacement.

Thread 1 Stack:     Thread 2 Stack:     Heap (shared):
[main frame]        [main frame]        [Object A]
[methodA frame]     [processData frame] [Object B]
41 Difference between == and equals(). When does each fail? MID

== compares references for objects (identity) and values for primitives.

.equals() compares logical equality, as defined by the class. Object.equals() falls back to ==; classes like String, Integer, and the collection types override it.

String a = new String("hi");
String b = new String("hi");
a == b;        // false โ€” different references
a.equals(b);   // true  โ€” same content

Common traps:

  • String literals share the constant pool, so "hi" == "hi" is often true โ€” but never rely on it. Always use equals().
  • Autoboxed Integer values in [-128, 127] are cached, so Integer a = 100; Integer b = 100; a == b returns true โ€” but 200 == 200 on boxed Integers returns false.
  • Calling x.equals(y) NPEs if x is null. Use Objects.equals(x, y) or "literal".equals(var).

Override equals() with care: it must be reflexive, symmetric, transitive, consistent, and x.equals(null) must return false. Always override hashCode() together.

42 Explain the contract between equals() and hashCode(). ADVANCED

The contract has two rules every Java developer must know:

  1. If a.equals(b) returns true, then a.hashCode() == b.hashCode() must be true.
  2. If a.hashCode() == b.hashCode(), a.equals(b) is not required to return true โ€” collisions are allowed and expected.

Why it matters: hash-based collections (HashMap, HashSet, ConcurrentHashMap) place an entry into a bucket using the hash, and only call equals() on entries within that bucket. If you violate the contract, an object you just inserted may be unfindable.

// Broken: equals overridden, hashCode not
@Override public boolean equals(Object o) { ... }
// missing hashCode โ†’ uses Object's identity-based hash
HashSet<User> s = new HashSet<>();
s.add(new User("alice"));
s.contains(new User("alice")); // false โ€” different bucket
Use Objects.hash(field1, field2, ...) or your IDE's generator. For records, the contract is auto-implemented and immutable.

Mutable keys: never use mutable fields in equals/hashCode if the object is in a hash collection โ€” its bucket would change after mutation and lookups would fail.

43 Inner class vs static nested class vs anonymous class vs lambda โ€” when to use which? MID
FormHolds outer reference?Typical use
Inner (non-static) classYes โ€” implicit Outer.thisTight coupling to outer state (e.g. iterator over outer's data)
Static nested classNoHelper class scoped to outer; safer โ€” no leak via implicit reference
Anonymous classYes (if inside instance context)One-off subclass / interface implementation; rare since lambdas
LambdaNo (captures only what it uses)Functional interfaces; cleanest, JIT-friendly

Memory leak warning: a non-static inner class instance keeps the outer alive. Common in Android (Handler holding Activity), or long-lived listeners. Prefer static nested + an explicit weak reference.

// Leaky
class Outer {
  Runnable r = new Runnable() { public void run() { use(this); } };
}
// Lambda โ€” no implicit outer ref unless it captures one
class Outer {
  Runnable r = () -> doWork();   // captures nothing โ†’ no leak
}

Lambdas compile to invokedynamic and are typically lighter than anonymous classes (no separate class file, often cached).

44 What is autoboxing/unboxing? What are the risks? MID

Autoboxing converts a primitive (int) to its wrapper (Integer) automatically; unboxing does the reverse.

List<Integer> xs = new ArrayList<>();
xs.add(5);              // autobox: Integer.valueOf(5)
int v = xs.get(0);      // unbox:   xs.get(0).intValue()

Risks:

  • NullPointerException on unboxing: Integer x = null; int y = x; throws NPE.
  • Performance: tight loops that auto-box every iteration can cause heap pressure and GC churn. Use IntStream/int[] for hot paths.
  • Identity quirks: Integer.valueOf(n) caches values in [-128, 127], so == on boxed Integers gives surprising results.
  • Overload resolution: list.remove(2) calls remove(int index), not remove(Object). Cast: list.remove((Integer) 2).
Mixing primitives and wrappers in arithmetic forces unboxing. Long total = 0L; for (long x : xs) total += x; unboxes every iteration. Use a long accumulator.
45 Explain var (Java 10) and when not to use it. MID

var is local-variable type inference (JEP 286, Java 10). The compiler infers the static type from the initializer; it is not dynamic typing โ€” Java remains strongly, statically typed.

var list = new ArrayList<String>();   // inferred as ArrayList<String>
var map  = Map.of("k", 1);            // inferred as Map<String, Integer>

Allowed: local variables, indexes in enhanced for, lambda parameters (Java 11+).

Not allowed: fields, method parameters, return types, var x = null, array initializers without a type.

When NOT to use it:

  • When the initializer is a literal that hides intent: var x = 0; โ€” int? long? byte?
  • When the inferred type is broader than what you want: var nums = List.of(1, 2.0) infers List<? extends Number>.
  • When the right-hand side is opaque: var u = service.find(id); โ€” readers can't tell the type without IDE help.
  • To "program to an interface": List<String> xs = new ArrayList<>(); documents intent better than var xs = new ArrayList<String>();.
Rule of thumb: use var when the type is obvious from the right-hand side and adds noise on the left. Otherwise spell out the type.
46 What are the data types in Java? BASIC

Java has two categories of data types:

1. Primitive Data Types (8 types โ€” stored by value, not objects):

TypeSizeDefaultRange / Notes
byte8-bit0-128 to 127
short16-bit0-32,768 to 32,767
int32-bit0~ยฑ2.1 billion
long64-bit0L~ยฑ9.2 ร— 10ยนโธ
float32-bit0.0fSingle-precision IEEE 754
double64-bit0.0dDouble-precision IEEE 754
char16-bit'\u0000'Unicode character (0โ€“65535)
booleanJVM-definedfalsetrue or false only

2. Non-Primitive (Reference) Data Types โ€” stored as references to objects on the heap:

  • String: sequence of characters, immutable
  • Array: fixed-size collection of same-type elements
  • Class: user-defined or library class instances
  • Interface: reference type that defines a contract

Each primitive has a corresponding Wrapper class (Integer, Long, Double, etc.) that adds OOP capabilities and is needed for collections like List<Integer>.

47 What is reflection in Java? MID

Reflection is a Java feature that allows a program to inspect and manipulate its own structure at runtime โ€” examining classes, interfaces, fields, methods, and constructors without knowing them at compile time.

Class<?> clazz = Class.forName("com.example.MyClass");
Method method = clazz.getDeclaredMethod("doSomething", String.class);
method.setAccessible(true);
Object result = method.invoke(instance, "arg");

Common uses:

  • Frameworks: Spring uses reflection to inject dependencies, scan @Component annotations, and create beans dynamically
  • Serialization: Jackson reads field names via reflection to map JSON to objects
  • Testing: JUnit discovers and runs test methods using reflection
  • ORM: Hibernate maps columns to fields via reflection
  • Debugging tools: inspect object state at runtime

Drawbacks:

  • Slower than direct calls (bypasses JIT optimizations)
  • Breaks encapsulation (setAccessible(true) ignores private)
  • More complex code, harder to read/debug
  • Module system (Java 9+) restricts reflective access across module boundaries
Use reflection when you truly need runtime dynamism. For most application code, prefer direct calls or generics.
48 What are the different types of ClassLoaders in Java? MID

Java loads classes lazily using a delegation hierarchy of ClassLoaders:

  1. Bootstrap ClassLoader (native code): Loads core JDK classes from rt.jar / java.base module โ€” java.lang.*, java.util.*, etc. Has no Java parent; implemented in C++.
  2. Extension ClassLoader (Java 8) / Platform ClassLoader (Java 9+): Loads standard extension libraries from $JAVA_HOME/lib/ext or platform modules.
  3. System (Application) ClassLoader: Loads classes from the application classpath (-cp, CLASSPATH). This is what loads your application classes.
// Check which classloader loaded a class
System.out.println(String.class.getClassLoader());     // null (Bootstrap)
System.out.println(MyClass.class.getClassLoader());    // AppClassLoader

Delegation model: Before loading a class, a classloader delegates to its parent. If the parent finds it, it's returned. If not, the child loads it. This prevents user code from replacing core JDK classes.

Custom ClassLoaders: You can create your own by extending ClassLoader. Use cases: loading classes from network/database, hot reload, plugin systems, isolation (each plugin gets its own classloader). Spring Boot's fat JAR uses a custom classloader to load nested JARs.

49 How can you prevent an object from being serialized in Java? MID

Several approaches to prevent serialization:

1. Declare fields as transient โ€” the JVM skips transient fields during serialization:

class User implements Serializable {
    private String username;
    private transient String password; // NOT serialized
}

2. Implement writeObject() to throw an exception โ€” prevents the entire object:

private void writeObject(ObjectOutputStream out) throws IOException {
    throw new NotSerializableException("User cannot be serialized");
}

3. Throw NotSerializableException from writeObject (same as above).

4. Don't implement Serializable โ€” the simplest prevention. If you try to serialize a non-Serializable object, ObjectOutputStream throws NotSerializableException automatically.

5. For subclass prevention โ€” if a superclass is Serializable but you don't want subclass instances serialized, override writeObject and readObject in the subclass to throw.

In modern Java, prefer records, sealed classes, or DTOs that are explicitly designed for serialization rather than making domain objects Serializable by default.
50 Is Java a purely object-oriented language? BASIC

No, Java is not a purely object-oriented language.

A purely OOP language requires everything to be an object. Java violates this with:

  • Primitive data types (int, char, boolean, etc.) โ€” they are NOT objects. They have no methods and are stored by value, not reference.
  • Static methods and fields โ€” they belong to a class, not an object instance. You can call Math.sqrt() without creating a Math object.

Contrast with purely OOP languages like Smalltalk or Ruby, where even integers and booleans are objects.

Java compensates with Wrapper classes (Integer, Character, Boolean) that wrap primitives into objects, and autoboxing which automatically converts between them. But the primitives themselves remain non-objects.

Java is often called a "hybrid" language โ€” mostly OOP but with performance-oriented primitives retained for efficiency.
51 What is coercion (type conversion) in Java? BASIC

Coercion in Java refers to converting one data type into another. There are two kinds:

1. Implicit coercion (Widening conversion) โ€” done automatically by the compiler when converting a smaller type to a larger compatible type. No data is lost:

int i = 42;
long l = i;     // int โ†’ long (implicit, safe)
double d = i;   // int โ†’ double (implicit, safe)

Widening order: byte โ†’ short โ†’ int โ†’ long โ†’ float โ†’ double

2. Explicit coercion (Narrowing / Casting) โ€” must be done manually using a cast operator. May lose data or precision:

double d = 9.99;
int i = (int) d;    // explicit cast โ†’ i = 9 (decimal part lost)

long l = 1000L;
byte b = (byte) l;  // may overflow/truncate

Key rule: Java does NOT allow implicit narrowing โ€” it's a compile error without an explicit cast. This prevents accidental data loss.

String conversion: Not technically coercion โ€” use Integer.parseInt(), String.valueOf(), etc. for String โ†” primitive conversions.

52 Can a private method be overridden in Java? BASIC

No โ€” private methods cannot be overridden.

Private methods are not inherited by subclasses. They are bound at compile time (early binding) and are invisible outside their declaring class. Therefore, there is nothing to override.

class Parent {
    private void display() {
        System.out.println("Parent");
    }
    void show() { display(); } // calls Parent's display
}

class Child extends Parent {
    private void display() {    // This is a NEW method, NOT an override
        System.out.println("Child");
    }
}

new Child().show(); // prints "Parent" โ€” NOT "Child"

Why? When show() calls display(), it resolves to Parent.display() at compile time because the method is private. The child's display() is a completely separate method that happens to share the same name.

Contrast with protected/public โ€” these CAN be overridden because they are inherited and resolved at runtime (dynamic dispatch).

53 What is a memory leak in Java? MID

A memory leak in Java occurs when objects that are no longer needed cannot be garbage collected because they are still being referenced somewhere โ€” even though the application will never use them again. Over time, this causes heap memory to grow until an OutOfMemoryError occurs.

Common causes:

  • Static collections: adding to a static Map or List that never removes entries
  • Non-static inner classes: hold an implicit reference to the outer class instance, keeping it alive
  • Event listeners / callbacks: registered but never de-registered
  • ThreadLocal: values stored in thread pool threads linger if not removed
  • Caches without eviction: growing caches (e.g., HashMap) with no size limit or TTL
  • Unclosed resources: while this is a resource leak, it can also prevent GC of associated objects

Detection:

  • Heap profilers: VisualVM, Eclipse MAT
  • JVM flags: -verbose:gc, -XX:+PrintGCDetails
  • Heap dumps: jmap -dump:format=b,file=heap.hprof <PID>
Java's GC handles most memory management automatically, but it cannot collect objects that are still (even accidentally) referenced. The key is ensuring references are released when objects are no longer needed.
54 What is the difference between new and newInstance() in Java? MID
FeaturenewnewInstance()
TypeKeywordMethod (Class.newInstance() or Constructor.newInstance())
Class resolutionCompile time (class must be known)Runtime (class loaded dynamically)
PerformanceFaster (no reflection overhead)Slower (reflection + security checks)
Exception handlingPropagates directlyWraps in InvocationTargetException
ConstructorAny constructorNo-arg only for Class.newInstance(); any with Constructor.newInstance()
Use caseNormal object creationFrameworks, plugins, dependency injection, deserialization
// new โ€” compile-time known class
MyService service = new MyService();

// newInstance โ€” dynamic, runtime class name
Class<?> clazz = Class.forName("com.example.MyService");
Object service = clazz.getDeclaredConstructor().newInstance(); // modern API

// Old (deprecated) form:
Object service2 = clazz.newInstance(); // throws checked exceptions if constructor throws
Prefer getDeclaredConstructor().newInstance() over the deprecated Class.newInstance() โ€” it wraps exceptions more cleanly and supports constructors with arguments.
55 What is garbage collection in Java? MID

Garbage Collection (GC) is Java's automatic memory management mechanism. The JVM's garbage collector identifies objects that are no longer reachable by any live thread and reclaims their heap memory โ€” eliminating the need for manual free()/delete calls (unlike C/C++).

How it works (generational GC):

  1. Objects are created in Eden space (Young Generation)
  2. Minor GC: clears Eden; surviving objects move to Survivor spaces (S0/S1)
  3. After several minor GCs, long-lived objects get promoted to Old Generation
  4. Major/Full GC: collects Old Generation โ€” more expensive, may cause stop-the-world pauses

Mark and Sweep algorithm:

  • Mark phase: GC traverses all references from GC roots (stack, static fields) and marks live objects
  • Sweep phase: Unmarked (unreachable) objects are cleared
  • Compact phase: Moves live objects together to reduce fragmentation (in some collectors)

Common GC algorithms in Java:

  • Serial GC: single-threaded, good for small apps
  • Parallel GC: multi-threaded, default in Java 8 for throughput
  • G1 GC: default from Java 9; region-based, balances throughput and pause time
  • ZGC / Shenandoah: ultra-low pause (<1ms), concurrent collection

Tuning flags: -Xms512m -Xmx4g -XX:+UseG1GC

56 What is the difference between implements and extends? BASIC
Featureextendsimplements
PurposeClass inheriting from another classClass adopting an interface's contract
Used withClass โ†’ Class, Interface โ†’ InterfaceClass โ†’ Interface
MultipleA class can extend only ONE classA class can implement MULTIPLE interfaces
InheritedFields, methods, constructors (partial)Abstract method signatures (+ default/static methods)
Mandatory overrideNo (can inherit all methods as-is)Yes โ€” must implement all abstract methods unless abstract class
// extends: inherit implementation from a class
class Dog extends Animal {
    @Override void speak() { System.out.println("Woof"); }
}

// implements: fulfill an interface contract
class Dog extends Animal implements Runnable, Comparable<Dog> {
    public void run() { ... }
    public int compareTo(Dog other) { ... }
}

// Interface extending interface
interface Flyable extends Movable, Audible { ... }

Key rule: extends is for IS-A inheritance (code reuse), implements is for behavioral contracts (polymorphism without inheritance). Prefer composition + interfaces over deep inheritance hierarchies.

57 What is the purpose of the toString() method in Java? BASIC

The toString() method returns a human-readable string representation of an object. It is defined in java.lang.Object and can be overridden by any class.

Default behavior: Object.toString() returns ClassName@hexHashCode (e.g., User@7852e922) โ€” not useful for debugging.

When toString() is called automatically:

  • String concatenation: "User: " + user calls user.toString()
  • System.out.println(object)
  • Logging frameworks: log.debug("user={}", user)
  • String.format / interpolation
class User {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

// Or using Java 14+ Records (toString auto-generated):
record User(String name, int age) {} // toString: User[name=Alice, age=30]

Best practices:

  • Always override toString() in domain/entity classes for meaningful logging
  • Include key identifying fields (don't include sensitive data like passwords)
  • Use IDE-generated or Lombok's @ToString to avoid boilerplate
  • Use Objects.toString(obj, "null") for null-safe conversion
58 What are annotations in Java? MID

Annotations are metadata tags that provide additional information about code elements (classes, methods, fields, parameters) using the @ prefix. They don't directly affect execution but can be processed by the compiler, build tools, or frameworks at runtime via reflection.

Built-in Java annotations:

  • @Override โ€” tells the compiler this method overrides a superclass method (compile-time check)
  • @Deprecated โ€” marks a code element as outdated; triggers compiler warnings on use
  • @SuppressWarnings("unchecked") โ€” suppresses specific compiler warnings
  • @FunctionalInterface โ€” marks an interface that should have exactly one abstract method
  • @SafeVarargs โ€” suppresses unchecked warnings on varargs

Meta-annotations (annotations on annotations):

  • @Retention(RetentionPolicy.RUNTIME) โ€” annotation is available at runtime via reflection
  • @Target(ElementType.METHOD) โ€” restricts where the annotation can be applied
  • @Inherited โ€” subclasses inherit the annotation from the parent class
  • @Repeatable โ€” allows the same annotation to be applied multiple times

Custom annotation example:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cacheable {
    int ttlSeconds() default 60;
    String key() default "";
}

Frameworks that heavily use annotations: Spring (@Component, @Autowired), JPA (@Entity, @Column), JUnit (@Test), Jackson (@JsonProperty).

59 What is the assert statement in Java? MID

The assert statement validates assumptions during development. If the condition is false, it throws an AssertionError.

// Basic form
assert condition;

// With message
assert x > 0 : "x must be positive, got: " + x;

// Example in code
public double sqrt(double x) {
    assert x >= 0 : "Input must be non-negative: " + x;
    return Math.sqrt(x);
}

Important: Assertions are DISABLED by default at runtime. You must explicitly enable them:

java -ea MyApp           # enable all assertions
java -ea:com.example MyApp  # enable for a specific package

When to use assertions:

  • Validate method preconditions for internal (private) methods
  • Check invariants inside algorithms
  • Verify assumptions that "should never be false"
  • Document assumptions for other developers

When NOT to use assertions:

  • To validate public method arguments (use IllegalArgumentException instead โ€” assertions can be disabled)
  • To check for errors that should be handled in production (use exceptions)
  • In expressions with side effects โ€” assert may be disabled and the side effect won't happen