// Java Interview — Senior Level

☕ PART 1: Java Basics & Fundamentals (Q1–40)

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

40 Questions
2 Basic
28 Mid
1 Advanced
9 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]