Java Interview Question

A Functional Interface 

A Functional Interface is an interface with exactly one abstract method (SAM – Single Abstract Method).

Examples: Runnable, Callable, Comparator, Function<T, R>.

  • @FunctionalInterface

    interface MyFunc {

        void sayHello();  // ✅ only 1 abstract method

    }

  • 2️⃣ Reason only 1 abstract method

    👉 Because Lambda Expressions in Java are designed to provide the implementation of exactly one abstract method.

    If there were multiple abstract methods, the compiler would not know which method the lambda is implementing.



  • difference between StringBuilder and StringBuffer in Java

    Feature StringBuffer StringBuilder
    Thread Safety          Thread-safe (methods are synchronized) Not thread-safe (no synchronization)
    Performance Slower (due to synchronization overhead)

    Faster (no synchronization)
    Use Case Use when multiple threads might modify the same string Use when single thread modifies the string
    Introduced in Java 1.0 Java 1.5


    String :-



    String -


    Immutable (cannot change once created) 
    and ✅ Thread-safe (because immutable)


    Slower when doing modifications (creates new object every time).


    difference between .equals() and == in Java 



    public class EqualsVsDoubleEquals {

        public static void main(String[] args) {

            String s1 = "Java";            // String literal (stored in String pool)

            String s2 = "Java";            // Points to same pool object

            String s3 = new String("Java");// New object in heap


            System.out.println(s1 == s2);       // true  (same reference in pool)

            System.out.println(s1.equals(s2));  // true  (same content)


            System.out.println(s1 == s3);       // false (different objects in memory)

            System.out.println(s1.equals(s3));  // true  (content matches)

        }

    }



    1. Method Overloading (Compile-Time Polymorphism)

    Definition:
    When two or more methods in the same class have the same name but different parameter lists (number or type), it’s called overloading.

    • Happens within the same class.

    • Decided at compile time based on method signature.

    • Return type can be different, but it alone cannot differentiate overloaded methods.



    class Calculator {

        int add(int a, int b) {

            return a + b;

        }


        double add(double a, double b) {

            return a + b;

        }


        int add(int a, int b, int c) {

            return a + b + c;

        }

    }


    public class TestOverload {

        public static void main(String[] args) {

            Calculator c = new Calculator();

            System.out.println(c.add(2, 3));        // calls int method

            System.out.println(c.add(2.5, 3.5));    // calls double method

            System.out.println(c.add(1, 2, 3));     // calls 3-param method

        }

    }


    Key Points:

    • Done in the same class.

    • Happens at compile time (compiler decides which method to call).

    • Can overload static, instance, and constructors.


    2. Method Overriding (Run-Time Polymorphism)

    Definition:
    When a subclass provides its own implementation of a method already present in the parent class (with the same method name, parameters, and return type), it’s called overriding.

    • Happens between parent and child classes.

    • Decided at runtime using the actual object type.


    class Animal {
        void sound() {
            System.out.println("Animal makes a sound");
        }
    }

    class Dog extends Animal {
        @Override
        void sound() {
            System.out.println("Dog barks");
        }
    }

    public class TestOverride {
        public static void main(String[] args) {
            Animal a = new Dog();  // Upcasting
            a.sound();             // Dog barks (runtime decision)
        }
    }
                              

                                                  Singleton class 

    A Singleton class in Java is a class that allows only one object (instance) to be created for the entire application.
    It’s used when exactly one instance of a class is needed to coordinate actions globally.


    Key Features

    1. Only one instance of the class exists.

    2. Global access point to that instance.

    3. Constructor is private so no one can create an object directly.

    4. Instance is returned using a static method.

    public class Singleton {
        // Step 1: Private static variable of same class
        private static Singleton instance;

        // Step 2: Private constructor so no one can create object
        private Singleton() {
            System.out.println("Singleton instance created!");
        }

        // Step 3: Public static method to get instance
        public static Singleton getInstance() {
            if (instance == null) {  // Lazy initialization
                instance = new Singleton();
            }
            return instance;
        }
    }

    public class Main {
        public static void main(String[] args) {
            Singleton obj1 = Singleton.getInstance();
            Singleton obj2 = Singleton.getInstance();

            System.out.println(obj1 == obj2); // true → same object
        }
    }

    When to Use



                           what is thread safety how do you ensure thread safe class ?


    Thread safety means that a class or piece of code works correctly when accessed by multiple threads at the same time, without causing race conditions, data corruption, or inconsistent results.


    Why it’s needed

    If two threads modify the same variable/object at the same time without proper control, results can be unpredictable.
    Example problem (race condition):


    class Counter {

        private int count = 0;


        public void increment() {

            count++; // not thread safe

        }


        public int getCount() {

            return count;

        }

    }

    If Thread A and Thread B both run increment() at the same time,
    count may not increase correctly because count++ is not atomic.


    How to Ensure a Thread-Safe Class

    1️⃣ Use Synchronization

    Make critical sections synchronized so only one thread accesses at a time.


    class Counter {

        private int count = 0;


        public synchronized void increment() {

            count++;

        }


        public synchronized int getCount() {

            return count;

        }

    }

    ✅ Simple but may be slower if many threads are waiting.

    2️⃣ Use volatile for visibility (not atomicity)

    Ensures changes to a variable are visible to all threads.


    volatile boolean flag = true;


    ⚠️ Volatile doesn’t make operations atomic — just ensures visibility.

    3️⃣ Use Atomic Classes (from java.util.concurrent.atomic)

    Atomic operations are faster than synchronized for simple counters.

    5️⃣ Use Thread-safe Collections

    Instead of ArrayList or HashMap, use:



    "How to make Singleton thread safe?" → Mention:

    • synchronized getInstance() (simple but slow)

    • Double-checked locking

    • Bill Pugh Singleton (static inner class)

    • Enum Singleton (best and simplest)


    1️⃣ How AtomicInteger Works

    AtomicInteger is part of java.util.concurrent.atomic and is thread-safe for single variable operations without using locks.
    It uses CAS (Compare-And-Set) at the CPU level.

    CAS works like this:

    1. Read the current value (expected value).

    2. Compute the new value.

    3. Atomically update the variable only if it’s still the expected value.

    4. If another thread has modified it, retry until success.


    import java.util.concurrent.atomic.AtomicInteger;

    class Counter {
        private AtomicInteger count = new AtomicInteger(0);

        public void increment() {
            count.incrementAndGet(); // Atomic operation
        }

        public int getCount() {
            return count.get();
        }
    }


    incrementAndGet() internally uses compareAndSet()lock-free and fast.





    Feature AtomicInteger synchronized
    Mechanism Lock-free (uses CAS at CPU level) Uses monitor locks (object-level)
    Performance Very fast for single variable updates Slower due to context switching & blocking
    Scope Works for atomic operations on single variables only Works for complex code blocks
    Blocking Non-blocking Blocking
    When to Use Counters, flags, sequence numbers Multi-step logic that must be atomic
    Fairness No fairness guarantee (fastest wins) Lock fairness can be ensured (ReentrantLock)


    3️⃣ Example Difference

    🔴 Using synchronized

    class SyncCounter {

        private int count = 0;


        public synchronized void increment() {

            count++;

        }

    }


  • Locks the entire method → even if 100 threads, only 1 runs count++ at a time.

  • Thread waits in BLOCKED state.

  • 🟢 Using AtomicInteger

  • class AtomicCounter {

        private AtomicInteger count = new AtomicInteger(0);


        public void increment() {

            count.incrementAndGet(); // lock-free

        }

    }

  • Multiple threads can execute in parallel. CAS ensures correctness without blocking.  

  • 1️⃣ What is a HashMap?

    • Key-value pair data structure.

    • Allows null keys (only one) and multiple null values.

    • Not thread-safe (use ConcurrentHashMap for thread safety).

    • O(1) average time complexity for put() and get()

    • 2️⃣ Internal Data Structure

      Internally, a HashMap uses:

    • static class Node<K,V> implements Map.Entry<K,V> {
    •     final int hash;     // hash code of the key
    •     final K key;        // key
    •     V value;            // value
    •     Node<K,V> next;     // pointer to next node in case of collision
    • }

    The process is:

    1. Hashing the Key

      • Java computes the key’s hashCode() (an integer).

      • Applies hash function to spread bits (to reduce collisions):

      • int hash = (key == null) ? 0 : hash(key.hashCode());

      • Find the Bucket Index

        • index = (n - 1) & hash (where n = array length).

        • This is faster than modulo.

        • Insert into Bucket

          • If bucket is empty → create new Node.

          • If key already exists → update value.

          • If collision occurs → add new node at the end (linked list).

          • Convert to Tree (Java 8+)

     


    5️⃣ Collision Handling

    • Uses Separate Chaining — each bucket stores multiple entries in a linked list/tree.

    • In Java 8+, linked list → tree if too many collisions.



    6️⃣ Resizing

    • When size exceeds threshold = capacity * loadFactor (default 0.75):

      • Double the capacity.

      • Rehash all entries into the new bucket array.

    • Resizing is costly — try to set initial capacity if possible.


    9️⃣ Common Interview Follow-ups

    • What happens if two keys have same hashCode?
      → Stored in same bucket, collision handled via chaining/tree.

    • Why is load factor 0.75?
      → Good balance between time & space; reduces collisions while avoiding too much resizing.

    If the load factor exceeds a certain threshold (often set to 0.75), the hashmap becomes inefficient as the number of collisions increases. To avoid this, the hashmap can be resized and the elements can be rehashed to new buckets, which decreases the load factor and reduces the number of collisions.



    • How is null key stored?
      → Always stored in bucket 0.

    • Is HashMap thread-safe?
      → No. Use ConcurrentHashMap or synchronize externally.

    • Difference between HashMap and Hashtable?
      Hashtable is synchronized, doesn’t allow null keys/values.



    7️⃣ Java 7 vs Java 8 Difference


    Feature Java 7 Java 8
    Bucket storage Linked List Linked List + Red-Black Tree
    Order of insertion in bucket Head insertion Tail insertion
    Hash collision handling More prone to long chains Tree structure improves worst case to O(log n)



    difference between HashMap, Hashtable, and ConcurrentHashMap in Java

    1. HashMap

    • Thread Safety: ❌ Not thread-safe — multiple threads can cause data inconsistency.

    • Nulls: ✅ Allows one null key and multiple null values.

    • Performance: Fastest (no synchronization overhead).

    • Introduced: Java 1.2

    • Use Case: Single-threaded or read-mostly operations.


    2. Hashtable

    • Thread Safety: ✅ Thread-safe — all methods are synchronized.

    • Nulls: ❌ No null key, ❌ no null values.

    • Performance: Slower due to full method synchronization.

    • Introduced: Java 1.0 (Legacy class)

    • Use Case: Rarely used now; replaced by ConcurrentHashMap in multi-threaded code.


    3. ConcurrentHashMap

    • Thread Safety: ✅ Thread-safe using bucket-level locking (Segmented Locking) instead of locking the entire map.

    • Nulls: ❌ No null key, ❌ no null values.

    • Performance: Faster than Hashtable in multi-threading because it only locks part of the map during updates.

    • Introduced: Java 1.5

    • Use Case: High-performance thread-safe map.

    Internal Working

    All three use:

    Difference in locking:

    • Hashtable: Locks entire map for every operation.

    • ConcurrentHashMap: Locks only the bucket being modified.

    • HashMap: No locking.


    how does hashmap work with employee as key ?

    If you use an Employee object as a key in a HashMap, the map works fine — but only if you properly implement hashCode() and equals() in the Employee class.

    Otherwise, you’ll run into unexpected behavior like:

    • Duplicate keys being allowed.

    • Failure to retrieve a value even when you used the same data.

    Steps:

    1. hashCode() of emp1 is called → gives a hash value.

    2. That hash is converted to a bucket index using (hash & (n - 1)).

    3. If the bucket is empty → store (key=emp1, value="Developer") there.

    4. If the bucket already has entries:

      • Compare keys using equals() to see if the key already exists.

      • If yes → update value.

      • If no → store alongside (collision).

    5. hashCode() of emp2 is called → bucket index calculated.

    6. Finds the bucket.

    7. Iterates keys in that bucket → calls equals() to match with stored keys.

    8. If match → returns value, else returns null.

    Key Rule

    For an object to work correctly as a HashMap key:

    • If emp1.equals(emp2) → then emp1.hashCode() must be equal to emp2.hashCode().

    • If you override equals() → you must override hashCode() too.



    💡 Interview takeaway:
    When using a custom object (like Employee) as a HashMap key:

    • Override equals() and hashCode() based on immutable fields.

    • Avoid mutable fields in keys, otherwise hash codes may change after insertion, making retrieval fail.

                                                         how many way object created in java ?



    1. Using new keyword ✅ (Most common)

    Employee emp = new Employee();
     Calls the constructor.
    Most frequently used method.

    2. Using Reflection

    Employee emp = Employee.class.newInstance(); // Deprecated in Java 9+

    3. Using clone() method

    Employee emp1 = new Employee();
    Employee emp2 = (Employee) emp1.clone();

    Requires implements Cloneable and overrides clone() in class.

    Creates a copy of an existing object without calling its constructor.


    ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
    Employee emp = (Employee) in.readObject();



    Integer num = Integer.valueOf(5); // Factory method


    📌 Interview Tip:
    If they ask "How many ways to create an object in Java?" — say:

    "There are 5 primary ways: new keyword, reflection, cloning, deserialization, and factory methods. Additionally, there are less common ways like using Unsafe, class loaders, and builders."


     






                                                             Encapsulation in Java 

    Encapsulation in Java is about hiding the internal details of a class (its data) and controlling how it’s accessed or modified, typically using private fields with public getter and setter methods.

    Think of it like a capsule of medicine: you can take the pill (public method) but you don’t see or directly handle the powder inside (private fields).


    Key Points of Encapsulation

    1. Data Hiding – Keep class variables private so they cannot be accessed directly from outside.

    2. Controlled AccessUse getter and setter methods to read and modify the data.

    3. Maintainability – You can change the internal implementation without affecting other classes.

    4. Validation – You can put checks in setters to avoid invalid data.


    // Class demonstrating encapsulation
    public class BankAccount {
        // Step 1: Make fields private
        private String accountHolder;
        private double balance;

        // Step 2: Provide public getter and setter methods
        public String getAccountHolder() {
            return accountHolder;
        }

        public void setAccountHolder(String accountHolder) {
            // Adding validation
            if(accountHolder != null && !accountHolder.trim().isEmpty()) {
                this.accountHolder = accountHolder;
            } else {
                System.out.println("Invalid account holder name!");
            }
        }

        public double getBalance() {
            return balance;
        }

        public void deposit(double amount) {
            if(amount > 0) {
                balance += amount;
                System.out.println("Deposited: " + amount);
            } else {
                System.out.println("Invalid deposit amount!");
            }
        }

        public void withdraw(double amount) {
            if(amount > 0 && amount <= balance) {
                balance -= amount;
                System.out.println("Withdrawn: " + amount);
            } else {
                System.out.println("Insufficient funds or invalid amount!");
            }
        }
    }

    public class Main {
        public static void main(String[] args) {
            BankAccount account = new BankAccount();

            account.setAccountHolder("Shivam Sharma");
            account.deposit(5000);
            account.withdraw(2000);

            System.out.println("Account Holder: " + account.getAccountHolder());
            System.out.println("Remaining Balance: " + account.getBalance());
        }
    }

    Why This is Encapsulation

    • We hid the fields (accountHolder, balance) from direct access.

    • We provided controlled access through getters/setters and specific methods (deposit, withdraw).

    • We added validation logic to prevent invalid state.




    1. Abstract Questions

    Q1: What is an abstract class in Java?
    A:


    Q2: Can we create an object of an abstract class?
    A:
    No, but we can have references of an abstract class type pointing to subclass objects.


    Q3: Can abstract classes have constructors?
    A:
    Yes. They are used for initializing fields when subclasses are created.


    2. Medium Questions

    Q4: Difference between abstract class and interface?
    A:

    FeatureAbstract ClassInterface
    MethodsAbstract + ConcreteAbstract (Java 7), + default & static (Java 8)
    FieldsInstance & static variables       public static final only
    InheritanceSingleMultiple
    Constructor YesNo

    Q5: Can abstract classes have static methods?
    A:
    Yes, but static methods cannot be abstract because they belong to the class, not an object.


    Q6: Can an abstract class extend another abstract class?
    A:
    Yes. The subclass can either implement the inherited abstract methods or remain abstract.


    3. Tricky Questions

    Q7: Can we declare an abstract method as private?
    A:
    No. Abstract methods must be visible to subclasses for implementation.


    Q8: Can we make an abstract class final?
    A:
    No. final means it cannot be inherited, but an abstract class needs inheritance to implement abstract methods.


    Q9: What happens if a subclass does not implement all abstract methods?
    A:
    The subclass must also be declared abstract.


    Q10: Can an abstract class implement an interface?
    A:
    Yes, but it must either implement all interface methods or remain abstract.

    abstract class Shape {
        abstract void draw(); // abstract method

        void info() { // concrete method
            System.out.println("I am a shape");
        }
    }

    class Circle extends Shape {
        void draw() {
            System.out.println("Drawing a Circle");
        }
    }

    public class TestAbstract {
        public static void main(String[] args) {
            Shape s = new Circle(); // polymorphism
            s.draw();
            s.info();
        }
    }

    Abstract Class vs Interface (Quick Answer)

    Memory Tip:

    Abstract Class = Partially built house (some work done).
    Interface = Blueprint (only plan given).


                                                                   Java Exceptions 

    Java Exceptions are unexpected events that occur during the execution of a program and disrupt the normal flow of instructions.
    They are represented as objects of classes derived from Throwable.

    In Java, exceptions are used to signal errors and handle them gracefully without crashing the program.


    Types of Exceptions

    1. Checked Exceptions – Checked at compile time (e.g., IOException, SQLException).

    2. Unchecked Exceptions – Occur at runtime (e.g., NullPointerException, ArrayIndexOutOfBoundsException).

    3. Errors – Serious problems not meant to be handled by applications (e.g., OutOfMemoryError).


    Example:


    try { int result = 10 / 0; // will cause ArithmeticException } catch (ArithmeticException e) { System.out.println("Cannot divide by zero"); }






    static keyword in Java is used for memory management. It means the member (variable, method, block, or nested class) belongs to the class rather than to an object, so it is shared by all objects of that class.

    Uses of static:

    1. Static Variable → Shared by all instances.

    static int count; // same copy for all objects

    Static Method → Can be called without creating an object; can only access static members.

    static void display() { ... }



    Static Nested Class → Inner class that does not need an instance of the outer class.

    Memory Tip:

    static = “class-level, one copy shared by all.”



    Garbage Collection (GC) in Java 


    Garbage Collection (GC) in Java is the automatic process of reclaiming memory by removing objects that are no longer reachable in a program.
    It helps prevent memory leaks and optimizes memory usage

    .


    Key Points:

     



    public class TestGC { public static void main(String[] args) { String str = new String("Hello"); str = null; // object is now eligible for GC System.gc(); // suggest GC } @Override protected void finalize() { System.out.println("Garbage collected"); } }



    What are generics in Java?


    Generics in Java allow you to write type-safe, reusable code by specifying a type parameter (like <T>) instead of using raw types.
    They help detect type errors at compile time and remove the need for explicit type casting.

    Before Generics (Java 1.4 and earlier)

    • Collections stored Object type, meaning they could hold any object.

    • This flexibility was dangerous because:

      1. Type safety was not enforced at compile time.

      2. Runtime errors like ClassCastException were common.

      3. You had to manually cast when retrieving data.

    Example (before generics):


    List list = new ArrayList(); // raw type list.add("Java"); list.add(100); // Allowed! String lang = (String) list.get(0); // Must cast String num = (String) list.get(1); // Runtime error: ClassCastException


    After Generics (Java 5 and later)

    • You specify type parameters like <String> or <Integer>.

    • Compiler checks type correctness at compile time.

    • No explicit casting when retrieving.

    • Fewer runtime errors.

    Example (after generics):


    List<String> list = new ArrayList<>(); list.add("Java"); // list.add(100); // Compile-time error String lang = list.get(0); // No casting needed



    Impact of Generics

    Advantages:

    1. Compile-time Type Safety → Prevents adding wrong types.

    2. No Casting Needed → Cleaner code.

    3. Better Code Reuse → One class/method works for multiple data types.

    4. Self-documenting Code → When you see List<String>, you know it’s storing strings only.

    Limitations:

    • Type Erasure: At runtime, generic types are erased to Object (or their bounds), so no type-specific info is kept.

    • Cannot create objects of type parameter: new T() is illegal.

    • Cannot use primitive types directly (List<int> ❌ → List<Integer> ).



    Real-Life Analogy

    • Before Generics: A storage box where you can put anything, but you don’t know what’s inside until you open it. You might put a shoe in a lunchbox by mistake.

    • After Generics: A labeled box — “Only shoes” — so you know exactly what’s allowed, and mistakes are caught early.





                                   A marker interface in Java 


    A marker interface in Java is a special type of interface that does not contain any methods or fields.

    Its primary purpose is to provide metadata or a "marker" to the class implementing it,

    which can be used by the Java runtime or other frameworks to perform specific operations.

    Key Features:

    1. No Methods or Fields: Marker interfaces are completely empty.
    2. Purpose: They serve as a tagging mechanism to indicate that a class possesses a particular property or behavior.
    3. Run-Time Type Information: They provide additional information about the object to the JVM or frameworks at runtime.

    Common Examples:

    • Serializable: Marks a class as capable of being serialized.
    • Cloneable: Indicates that a class supports cloning.
    • Remote: Marks a class as capable of being used in remote method invocation (RMI).

    Interface Purpose
    Serializable                  Marks objects that can be serialized/deserialized
    Cloneable                  Marks objects that can be cloned using Object.clone()
      

    Why Use Marker Interfaces?

    Metadata Tagging → Indicates that a class has a special property. Runtime Identification → JVM or frameworks use instanceof to check if an object has a specific capability. Design Clarity → Other developers can easily identify a class’s purpose from its interface.

    Custom Marker Interface:

    You can create your own marker interface to define custom behavior. For example:

    // Marker Interface
    public interface MyMarker {}
    
    // Class implementing the marker interface
    public class MyClass implements MyMarker {}
    
    // Checking the marker at runtime
    public class MarkerTest {
        public static void main(String[] args) {
            MyClass obj = new MyClass();
            if (obj instanceof MyMarker) {
                System.out.println("MyClass is marked with MyMarker!");
            } else {
                System.out.println("MyClass is NOT marked with MyMarker.");
            }
        }
    }
    


    // Marker interface public interface Serializable { // No methods } // Class implementing marker interface public class Employee implements Serializable { private String name; private int id; }

    Here, Serializable doesn’t force us to implement any method —
    but the JVM sees Employee implements it and knows this object can be serialized.

    Alternatives:

    In modern Java, annotations are often preferred over marker interfaces because they are more flexible and provide additional metadata.

    For example, instead of using a marker interface, you can use a custom annotation like @MyMarker.

    Marker interfaces are still relevant in legacy systems but are less commonly used in newer Java applications.




    Java Memory Model (JMM)



    The Java Memory Model (JMM) is basically the rulebook that defines how Java programs interact with memory in a multi-threaded environment
    — it decides how and when changes made by one thread become visible to others and how the ordering of instructions works across threads. Think of it as the traffic rules for threads to safely read/write variables in memory without crashing into each other. 1️⃣ Why do we need the Java Memory Model? Without a JMM, the following problems occur in multi-threading: Reordering issues – The compiler/CPU may reorder instructions for optimization, which could break your program if not handled correctly. Visibility issues – One thread may update a variable, but another thread might still see the old value because of CPU caching. Atomicity issues – Reading/writing to a variable may not be atomic (especially long/double in older JVMs). 2️⃣ Key concepts in the JMM a. Main Memory & Working Memory Main memory → Shared space for all variables (RAM). Working memory → Each thread has its own copy of variables (usually in CPU registers or thread-local cache). When a thread changes a variable, it updates its own working memory first, and later the change gets pushed to main memory. b. Happens-Before Relationship The JMM defines a "happens-before" rule to determine visibility and ordering: If A happens-before B, then: All changes by A are visible to B. A is executed before B (in program order). Examples of happens-before: Unlocking a monitor (synchronized) happens-before locking it again in another thread. Writing to a volatile variable happens-before reading it. Thread start/join establish happens-before relationships. c. Volatile Keyword Marks a variable so that reads/writes go directly to main memory. Guarantees visibility but not atomicity for compound actions. Prevents certain types of instruction reordering. d. Synchronization synchronized blocks/methods ensure mutual exclusion and visibility. Flushing changes to main memory happens at the end of a synchronized block. e. Reordering Compilers and CPUs can reorder instructions for optimization. JMM allows some reordering unless it breaks the happens-before rules. Volatile and synchronized act as memory barriers to stop unsafe reordering.





    1. What Garbage Collection Is

    In Java, garbage collection is the process of automatically freeing up memory by deleting objects that are no longer reachable in the program.
    You don’t have to manually free() memory like in C or C++.
    Java’s JVM does this for you.

    2. When an Object Becomes Eligible for GC

    An object is eligible for garbage collection when no live thread can reach it through any chain of references.


    4. The Heap and Generations Java heap memory is divided into: Young Generation – where new objects go. Eden Space: new objects start here. Survivor Spaces: surviving objects get moved here during minor collections. Minor GC happens often here — it’s fast. Old (Tenured) Generation – for long-lived objects. Objects that survive multiple minor GCs are promoted here. Major GC (Full GC) happens less often but takes longer. Metaspace – stores class metadata (since Java 8). 5. Types of Garbage Collectors in Java Common GC implementations you might encounter: Serial GC – single-threaded, simple, good for small apps. Parallel GC – uses multiple threads for faster collection. G1 GC – balanced for large heaps, avoids long pauses. ZGC & Shenandoah GC – ultra-low pause collectors for very large heaps.


    Survivor spaces reduce fragmentation by copying only live objects. This keeps Eden fully clear after each Minor GC. Promotion to Old Gen only happens for objects that live long enough, reducing pressure on the Old Gen.



    2. Minor GC Flow (Object Movement) Let’s say: You create objects → they go to Eden. When Eden fills up, a Minor GC is triggered. During a Minor GC: Mark reachable objects in Eden. Copy reachable objects from Eden → empty Survivor space. If some objects were already in a Survivor space and survive again, their age increases. Objects that become old enough (hit the tenuring threshold, e.g., age 15) are promoted to the Old Generation. The other survivor space becomes empty and ready for the next cycle.

    6. Important Points You cannot force GC; you can only request it with:

    System.gc(); // Just a suggestion, JVM may ignore it



    Objects with finalize() are cleaned later (but finalize() is deprecated in modern Java — use try-with-resources or cleaners). GC helps avoid memory leaks, but memory leaks can still happen in Java if references are unintentionally kept alive.


    1. Primitive Data Types Definition: The most basic, built-in data types in Java — they store simple values directly in memory. Nature: Not objects. Examples: byte, short, int, long, float, double, char, boolean Memory: Fixed size, stored on the stack (or inside objects on the heap). Default values: Zero-like defaults (0, false, '\u0000'). Operations: Fast — handled directly by the JVM without method calls. Null? Cannot be null (except if wrapped in a wrapper class like Integer). 2. Non-Primitive (Reference) Data Types Definition: Data types that are based on classes or interfaces — they store a reference (memory address) to the actual object in the heap. Nature: Always objects (except arrays, which are special objects). Examples: String, arrays (int[], String[]), user-defined classes, Integer, List, Map, etc. Memory: The reference is stored on the stack, but the actual data is stored in the heap. Default values: null (because they’re references). Operations: Can have methods, can be null, can be large/complex. Null? Yes — and NullPointerException happens if you try to use a null reference.



    1. Why Java Doesn’t Have Pointers Java was designed to be: Safe → Direct memory access can cause security risks and memory corruption. Simple → Removing pointer arithmetic avoids complexity and bugs. Managed → The JVM handles memory allocation and garbage collection automatically. Instead of giving you a raw memory address to work with, Java gives you references.


    what is object class
    In Java, Object class is the root (super) class of all classes. That means: Every class in Java directly or indirectly extends java.lang.Object. Even if you don’t explicitly write extends Object, it’s done automatically by the compiler.

    The key methods are equals(), hashCode(), toString(), clone(), finalize(), wait(), notify(), and notifyAll(). These provide basic operations like equality checks, memory management, and thread coordination.



    1. What is an Anonymous Class? An anonymous class in Java is: A class without a name. Declared and instantiated at the same time. Used to make a one-time use class — usually when you don’t need to reuse the class definition. It’s typically used: To implement interfaces quickly. To extend a class with minor changes, without creating a separate named class file.

    5. Advantages of Anonymous Classes Less code → No need to create a separate named class file. Quick customization → Modify or extend an existing class for one-time use. Improves readability for small, local implementations. Often used with event listeners or callbacks (e.g., GUI programming, threads). 6. Limitations Can’t have constructors (only instance initializers). Not reusable — it’s for one-time use. Code can become hard to read if overused.

    In Java, immutable classes are classes whose objects cannot be modified once they are created. 1. Meaning Immutable object → All its fields are final and cannot change after construction. Any "change" actually creates a new object instead of modifying the existing one. 2. How to Create an Immutable Class Rules for making a class immutable: Declare the class as final → So it can’t be subclassed and modified. Make all fields private and final → So values can’t be changed. No setter methods → Only getters to access values. Initialize fields in the constructor → So values are set only once. If a field is mutable (like Date or List), return a clone from getter instead of the actual object. Example: import java.util.Date; final class Employee { private final String name; private final Date joinDate; public Employee(String name, Date joinDate) { this.name = name; this.joinDate = new Date(joinDate.getTime()); // defensive copy } public String getName() { return name; } public Date getJoinDate() { return new Date(joinDate.getTime()); // defensive copy } }

    3. Advantages of Immutable Classes Thread-safe → No synchronization needed (good for concurrent programming). Cacheable → Same object can be reused (like String pool). Predictable behavior → No accidental changes. 4. Disadvantages More objects may be created → can cause higher memory usage if used excessively. Performance hit when frequent modifications are needed (because each "change" creates a new object). 5. Examples of Immutable Classes in Java String All wrapper classes (Integer, Long, Double, etc.) java.time classes (LocalDate, LocalTime, etc.)



    Why multiple inheritance is not possible in java?


    Java doesn’t allow multiple inheritance with classes to avoid the Diamond Problem and keep the language simpler and safer.




    Comments

    Popular posts from this blog

    Two Sum II - Input Array Is Sorted

    Comparable Vs. Comparator in Java

    Increasing Triplet Subsequence