Java Streams
Java Streams
Lazy + short circuiting - means till there is a terminal op nothing happens + 1 element goes
through the entire pipeline before next is processed so it gets short circuited if findAny or findAll
matches
Intermediate operations
1. map(x->x*x)
2. filter(x->x%2==0)
3. sorted() , sorted([Link]()),
sorted([Link](Person::getName).thenComparing(Person::getAge)),
sorted([Link](String::length).reversed())
4. flatMap(x->[Link]())
5. distinct()
6. peek(x->sopln(x)); - dont modify elements here
7. skip(1)
8. limit(10)
Terminal operators
1. collect([Link]()) [Link](“,”) [Link](x->x%2) this
groups by numbers even or odd. In the groupingby you have to tell how to form the key.
[Link](x -> x % 2 == 0) boolean exp
2. forEach(x->sopln(x))
3. reduce(“”,(p,e)->p+” ”+e);
4. count()
5. allMatch(x->[Link](“s”))
6. anyMatch
7. findFirst(), findAny() these return Optional
groupingBy(
Employee::getDepartment,
[Link]([Link](Employee::getSalary))
)
2nd arg is how to collect the values. Generally the default is [Link]()
groupingBy(
Employee::getDepartment,
[Link]()
)
groupingBy(
Employee::getDepartment,
[Link](Employee::getName, [Link]())
)
groupingBy(
Employee::getDepartment,
[Link]()
)
groupingBy(
Employee::getDepartment,
[Link](
[Link](),
list -> [Link]()
.sorted([Link](Employee::getSalary).reversed())
.limit(2)
.collect([Link]())
)
)
🔐 1. Access Modifiers
Modifier Same Same Subclass (diff Outside
Class Package pkg)
private ✅ ❌ ❌ ❌
default ✅ ✅ ❌ ❌
protect ✅ ✅ ✅ ❌
ed
public ✅ ✅ ✅ ✅
🔥 Rules
❌ NOT allowed:
Case Allowed?
Reduce visibility ❌
✅ Allowed:
Case Example
❌ Illegal combinations:
Parent Child Result
static non-static ❌
non-static static ❌
✅ Valid:
Case Behavior
🧊 4. Final Keyword
final variable
● Must be initialized once
● Cannot be reassigned
final method
● Cannot be overridden
final class
● Cannot be extended
🧩 5. Abstract vs Interface
Abstract Class
● Can have:
○ Abstract methods
○ Concrete methods
○ Instance variables
● Supports constructors
🔥 Key Differences
Feature Abstract Interface
Class
Multiple inheritance ❌ ✅
Constructors ✅ ❌
State ✅ ❌ (only
constants)
🧱 7. Constructors + Inheritance
Rules:
❌ Error case:
class A {
A(int x) { }
}
class B extends A {
B() { } // ❌ ERROR
}
👉 Fix:
B() {
super(10);
}
👉 Don’t expose:
setBalance()
⚠️9. Common Interview Traps
❌ 1. @Override misconception
● Not required
● Compiler still checks overriding
❌ 3. Overloading vs Overriding
Feature Overloading Overriding
Real meaning:
class BankAccount {
👉 Why private?
💡 Interview answer:
“Encapsulation is about controlling access and ensuring data integrity, not just
hiding variables.”
void eat() {}
Composition
class Engine {}
class Car {
● Loose coupling
● More flexible
● Avoids deep hierarchy problems
● “has-a” relationship
3. Polymorphism
Compile-time (Overloading)
void add(int a, int b)
Runtime (Overriding)
class Animal {
void sound() {}
void sound() {}
💡 Interview twist:
1. static
👉 Belongs to class, not object
class A {
Key points:
● Loaded once (class loading)
● Shared across objects
● Can’t access non-static directly
💡 Interview question:
2. final
Final variable → constant
💡 Interview:
super();
🔹 PART 3: Quick JVM Intro (light today,
deep tomorrow)
Just basics today:
Q1:
Why do we prefer composition over inheritance?
Q2:
Can we override a static method? Why or why not?
Q3:
Q4:
What is the difference between compile-time and runtime polymorphism?
After that:
👉 I’ll correct them (strictly like an interviewer)
👉 Then move you to JVM + Memory (very important round topic)
no you are teaching v surface level. that's fine this time but if i try to override a final method
what happens i get error right
❓ Your question:
If I try to override a final method, I get an error right?
✅ Short answer:
Yes — compile-time error.
class B extends A {
👉 Error:
So Java enforces:
● No overriding allowed
● Method is bound early (compile-time guarantee)
💡 Result:
● JVM can optimize it (inlining, etc.)
● No need for dynamic dispatch
⚠️Interview Trap
👉 Question:
Answer:
✅ YES — it is inherited
❌ But it cannot be overridden
👉 So:
They behave closer to static binding, even though they are not static.
🧪 Follow-up (you answer now)
Q1:
What happens if a class is final?
Q2:
What happens if a variable is final but is a reference type?
Example:
Then we’ll move to JVM + Memory (deep, not surface level) where most candidates struggle.
child class can have methods that parent doesn't have right. in that case if A is parent B is child
n i do A a = new B(); will i get error;
Good question — this is exactly where interviews start testing real understanding vs surface
knowledge.
✅ First part:
Can child class have methods that parent doesn’t have?
✔️Yes, absolutely.
class A {
void show() {}
class B extends A {
void display() {}
👉 Why?
Because:
● Reference type = A
● Compiler only allows methods present in A
🔥 Example
class A {
void show() {
[Link]("A");
class B extends A {
void show() {
[Link]("B");
void display() {
[Link]("Display");
A a = new B();
Otherwise:
👉 This is downcasting
A a = new A();
B b = (B) a;
Q2:
Why is method access decided at compile time but method execution at runtime?
1. this is specialisation. it will not give any error. the fields of the child which aren't in parent will
remain null or the default for primitives. 2. method access is decided at compile time because
we have all the classes and we can ensure that the method is present and will be availible.
executiion is decided at runtime based on the object passed
Good attempt — but I’m going to be strict here because this is exactly where interviews reject
people.
❌ Q1 — Your answer is incorrect
You said:
“It will not give any error… child fields will be null/default”
👉 This is wrong.
✅ Correct behavior:
A a = new A();
B b = (B) a;
❌ Throws ClassCastException
🔥 Why?
Because:
👉 JVM says:
✅ Valid case:
A a = new B();
B b = (B) a; // ✅ works
👉 Because object is actually B
❌ Invalid case:
A a = new A();
🔥 Interview-level answer:
“Downcasting compiles, but at runtime it checks the actual object type. If the object
is not an instance of the target class, a ClassCastException is thrown.”
class A {
void show() {
[Link]("A");
class B extends A {
void show() {
[Link]("B");
A a = new B();
[Link]();
Q2:
What about this?
class A {
[Link]("A");
class B extends A {
[Link]("B");
A a = new B();
[Link]();
Answer carefully.
1. b 2. A
Good — both answers are correct. Now let’s go from correct → interview strong.
✅ Q1 Analysis (Runtime
Polymorphism)
A a = new B();
[Link]();
✔ Output: B
🔥 Why?
● Method is overridden
● Java uses dynamic method dispatch
● JVM looks at actual object (B) at runtime
🧠 Interview-grade answer:
“Since show() is overridden, Java uses runtime polymorphism and calls the
method based on the actual object type, which is B.”
[Link]();
✔ Output: A
👉 Compiler decides:
🔥 Interview-grade answer:
“Static methods are not polymorphic. They are resolved at compile time based on
the reference type, so [Link]() is called.”
Polymorphism ✅ Yes ❌ No
A a = new B();
👉 For static methods:
It’s just:
int x = 10;
class B extends A {
int x = 20;
A a = new B();
[Link](a.x);
Answer this, then we move to JVM + Memory (deep dive — interview critical).
Good instinct — 10 is correct. Now let’s fix the “idk why” part, because this is a very common
interview trap.
🔥 What’s happening here?
class A {
int x = 10;
class B extends A {
int x = 20;
A a = new B();
[Link](a.x);
👉 Output: 10
🔍 Why?
1. Field access is decided at compile time
● Based on reference type (A)
👉 Compiler sees:
Aa
So it binds:
a.x → A.x
2. No dynamic dispatch for variables
● JVM does NOT check actual object for fields
● No overriding for variables — only hiding
Field
a.x → A.x ❌ no polymorphism
👉 So Java keeps:
int x = 10;
void print() {
[Link](x);
class B extends A {
int x = 20;
void print() {
[Link](x);
A a = new B();
[Link]();
👉 Think carefully:
● Field?
● Method?
● Which x?
Answer this — then we move to JVM + Memory (where most candidates break).
20
✅ Correct — 20
Now let’s break why, because this question is designed to confuse you.
🔍 Code again
A a = new B();
[Link]();
🧠 Step-by-step reasoning
1. Method call → runtime polymorphism
[Link]();
2. Inside [Link]()
[Link](x);
👉 So:
x → B.x → 20
⚡ Key Insight
Even though reference is A, once method dispatch happens, execution is entirely
inside B
Now:
[Link]();
🧠 Interview-ready summary
“Method overriding enables runtime polymorphism, so the method from the actual
object type is executed. Inside that method, all member access happens in that
class’s context.”
Tell me step-by-step:
● What happens from .java → execution
● Where things are stored (heap, stack, etc.)
wait suppose parent has a method and child doesn't override. but can it overload the method
from parent
🔍 Example
class A {
void show(int x) {
class B extends A {
void show(String s) {
🧠 What’s happening?
● Parent has: show(int)
● Child adds: show(String)
Same method ✅ ✅
name
Same parameters ❌ ✅
Inheritance required ❌ ✅
[Link](10); // ?
[Link]("hello"); // ?
👉 What happens?
🧠 Why?
Because:
● Reference type = A
● Compiler only sees methods in A
● show(String) is not in A
🔥 Key Insight
Overloading is resolved at compile time, based on reference type
class B extends A {
@Override
void show(int x) {
[Link]("B int");
void show(String s) {
[Link]("B string");
A a = new B();
[Link](10); // ?
👉 Output: "B int" (runtime polymorphism)
🧠 Interview-ready answer
“Yes, a child class can overload a parent method by defining a method with the
same name but different parameters. Overloading is resolved at compile time
based on the reference type, unlike overriding which is resolved at runtime.”
void show(Object o) {
[Link]("Object");
class B extends A {
void show(String s) {
[Link]("String");
A a = new B();
[Link]("hello");
🔍 Code again
class A {
void show(Object o) {
[Link]("Object");
class B extends A {
void show(String s) {
[Link]("String");
A a = new B();
[Link]("hello");
✅ Correct Answer:
👉 "Object"
void show(Object o)
void show(String s)
👉 Compiler checks:
● "hello" is a String
● Can it match show(Object)? ✅ YES (String is an Object)
👉 So it binds:
show(Object)
3. Runtime step
Now JVM checks:
● Is show(Object) overridden in B?
👉 ❌ No
So it calls:
[Link](Object)
But here:
🔥 Interview One-Liner
“Even though the object is B, method overloading is resolved at compile time using
the reference type, so show(Object) is called.”
🧠 Question:
When you run:
User u = new User();
Explain in detail:
suppose parent show returns object and child show returns string is that overriding
Excellent — now you’re touching advanced overriding rules. This is a very common interview
deep-dive question.
✅ Short Answer:
✔️Yes, this is overriding — and it’s allowed.
This is called covariant return type.
🔍 Example
class A {
Object show() {
return "A";
class B extends A {
@Override
👉 Java allows:
class B extends A {
👉 Why?
🔥 Interview-level explanation
“Java supports covariant return types, meaning an overridden method can return a
subtype of the original method’s return type, ensuring flexibility while maintaining
type safety.”
🔥 Real-world intuition
Think:
Animal getAnimal()
Dog getAnimal()
class B extends A {
Cover:
1. Compilation (.java → .class)
2. Class loading
3. Memory allocation (heap, stack, etc.)
4. Object creation steps
👉 Short answer:
You’re very close, but there are 5–6 critical edge cases that interviewers LOVE which are
missing.
class A {
A() {
[Link]("A");
class B extends A {
B() {
[Link]("B");
👉 Output:
B
🧠 2. Private members are NOT inherited
class A {
class B extends A {
void print() {
// [Link](x); ❌ ERROR
👉 Important:
● Not accessible
● Not visible in child
class B extends A {
🧠 4. Final + Inheritance
● Final class → cannot extend
● Final method → cannot override
👉 Used when:
● Explicit override
● [Link]()
Bad example:
class Bird {
void fly() {}
👉 Why?
🧠 9. Downcasting safety
You learned casting, but add:
if (a instanceof B) {
B b = (B) a;
class B extends A {
👉 Rule:
● Definitions
They DO ask:
🚀 Decision
👉 You are ready to move on.
Next:
👉 Include:
● Compilation
● Class loading
● Memory (heap, stack, method area)
● Object creation steps
Good — this is a must-know concept, especially when you move into interfaces and design.
🔍 Visual Structure
A
/\
B C
\/
void show() { }
class B extends A {
class C extends A {
Now:
class D extends B, C { } // ❌ not allowed in Java
👉 Question:
[Link]("A");
interface B extends A {}
interface C extends A {}
class D implements B, C {
[Link]("D resolves");
[Link]("B");
interface C {
[Link]("C");
class D implements B, C {
[Link](); // OR [Link]()
🧠 Interview-level answer
“The diamond problem occurs in multiple inheritance when a class inherits the
same method from multiple sources, leading to ambiguity. Java avoids this with
classes by not supporting multiple inheritance, and resolves it in interfaces by
forcing the implementing class to override the conflicting method.”
⚡ Key Takeaways
● ❌ Multiple inheritance of classes → NOT allowed
● ✅ Multiple inheritance of interfaces → allowed
● ⚠️Conflict → must override
[Link]("A");
interface B {
[Link]("B");
class C implements A, B {
i dont think i think it will take order in which interfaces are implemented. in this case A will be
printed
❌ Nope — this is exactly where Java is strict, and your intuition (order-based resolution) is
wrong.
🔥 Correct Answer:
👉 Compilation ERROR
🔍 Code again
class C implements A, B {
❗ Why error?
Both interfaces have:
So class C gets:
● [Link]()
● [Link]()
👉 JVM/compiler says:
⚠️Important:
Java does NOT resolve based on order
This is by design:
class C implements A, B {
@Override
[Link]("Resolved");
🔥 Or explicitly choose:
class C implements A, B {
@Override
[Link](); // or [Link]();
🧠 Interview-level explanation
“If multiple interfaces provide the same default method, Java throws a compile-time
error due to ambiguity. The implementing class must explicitly override and resolve
the conflict.”
🔵 JVM + Memory
Cover:
Good correction — you’re right. For JVM especially, surface-level Q&A won’t work.
I’ll teach it properly first, then we’ll do interview-style drilling.
[Link] → [Link]
👉 Output:
● Bytecode (platform-independent)
● NOT machine code
🧠 Key point:
JVM does NOT understand Java — it understands bytecode
java User
2. Linking
Split into 3:
a. Verification
b. Preparation
👉 Here:
x = 0 (not 10 yet)
c. Resolution
3. Initialization
👉 Now static variables get actual values:
x = 10;
🧠 Interview One-liner:
“Class loading consists of loading, linking (verification, preparation, resolution), and
initialization.”
🔹 2. Stack
● Stores method calls + local variables
● Each thread has its own stack
👉 u (reference) → stack
👉 object → heap
🔹 4. PC Register
● Tracks current instruction
🔥 Visual
Stack Heap
----- -----
🔥 Step-by-step
1. Class is loaded (if not already)
3. Default initialization
int x = 0;
boolean flag = false;
4. Constructor runs
User() {
x = 10;
5. Reference assigned
u → points to object in heap
⚠️Common Misconceptions
❌ “Objects are stored in stack”
👉 Wrong — only references are in stack
👉 In YOUR words:
firstly when this user class is compiled by javac a .class file is created which contains bytecode.
this bytecde is platform independent and is interpreted by the jvm (which is platform specific)
into machine code. then when the jvm comes accross that statement first the class is loaded
into memory then the linking phase takes place where jvm checks the bytecode for
security/correctness, static variables are initialized, static blocks run etc. memory is allocated for
this obj in the heap space and then the default initialisation takes place before constructor is
called. then a reference to that obj memory is created and stored in the stack
This is a good answer — you’ve got the overall flow right. Now I’ll refine it to interview-perfect
level and fix a few subtle mistakes (these matter).
⚠️Corrections (IMPORTANT)
❌ 1. “JVM interprets bytecode into machine
code”
👉 Not fully accurate.
✅ Better answer:
JVM uses Interpreter + JIT (Just-In-Time compiler)
Correct sequence:
🔹 Linking → Preparation
● Static variables get default values
👉 Here:
x=0
🔹 Initialization phase
● Static variables get actual values
● Static blocks run
x = 10
👉 Slight refinement:
✅ Strong Answer:
“First, the Java source file is compiled using javac into a .class file containing
bytecode. This bytecode is platform-independent and executed by the JVM using
an interpreter and JIT compiler.
When the program runs, the JVM loads the User class using the class loading
process, which includes loading, linking (verification, preparation, and resolution),
and initialization. During preparation, static variables are assigned default values,
and during initialization, actual values and static blocks are executed.
When the statement new User() is encountered, memory is allocated in the heap
for the object. The object fields are first initialized with default values, then the
constructor is executed to initialize them properly.
The reference variable u is stored in the stack and points to the object in the heap.”
Good attempt — but this has a serious misconception. Let’s fix it cleanly.
✅ Correct Answer
User u1 = new User();
🔥 Important Concept
🧠 Class loading is NOT tied to object existence
● Objects → live in heap
● Class metadata → lives in method area (Metaspace)
👉 Even if all objects are garbage collected:
● App servers
● Dynamic modules
● Custom class loaders
🧠 Interview-level answer
“Class loading happens only once per class loader. Creating multiple objects does
not reload the class. Garbage collection removes objects from heap but does not
unload classes in normal execution.”
🔥 Key takeaway
Concept Happens Multiple Times?
Class Loading ❌ Once
String s2 = "hello";
✅ Correct Concept
Classes are NOT loaded right after compilation.
🔍 What actually happens
Step 1: Compilation
javac [Link]
👉 Creates:
[Link]
🔥 Key Rule
Classes are loaded lazily (when needed), not all at once
🧠 Example
class A {
static {
[Link]("A loaded");
class B {
static {
[Link]("B loaded");
new A();
Output:
A loaded
👉 B is NEVER loaded
Because it's never used
🔥 Interview one-liner
“Java uses lazy class loading — classes are loaded into memory only when they
are first actively used, not immediately after compilation.”
⚡ Your earlier doubt (now clarified)
User u1 = new User();
👉 Flow:
String s2 = "hello";
only 1. stored in heap. both s1 and s2 point to the same heap address
Good — you’re close, but this is where interviewers expect precision, not approximation.
String s2 = "hello";
🔥 Important refinement
❗ Not just “heap”
It’s specifically in the String Constant Pool (SCP)
🧠 What is SCP?
● Special memory area inside heap
● Stores unique string literals
● Avoids duplicate objects
Step 2:
String s2 = "hello";
s2 ----/
🔥 Interview one-liner
“String literals are stored in the String Constant Pool, and duplicate literals reuse
the same object to optimize memory.”
still 1 because string constant pool ensures that we don't have duplicates
❌ This is a very common mistake — and interviewers LOVE this question because it exposes
this exact misunderstanding.
🔥 Correct Answer
String s1 = new String("hello");
🧠 Breakdown (step-by-step)
Step 1: "hello" (literal)
● JVM checks String Constant Pool (SCP)
● If not present → creates 1 object in SCP
✅ Now:
SCP → "hello"
🔥 Final count
Location Objects
SCP 1
Heap 2
Total 3
📦 Memory Diagram
Stack:
s1 → Heap Obj1
s2 → Heap Obj2
Heap:
Obj1 → "hello"
Obj2 → "hello"
SCP:
"hello"
String s2 = "hello";
[Link](s1 == s2);
Answer this — we’re getting into deep string behavior now (== vs equals next)
false memory address is different. 1 obj hello for the literal in scp. s1 creates new obj in heap.
s2 points to scp. address is diff. .equals would return true as it compares value not add
You didn’t just answer — you explained the memory model + comparison behavior, which is
🔥
String s2 = "hello";
[Link](s1 == s2);
✅ Final Answer
👉 Output: false
🧠 Why?
● "hello" → stored in String Constant Pool (SCP)
● new String("hello") → creates a new object in heap
● So:
○ s1 → heap object
○ s2 → SCP object
✅ equals()
[Link](s2) → true
👉 Because:
🔥 Interview-level explanation
“== compares references, so it returns false because one object is in heap and the
other in the String Constant Pool. However, equals() returns true because String
overrides it to compare values.”
Say:
String s2 = [Link]();
[Link](s1 == s2);
After this:
We’ll cover:
idk what interning is. and before i forget idk static blocks
Perfect — this is exactly how gaps should surface. Both interning and static blocks are very
important and often asked.
🔍 Example
String s1 = new String("hello");
String s2 = [Link]();
Step-by-step
1. "hello"
● Goes into SCP (if not already present)
2. new String("hello")
● Creates a new object in heap
SCP → "hello"
3. [Link]()
👉 JVM checks:
s2 → SCP object
✅ Output
[Link](s1 == s2); // false
🔥 KEY RULE
intern() returns reference from the String Constant Pool
💣 Important variation
String s1 = new String("hello").intern();
String s2 = "hello";
[Link](s1 == s2);
👉 Output: true
🧠 Interview one-liner
“Interning ensures that identical string values share a single reference from the
String Constant Pool, optimizing memory usage.”
🟡 2. Static Blocks (VERY IMPORTANT)
🔍 Example
class A {
static {
[Link]("Static block");
[Link]("Main method");
✅ Output
Static block
Main method
🔥 Why?
● Class loads → static block runs
● Then main() executes
🧠 Key Properties
✅ Runs only once
Even if you create multiple objects:
new A();
new A();
✅ Used for:
● Static initialization
● Loading configs
● Database setup (older patterns)
⚠️Order of execution
class A {
static {
[Link]("Block 1");
static {
[Link]("Block 2");
}
}
🧠 Important distinction
Concept Runs when
💣 Trap Question
class A {
static {
[Link]("Static");
A() {
[Link]("Constructor");
new A();
new A();
}
👉 Output?
String s2 = "hello";
[Link](s1 == s2);
✅ Perfect. Both answers are 100% correct — and more importantly, your reasoning is
aligned now.
🔥 Quick confirmation
1. Interning
String s1 = new String("hello").intern();
String s2 = "hello";
Constructor
Constructor
👉 Because:
🔍 Example
String s = "hello";
[Link](" world");
[Link](s);
👉 Output: hello
❗ Why?
● concat() does NOT modify existing string
● It creates a new object
"hello" → unchanged
✅ Correct way
s = [Link](" world");
3. Thread safety
● No synchronization needed
💣 Interview Trap
String s = "hello";
s = s + " world";
s += i;
✅ StringBuilder
StringBuilder sb = new StringBuilder();
[Link]("hello");
🔥 Key properties
Feature StringBuilder
Mutable ✅
Thread- ❌
safe
Fast ✅
✅ StringBuffer
Feature StringBuffer
Mutable ✅
Thread- ✅ (synchronized)
safe
Slow ❌
🔥 Interview one-liner
“String is immutable, while StringBuilder and StringBuffer are mutable. StringBuilder
is preferred for performance, while StringBuffer is used in multi-threaded
environments.”
String s2 = "hello";
[Link](s1 == s2);
[Link](s1 == s3);
[Link]([Link](s3));
After this:
👉 We move to equals() vs hashCode() (VERY CRITICAL for interviews)
3 objects 1 for hello in scp 1 for world in scp 1 for the new hello world that s points to
✅ Good thinking — you’re very close, but let’s make it precise and interview-perfect.
🔍 Question
String s = "hello";
s = s + " world";
❌ Your answer:
3 objects: "hello", "world", "hello world"
🧠 Step-by-step
1.
String s = "hello";
2.
s = s + " world";
This is internally:
new StringBuilder()
.append(s)
.append(" world")
.toString();
🔥 What gets created?
✅ 1. "world" (or " world")
● Goes to SCP
⚠️Important correction
👉 The final "hello world" is NOT placed in SCP automatically
✅ Final count
Object Location
"hello" SCP
StringBuilder Heap
🔥 Interview-safe answer
“Three string objects are involved: ‘hello’ and ‘ world’ in the String Constant Pool,
and a new ‘hello world’ object in heap. Additionally, a StringBuilder object is created
internally.”
String s2 = "hello";
[Link](s1 == s2);
[Link](s1 == s3);
[Link]([Link](s3));
👉 Give:
● Outputs
● Proper reasoning (SCP vs heap + == vs equals)
After this:
We move to:
🔴 equals() vs hashCode() (SUPER
IMPORTANT — asked everywhere)
true false true s1 and s2 point to hello in scp. s3 is an obj in heap. s1 s2 have same address s1
s3 dont and == compares references. equals compares values
You covered:
● SCP vs heap ✔️
● == vs equals() ✔️
● Reference vs value ✔️
🧠 1. equals()
🔍 Default behavior (Object class)
public boolean equals(Object obj) {
👉 By default:
🧠 2. hashCode()
🔍 What is it?
A numeric value representing the object (used in hashing)
int hashCode()
🔥 Why needed?
Used in:
● HashMap
● HashSet
● Hashtable
🔴 RULE 2:
If hashCode() same → equals() MAY or MAY NOT be true
String name;
Person(String name) {
[Link] = name;
[Link]([Link](p2));
👉 Output: false
❗ Why?
● equals() not overridden → reference comparison
[Link](new Person("A"));
[Link](new Person("A"));
[Link]([Link]());
👉 Output?
❌ Most people say: 1
✅ Correct: 2
🧠 Why?
● hashCode different → different buckets
● equals not even checked properly
✅ Correct Implementation
class Person {
String name;
Person(String name) {
[Link] = name;
@Override
Person p = (Person) o;
return [Link]([Link]);
}
@Override
return [Link]();
🔥 Interview one-liner
“Whenever we override equals(), we must override hashCode() to maintain
consistency, especially for hash-based collections.”
[Link]([Link]());
After this:
👉 We go to Collections (deep + practical)
Good catch — and this is important. Let’s finish StringBuilder vs StringBuffer properly
(interview depth) before moving on.
🧠 Core Idea
Feature String StringBuilder StringBuffer
Mutable ❌ ✅ ✅
Thread-safe ❌ ❌ ✅
👉 StringBuilder:
🔥 2. Thread Safety
🔴 StringBuilder
● NOT synchronized
● Faster
● Use in single-threaded
🔴 StringBuffer
● Synchronized methods
● Thread-safe
● Slower
🔍 Internally
public synchronized StringBuffer append(String str)
⚡ Interview one-liner
“StringBuilder is preferred in most cases due to better performance, while
StringBuffer is used only when thread safety is required.”
s += i;
❌ Very slow
[Link](i);
✅ Fast
🔥 4. Memory Behavior
String:
1000 operations → ~1000 objects
StringBuilder:
1000 operations → 1 object
[Link]([Link]()); // 16
👉 Default capacity = 16
When exceeded:
newCapacity = (old * 2) + 2
💣 Trap Question
StringBuilder sb = new StringBuilder("hello");
String s = [Link]();
[Link](" world");
[Link](s);
👉 Output?
⚠️Important concept
● toString() creates new String object
● Further changes in SB do NOT affect String
🧠 Another trap
StringBuilder sb1 = new StringBuilder("abc");
[Link](sb1 == sb2);
👉 Output?
String s = [Link]();
[Link](" world");
[Link](s);
2.
StringBuilder sb1 = new StringBuilder("abc");
[Link](sb1 == sb2);
After this:
👉 We go to Collections (very deep + practical + must-know)
hello. false
✅ Perfect — both