Interview questions
4 subscribers
6 files
3 links
Answers to common Java Backend questions

My Linked in: www.linkedin.com/in/axmadullo-ubaydullayev-0738a1210

Tg: @HardWorker3334
Download Telegram
What Happens if main() is Not Static

When you type java MyApp, the Heap is empty — no objects exist yet. The JVM needs an entry point to start your programme.

If main() were non-static — JVM would need to create an object first. But which constructor? What arguments? What if it throws an exception? JVM has no information to decide.

With static — JVM calls MyApp.main(args) directly on the class level. No object needed, no guessing.

Without static — JVM doesn't even try. You get:

Error: Main method not found, please define as public static void main(String[] args)

Java 21 introduced a preview feature — you can write just void main() without static, without String[] args, without public. JVM handles object creation internally.

#Java #JVM #Static #Main
Memory Leaks in Java — yes, even with GC

A lot of devs think "Java has GC, so no memory leaks". I thought the same. Then I spent 3 hours debugging why our app crashed every night at 3am.
Turned out — one unclosed DB connection. That's it.

GC is smart but it's not magic. It removes objects nobody references anymore. The problem is you — you keep referencing objects you forgot about.
Classic examples from real life:
You register a listener and never unregister. You put something in ThreadLocal and move on. You cache objects in a static list and never clean it. You open a connection and "handle it later".

The app doesn't crash immediately. It slows down. Memory grows. GC works harder. Until one night — boom.
The fix isn't a library or a pattern. It's just discipline — close what you open.

#Java #Backend #RealTalk
GC Pauses Increased After a Small Code Change

A small code change caused GC pauses to spike. How?

Most developers add a log line, forget to close a connection, or switch from primitive to wrapper type. Looks innocent. But the chain reaction is brutal.
Too many objects created → Eden fills fast → Minor GC runs constantly → objects survive and get promoted to Old Generation → Old Gen fills up → Major GC kicks in → long Stop The World pause.
Minor GC pauses are short — milliseconds. Major GC pauses are long — hundreds of milliseconds or even seconds. That's the difference between a smooth app and one that freezes randomly.
The culprit is almost always objects living longer than they should — unclosed connections, unbounded caches, forgotten listeners.

#Java #JVM #GC #Performance
Increasing Heap Size Made Performance Worse

Counterintuitive but real. Here's why.

Bigger heap means more objects can live in memory. GC runs less frequently — sounds good. But when Major GC finally kicks in it has to scan the entire heap.
512MB heap → Major GC → 200ms pause
16GB heap → Major GC → 10 second pause 💀
App doesn't crash. It just freezes for 10 seconds randomly. Users think it's dead.
More heap = less frequent but more painful GC pauses.
The real fix is not throwing more memory at the problem. Fix memory leaks first. Then if you still need large heap — switch to ZGC or Shenandoah which keep pauses under 1ms regardless of heap size.

#Java #JVM #GC #Performance #Heap
== vs equals() in Java
== compares memory addresses — are these two variables pointing to the same object in heap?
equals() compares content — are these two objects meaningfully the same?
Default equals() from Object class just does ==. The magic happens when you override it — like String does, comparing character by character.
Two Dogs with the same name are two different objects at different heap addresses. == returns false. Override equals() and it returns true.
Important rule — whenever you override equals() always override hashCode() too. Otherwise HashMap and HashSet break completely.
#Java #CoreJava #Equals #Hashcode

Shallow Copy vs Deep Copy
Shallow copy — copies the object but nested objects are still shared. Change a nested object in the copy and the original changes too.
Deep copy — copies everything completely. Original and copy are fully independent. Change anything in one — the other doesn't care.
Most common approach for deep copy in real projects — copy constructor, or serialize then deserialize, or libraries like ModelMapper.
#Java #CoreJava #DeepCopy #ShallowCopy

Serialization in Java
Serialization converts an object into a byte stream so it can be saved to a file, sent over a network, or stored in cache.
Deserialization is the reverse — byte stream back to object.
Serializable is a marker interface — no methods, just tells JVM this class can be serialized.
Used for — saving object state to file, sending objects between services, storing in Redis, deep copying objects.
The output is binary — not human readable. If you need human readable use JSON instead.
#Java #Serialization #CoreJava

transient vs volatile
Two completely different problems — just both are field modifiers.
volatile — always read fresh value from main memory, bypassing CPU cache. Solves visibility problem between threads.
transient — skip this field during serialization. Field won't be written to file or sent over network. Most common use — sensitive data like passwords and tokens you never want leaving the application.
#Java #CoreJava #Volatile #Transient #Threads

Reflection in Java
Reflection API gives access to private fields, methods, constructors and annotations at runtime — bypassing normal access rules.
Spring uses it heavily — creating beans without you calling new, injecting dependencies into private fields with @Autowired, scanning annotations like @Service and @Transactional.
JUnit finds @Test methods via reflection. Jackson reads object fields to convert to JSON. Hibernate maps fields to database columns.
Downside — slow, breaks encapsulation, and Java 9+ restricts access to internal JDK classes via module system. One of the biggest reasons companies stayed on Java 8 for so long.
#Java #Reflection #CoreJava #Spring

