Java Fundamentals — Complete Study Guide
Java With DSA | Core language, OOP, memory, exceptions, generics and modern Java
Java Platform & Execution
Java source code is compiled into platform-independent bytecode. The JVM loads classes, verifies bytecode, executes it and
can use JIT compilation to optimize frequently executed code.
JDK, runtime libraries and JVM responsibilities should be distinguished. The JDK is the developer-facing distribution
containing tools such as javac and the runtime needed to execute Java programs.
Class loading normally involves loading, linking and initialization. Linking includes verification, preparation and resolution.
Static initialization occurs when a class is initialized.
Typical memory areas include heap, per-thread stacks, metaspace and native memory. Objects normally live on the heap
while local variables and stack frames belong to individual threads.
JIT compilation changes the performance model: Java is not simply an interpreter. Hot code can be compiled and optimized
at runtime based on observed execution behavior.
Interview focus: explain what happens from `javac [Link]` to executing `java MyClass`, and distinguish compile-time
errors from runtime exceptions.
Java With DSA — Study Document Page 1
Variables, Types & Operators
Primitive types include byte, short, int, long, float, double, char and boolean. Reference variables hold references to objects
rather than containing the object itself.
Java is statically typed. Local variable type inference with `var` still results in a statically determined type; it does not turn Java
into a dynamically typed language.
Integer arithmetic can overflow silently. For example, multiplying two large int values may wrap around. Use long or explicit
overflow-aware APIs when constraints require it.
Boxing converts primitives to wrapper objects and unboxing performs the reverse. Excessive boxing can create allocation and
performance overhead.
Use `final` to prevent reassignment of a variable, prevent method overriding, or prevent class inheritance depending on where
it is applied.
Operator precedence matters. For complex expressions, parentheses improve readability and reduce subtle mistakes.
Java With DSA — Study Document Page 2
Classes, Objects & Constructors
A class defines state and behavior; an object is a runtime instance of a class. Instance fields belong to objects while static
fields belong to the class.
Constructors initialize object state. Constructor chaining with `this(...)` and superclass construction with `super(...)` should be
understood clearly.
Java does not support user-defined copy constructors as a special language feature, but constructors or factory methods can
implement copying semantics.
Prefer encapsulated state with private fields and intentional methods. Exposing mutable collections directly can break class
invariants.
Static methods are resolved from the reference type rather than dynamically dispatched like overridden instance methods.
Use factory methods when construction needs validation, descriptive names, caching, or multiple creation strategies.
Java With DSA — Study Document Page 3
Inheritance & Polymorphism
Java supports single class inheritance but multiple interface implementation. A subclass inherits accessible behavior from its
superclass and can override methods.
Overriding is runtime polymorphism. Overloading is compile-time selection based on parameter types and is not the same
mechanism.
An upcast such as `Animal a = new Dog()` is safe because every Dog is an Animal. Downcasting requires that the runtime
object actually has the target type.
Use `@Override` to let the compiler verify overriding intent. It prevents many signature mistakes.
Favor composition over inheritance when the relationship is not a true substitutable 'is-a' relationship. Composition often
reduces coupling.
Sealed classes can restrict which classes may extend or implement a type, making domain hierarchies more explicit.
Java With DSA — Study Document Page 4
Interfaces & Abstraction
An interface defines a contract. Modern Java interfaces can contain abstract methods, default methods, static methods and
private helper methods.
An abstract class can hold state and implementation while also requiring subclasses to implement abstract behavior.
Use interfaces when different implementations should satisfy the same capability contract. Use abstract classes when
implementations share substantial state or behavior.
Dependency inversion becomes practical through interfaces: business code can depend on abstractions while infrastructure
provides concrete implementations.
Functional interfaces have one abstract method and work naturally with lambdas. `Predicate`, `Function`, `Consumer` and
`Supplier` are common standard interfaces.
Good abstraction hides decisions that callers should not need to know, rather than merely adding more layers.
Java With DSA — Study Document Page 5
Strings, Arrays & Immutability
String objects are immutable. Operations that appear to modify a String actually produce another String.
String literals can be interned in the String pool. Do not use `==` when the requirement is logical String equality; use
`equals()`.
StringBuilder is preferable to repeated concatenation in loops when many modifications are required. StringBuffer adds
synchronization and is less commonly needed.
Arrays have fixed length and provide fast indexed access. Multidimensional Java arrays are arrays of arrays, so rows can
have different lengths.
Immutable objects are easier to reason about, safer to share and naturally thread-friendly. Defensive copies may be needed
around mutable fields.
Records provide a compact syntax for data carriers with final components and generated accessors, equals, hashCode and
toString.
Java With DSA — Study Document Page 6
equals(), hashCode() & toString()
`equals()` should define logical equality consistent with the class's domain. The usual contract includes reflexivity, symmetry,
transitivity, consistency and non-null behavior.
`hashCode()` must remain consistent while relevant state is unchanged. Equal objects must have equal hashes.
Using mutable fields in hashCode can be dangerous when the object is stored in a HashSet or used as a HashMap key and
those fields later change.
`toString()` is valuable for logs and debugging. A useful implementation exposes relevant state without leaking secrets or
sensitive credentials.
Records automatically provide value-oriented equality based on their components.
Always think about equality semantics before designing a domain object used as a map key.
Java With DSA — Study Document Page 7
Exceptions & Resource Management
Checked exceptions must be handled or declared. Unchecked exceptions derive from RuntimeException and usually indicate
programming errors or invalid runtime conditions.
Catch exceptions at a level where recovery or meaningful translation is possible. Avoid broad catches that hide the actual
problem.
Try-with-resources closes AutoCloseable resources even when exceptions occur. It is preferred for files, streams, database
resources and similar objects.
Exception chaining preserves the original cause. Use the cause when translating lower-level failures into domain-level
exceptions.
Do not use exceptions as normal loop control. Exceptions should represent exceptional conditions.
Design exception messages to provide actionable context while avoiding secrets, tokens and sensitive information.
Java With DSA — Study Document Page 8
Generics
Generics provide compile-time type safety and reduce casts. `List` communicates that the list is intended to contain Strings.
Generic type parameters are erased at runtime in ordinary Java generics. You cannot generally write `new T()` or `[Link]`
without additional type information.
`? extends T` is useful when reading values from a producer. `? super T` is useful when writing values to a consumer. This is
the PECS principle.
Generic methods can infer type parameters from arguments. Bounds can restrict a type parameter such as `>`.
Raw types disable much of generic type safety and should normally be avoided in new code.
Generics and inheritance are not covariant: `List` is not a subtype of `List`.
Java With DSA — Study Document Page 9
Enums, Records & Sealed Types
Enums are full Java types and can contain fields, constructors and methods. They are preferable to magic integer constants
for fixed domains.
Records are concise immutable data carriers. Their components are final, but referenced objects can still be mutable.
Sealed classes and interfaces restrict permitted subtypes. This can improve modeling and enable exhaustive reasoning with
modern pattern matching.
Pattern matching for instanceof can combine type testing and binding, reducing repetitive casts.
Switch expressions can return values and use `yield` in traditional block cases.
These features are most valuable when they make domain models clearer rather than simply making syntax shorter.
Java With DSA — Study Document Page 10
Streams, Lambdas & Optional
A stream represents a pipeline over data. Intermediate operations such as map and filter are lazy; terminal operations trigger
evaluation.
Use `map` for one-to-one transformation, `flatMap` to flatten nested structures, `filter` for selection and `reduce` for
aggregation.
Streams are not automatically faster than loops. For simple hot paths, a loop may be clearer and cheaper.
Optional is useful for expressing an explicitly optional return value. Avoid using Optional as a field or blindly calling `get()`.
Lambda captures can reference effectively final local variables. Mutable shared state inside stream operations can make code
difficult to reason about.
Parallel streams require careful workload and thread-pool considerations; they are not a universal performance switch.
Java With DSA — Study Document Page 11
Java Interview Review
Be ready to explain stack versus heap, pass-by-value, immutability, method overloading versus overriding, interface versus
abstract class, and checked versus unchecked exceptions.
Explain why `String` is immutable, why HashMap depends on equals/hashCode, and why `volatile` does not make `count++`
atomic.
Know common collection complexities and be able to justify a choice based on ordering, lookup, memory, concurrency and
workload.
Practice writing clean code without unnecessary abstractions. Use descriptive names, small methods and explicit invariants.
Senior answers should include trade-offs rather than only definitions: performance versus readability, inheritance versus
composition, and synchronization versus lock-free approaches.
Final checklist: compile mentally, test edge cases, state complexity, and explain why the selected Java feature is appropriate.
Java With DSA — Study Document Page 12