Bird
Raised Fist0

In-Memory File System

LLDhardInterview freq: medium
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
FileSystemNode abstract class

FileSystemNode is an abstract class holding shared state like name and permissions which interfaces cannot hold in Java.

🎯 Tests whether candidate knows abstract class is needed because shared mutable state (name, permissions) cannot be in interfaces in Java.
public abstract class FileSystemNode {
    protected String name;
    protected int permissions;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getPermissions() { return permissions; }
    public void setPermissions(int permissions) { this.permissions = permissions; }
}
Directory composition in FileSystem

FileSystem composes a root Directory, owning its lifecycle, enforcing strong containment (composition).

🎯 Tests if candidate understands composition means Directory cannot exist independently outside FileSystem lifecycle.
public class FileSystem {
    private final Directory root = new Directory("/");
    public Directory getRoot() { return root; }
}
Directory children management with synchronization

Directory manages children nodes in a Map with synchronized methods to ensure thread-safe add/remove operations.

🎯 Tests if candidate can explain why synchronized is needed on addChild/removeChild to prevent concurrent modification issues.
public class Directory extends FileSystemNode {
    private final Map<String, FileSystemNode> children = new HashMap<>();
    public synchronized void addChild(FileSystemNode node) {
        children.put(node.getName(), node);
    }
    public synchronized void removeChild(String name) {
        children.remove(name);
    }
    public FileSystemNode getChild(String name) {
        return children.get(name);
    }
}
SymbolicLink realization

SymbolicLink extends FileSystemNode and holds a reference to another FileSystemNode, demonstrating realization of link behavior.

🎯 Tests if candidate understands SymbolicLink is a concrete subclass realizing link semantics by referencing target node.
public class SymbolicLink extends FileSystemNode {
    private final FileSystemNode target;
    public SymbolicLink(String name, FileSystemNode target) {
        this.name = name;
        this.target = target;
    }
    public FileSystemNode getTarget() { return target; }
}
📐
Class Diagram
Class Diagram
       +----------------------+
       | <<Abstract>>         |
       | FileSystemNode       |
       |----------------------|
       | - name: String       |
       | - permissions: int   |
       |----------------------|
       | + getName(): String  |
       | + setName(String)    |
       | + getPermissions():int|
       | + setPermissions(int)|
       +----------------------+
                │ extends
       +----------------------+
       | File                 |
       |----------------------|
       | - content: byte[]    |
       |----------------------|
       | + read(): byte[]     |
       | + write(byte[]):void |
       +----------------------+
                │ extends
       +----------------------+
       | Directory            |
       |----------------------|
       | - children: Map<String, FSNode> |
       |----------------------|
       | + addChild(FSNode): void [sync] |
       | + removeChild(String): void [sync] |
       | + getChild(String): FSNode       |
       +----------------------+
                ◆ composition
       +----------------------+
       | FileSystem           |
       |----------------------|
       | - root: Directory    |
       |----------------------|
       | + getRoot(): Directory|
       | + search(String): List<FSNode> |
       +----------------------+
                │ association
       +----------------------+
       | SymbolicLink         |
       |----------------------|
       | - target: FSNode     |
       |----------------------|
       | + getTarget(): FSNode|
       +----------------------+
                │ extends

This class diagram illustrates key Java OOP design decisions for an in-memory file system. FileSystemNode is an abstract class because it holds shared mutable state like name and permissions, which interfaces cannot hold in Java. The FileSystem class composes a root Directory, enforcing lifecycle ownership via composition. Directory manages its children with synchronized methods to ensure thread safety during concurrent modifications, demonstrating precise use of Java's synchronized keyword. SymbolicLink extends FileSystemNode and realizes link behavior by holding a reference to a target node, showing inheritance and realization. These decisions enforce SOLID principles like Single Responsibility and Open-Closed, while leveraging Java-specific constructs such as abstract classes and synchronized methods for concurrency control.

Primary Focus

✓ Abstract class vs interface state + Composition lifecycle + Realization + Synchronization

Practice

(1/5)
1. In the Hotel Management System, the RoomManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is this the correct choice?
easy
A. Prototype pattern, to clone RoomManager instances efficiently.
B. Factory pattern, because it controls object creation centrally.
C. Builder pattern, to construct complex RoomManager objects step-by-step.
D. Singleton pattern, to ensure only one instance manages room allocation.