Abstract Class vs Interface
Abstract class — use when classes share common state and behavior. Supports only one extends. Can have instance fields, concrete methods, abstract methods.
Interface — use when unrelated classes share a contract. A class can implement many interfaces. Since Java 8 supports default and static methods too.
Real use case difference — abstract class is what you ARE, interface is what you CAN DO.
Vehicle is an abstract class — Car and Truck share speed, acceleration, fuel logic.
Flyable is an interface — Bird, Airplane, Superman are completely unrelated but all can fly.
#Java #CoreJava #AbstractClass #Interface #OOP

Design Patterns in Java
Patterns are proven solutions to common software design problems. Three categories:
Creational — how objects are created.
Singleton — one instance across entire app. DB connections, Logger, Spring beans by default.
Factory — delegate object creation to a method. Spring BeanFactory, JDBC DriverManager.
Builder — construct complex objects step by step. Lombok @Builder, HTTP request builders.
Structural — how objects are composed.
Proxy, Adapter, Decorator — Spring AOP uses Proxy pattern heavily.
Behavioral — how objects communicate.
Observer, Strategy, Template Method — used everywhere in frameworks.
#Java #DesignPatterns #CoreJava #Spring
🔒 JPA — @Transactional

"The session stays open until the job finishes."

• Guarantees ACID — all or nothing
• Keeps Hibernate session alive for the entire method
• Without it → session closes after first query → LazyInitializationException
• readOnly=true → skips dirty checking → faster reads, no accidental writes
• spring.jpa.open-in-view=true (default) keeps session open till HTTP response — hides real problems, disable it
• Dirty checking: Hibernate tracks changes and auto-flushes at transaction end

💡 Reminder: No @Transactional = no session = no lazy loading.

#Java #JPA #Hibernate #Transactional #ACID #SpringBoot #EPAM
🔧 JPA — FETCH JOIN & @EntityGraph

"Tell Hibernate exactly what to load, exactly when you need it."

• FETCH JOIN → collapses N+1 into 1 single SQL query
@EntityGraph → same idea, but without writing JPQL
• Both keep FetchType LAZY but load eagerly on demand
• Loop after FETCH JOIN = iterating memory, not hitting DB
• Use FETCH JOIN when you KNOW you'll need the children
• Don't use it blindly — fetching unnecessary data is still waste

💡 Reminder: LAZY is the default. FETCH JOIN is your controlled override.

#Java #JPA #Hibernate #FetchJoin #EntityGraph #SpringBoot #EPAM
🚨 JPA — The N+1 Problem

"You asked for 1 list. Hibernate made 1001 queries."

• 1 query fetches all parents
• N queries fire — one per parent — to fetch their children
• With 1000 users → 1001 DB hits
• Root cause: LAZY loading triggered inside a loop
• Grows silently — works fine in dev, crashes in production
• How to spot it: same query shape repeating in logs with different IDs
• Enable spring.jpa.show-sql=true to see it happening live

💡 Reminder: The loop is not the problem. DB roundtrips inside the loop are.

#Java #JPA #Hibernate #NPlus1 #Performance #SpringBoot #EPAM
JPA — FetchType: LAZY vs EAGER

"EAGER loads children when parent is fetched. LAZY loads children only when you actually call them."

• LAZY = load on demand
• EAGER = load everything immediately ⚠️
• Default: @OneToMany → LAZY, @ManyToOne → EAGER, @OneToOne → EAGER
• EAGER with large data = fetching millions of rows you didn't ask for
• Always prefer LAZY, load eagerly only when you explicitly need it
• Use FETCH JOIN or @EntityGraph to control loading, not EAGER

💡 Golden rule: Always LAZY. Load eagerly only when you choose to.

#Java #JPA #Hibernate #SpringBoot #Backend #EPAM
🔗 JPA — Cascade Types

"When something happens to the parent, the same happens to the child."

• PERSIST → save parent = save children
• REMOVE → delete parent = delete children
• MERGE → update parent = update children
• ALL → all of the above
• Cascade is NOT a DB feature — it's pure Hibernate logic
• DB has its own version: ON DELETE CASCADE (they're independent)
• Without cascade → you must save/delete every child manually

💡 Reminder: Cascade flows Parent → Child, not the other way around.

#Java #JPA #Hibernate #SpringBoot #Backend #EPAM
Create custom thread safe HashMap.
Liquibase real work experience.
Use @Profile in real project.
Java 21, except virtuals threads feature.
OOP - is just implements, extends classes or more than this.
Working with files, in case if we remove the package from the project.
Try to say with steps in real project experience.
How we can resolve the huge data amounts, in case if the time duration of coming the data is 5-10 seconds.
Show up theoretical knowledge.
Questions:

1. How it works @Transactional under the hood?
2. Imagine we have method A and method B, on A method put @Transactional and it calls method B, and there is some problem, will be roll backed everything to the start position or not?
3. Why ArrayList looks up data in O(1) date period, how it works under the hood?


Books:

1. Designing Data-Intensive Applications

Video_lessons:

In russian: www.youtube.com/@java-guru
In English: www.youtube.com/@EugeneSuleimanov