Solution

  1. Step 1: Identify the pattern from constructor and method

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single shared instance, which matches the Singleton pattern.
  2. Step 2: Why Singleton fits RoomManager

    RoomManager manages shared state like room availability; having multiple instances risks inconsistent state. Singleton ensures centralized control.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized static getInstance() -> Singleton [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
2. In designing the Airline Reservation System, should the Seat entity be modeled as an abstract class or an interface, and why?
easy
A. Abstract class, because seats share common state like seat number and class, and behavior like availability checks.
B. Interface, because it allows multiple inheritance and flexible seat type combinations.
C. Interface, because seats only define behavior without any shared state or implementation.
D. Abstract class, because interfaces cannot enforce method signatures for seat operations.

Solution

  1. Step 1: Analyze seat characteristics

    Seats have shared state (seat number, class) and common behavior (availability, booking), which suggests code reuse.
  2. Step 2: Abstract class vs interface

    Abstract class allows shared state and default behavior implementation, while interface cannot hold state and only defines method signatures.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Shared state + behavior -> abstract class [check]
Hint: Shared state needs abstract class, interfaces lack fields [check]
Common Mistakes:
3. In a multi-threaded chain of responsibility, if the method handleRequest() is not synchronized, which exact sequence of events can cause a request to be handled twice by two handlers?
medium
A. Thread 1 checks canHandle() -> true, context switch; Thread 2 checks canHandle() -> true; both handle the request concurrently.
B. Thread 1 finishes handling, Thread 2 starts after; no overlap occurs.
C. Thread 1 and Thread 2 both call handleRequest() simultaneously and both skip to next handler.
D. Thread 1 locks the handler, Thread 2 waits until unlock; no double handling.

Solution

  1. Step 1: Identify race condition

    Without synchronization, two threads can both see canHandle() as true before either marks the request handled.
  2. Step 2: Trace thread interleaving

    Thread 1 checks canHandle() -> true, context switch before marking handled; Thread 2 also checks canHandle() -> true and proceeds; both handle the same request.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Check-then-act gap causes double handling [check]
Hint: Check-then-act gap causes double handling [check]
Common Mistakes:
4. In a plugin loader, the loadPlugin() method checks if a plugin is already loaded before loading it. Without synchronizing this method, what exact thread interleaving causes the same plugin to be loaded twice?
medium
A. Thread 1 checks isLoaded() -> false, context switch; Thread 2 checks isLoaded() -> false; both proceed to load the plugin.
B. Thread 1 and Thread 2 both wait on a lock, causing deadlock.
C. Thread 1 loads plugin, but Thread 2 never sees the updated loaded state due to caching.
D. Thread 1 and Thread 2 both call loadPlugin() simultaneously and both throw exceptions.

Solution

  1. Step 1: Trace the check-then-act sequence without synchronization

    Thread 1 calls isLoaded() and sees false, then context switches before loading.
  2. Step 2: Thread 2 also calls isLoaded() and sees false, both threads proceed to load plugin concurrently, causing duplicate loading.

  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act allows double loading due to race [check]
Hint: Check-then-act without sync -> double load race condition [check]
Common Mistakes:
5. Consider a tryConsume() method in TokenBucketRateLimiter that checks if tokens are available and then decrements the count without synchronization. Which exact thread interleaving causes double token consumption?
medium
A. Thread 1 reads tokens=1, decrements; Thread 2 waits until Thread 1 finishes
B. Thread 1 increments tokens while Thread 2 decrements tokens simultaneously
C. Thread 1 and Thread 2 both block on synchronized method, then proceed sequentially
D. Thread 1 checks tokens > 0 -> true, context switch; Thread 2 checks tokens > 0 -> true; both decrement tokens

Solution

  1. Step 1: Identify check-then-act race condition

    Without synchronization, both threads can read tokens > 0 before either decrements.
  2. Step 2: Trace exact interleaving causing double consumption

    Thread 1 checks tokens > 0 -> true, context switch; Thread 2 checks tokens > 0 -> true; both proceed to decrement, consuming same token twice.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Unsynchronized check-then-act allows double token consumption [check]
Hint: Check tokens > 0 twice before decrement -> double consume [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard