Part 2: Advanced Abstraction (Mid-Level)


📝 About This Part
In Part 1 of this series, we explored the fundamentals of abstraction in Java — what it is, why it matters in OOP, and the most common beginner-level interview questions.
But abstraction questions don’t stop at the basics. For developers with 4–8 years of experience, interviewers dig deeper. They test not just whether you can define abstraction, but whether you understand:
How abstraction evolved with Java 8 and 9 features
The tricky nuances between abstraction and encapsulation
How abstraction interacts with multiple inheritance, lambdas, and enums
Edge cases like calling abstract methods in constructors or using private methods in interfaces
This part of the series is designed for those preparing for mid-level Java interviews — where abstraction isn’t just about definitions but about design choices, pitfalls, and real-world scenarios.
By the end of this post, you’ll be comfortable answering advanced questions that separate surface-level knowledge from true understanding.
🔵 Q1: Can you achieve abstraction without using abstract classes or interfaces? How?
💡 Answer:
Yes — while abstract classes and interfaces are the primary tools for abstraction in Java, you can achieve abstraction in other ways as well.
👉 At its core, abstraction is about hiding implementation details and exposing only necessary behavior. This can be achieved through:
✅ 1. Encapsulation with Access Modifiers
By using private
fields and exposing only necessary methods, you abstract away the internal complexity.
class Car {
private String engine; // hidden detail
public void start() { // exposed action
igniteEngine();
System.out.println("Car started");
}
private void igniteEngine() {
System.out.println("Igniting " + engine);
}
}
➡️ Here, users only see start()
. They don’t care how the engine starts — that’s abstraction without abstract classes or interfaces.
✅ 2. Composition and Delegation
Instead of inheritance, abstraction can be achieved by delegating tasks to helper classes.
class PaymentProcessor {
private PaymentService service = new PaymentService();
public void process() {
service.connect();
service.pay();
}
}
➡️ The consumer of PaymentProcessor
doesn’t see the internal complexity of PaymentService
.
✅ 3. Using Anonymous Classes and Lambdas (Java 8+)
Abstraction can also be implemented inline with anonymous classes or lambdas:
Runnable task = () -> System.out.println("Running task...");
new Thread(task).start();
➡️ The caller doesn’t know how Thread
manages execution. They only know the task will “run.”
⚡️ Cross-Questions Interviewers Might Ask:
🔹 Q: If we can achieve abstraction through encapsulation, why do we need abstract classes and interfaces?
➡️ Answer: Abstract classes and interfaces provide formal contracts. Encapsulation hides data, but abstraction formalizes behavior across multiple classes — enabling polymorphism.
🔹 Q: Can we say abstraction = interfaces only?
➡️ Answer: No. Interfaces are just one way to enforce abstraction. Even without interfaces, hiding details and exposing only necessary behavior is abstraction.
🔹 Q: In real-world systems, where do we see abstraction beyond abstract classes/interfaces?
➡️ Answer:
JDBC hides database details behind a driver interface.
Java Collections API hides sorting algorithms behind methods like
Collections.sort()
.Frameworks like Spring abstract object creation via Dependency Injection.
🎯 Key Takeaway for Interviews:
Abstraction is not limited to abstract classes and interfaces. It’s a design principle. You can achieve it with access modifiers, delegation, frameworks, and functional constructs. Abstract classes and interfaces just provide the strongest guarantees.
🔵 Q2: How does abstraction differ from encapsulation at a deeper level?
💡 Answer:
Although abstraction and encapsulation are related, they serve different purposes in object-oriented programming. Interviewers love this because many candidates confuse the two.
✅ Core Difference
Aspect | Abstraction | Encapsulation |
Definition | Hiding implementation details and exposing only essential features. | Hiding internal state and controlling access via methods. |
Focus | What an object does. | How data is protected and accessed. |
Achieved By | Abstract classes, interfaces, method overriding, design contracts. | Private fields, getters/setters, access modifiers. |
Goal | Reduce complexity, improve design flexibility. | Protect state, ensure data integrity. |
Level | Design level (blueprints, contracts). | Implementation level (access control, safety). |
⚡️ Illustration with Example
Abstraction (What it does):
interface Payment {
void process(double amount); // contract only
}
➡️ Here, you only know that payments can be processed. You don’t know how.
Encapsulation (How it’s done safely):
class BankAccount {
private double balance; // hidden
public void deposit(double amount) { // controlled access
if (amount > 0) balance += amount;
}
}
➡️ Balance is hidden, only modified through controlled methods.
⚠️ Special Attention (Interview Trap):
Many interviewers will ask:
“Is encapsulation part of abstraction, or are they completely separate?”
👉 Correct answer:
They are different but complementary.
Encapsulation helps implement abstraction.
Without encapsulation, it’s hard to truly abstract internal complexity because details may leak.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: Can we achieve abstraction without encapsulation?
➡️ Answer: Yes, in theory. For example, an interface defines a contract (abstraction) without hiding any state. But in practice, encapsulation strengthens abstraction by preventing direct access to implementation details.
🔹 Q: Give me a real-world example of both abstraction and encapsulation together.
➡️ Answer:
ATM:
Abstraction: User presses “Withdraw” without knowing backend logic.
Encapsulation: Account balance is private and validated before withdrawal.
🔹 Q: Which is more important: abstraction or encapsulation?
➡️ Answer (balanced): Both are pillars of OOP. Abstraction improves design clarity, while encapsulation ensures data safety and correctness. In practice, they work hand-in-hand.
🎯 Key Takeaway for Interviews:
Abstraction = design contracts (what).
Encapsulation = implementation safety (how).
They are not the same, but they complement each other to produce clean, safe, and scalable code.
🔵 Q3: How do abstract classes enable partial abstraction?
💡 Answer:
An abstract class in Java allows partial abstraction because it can contain both:
Abstract methods → no body, must be implemented by subclasses.
Concrete methods → already implemented and shared across subclasses.
This mix means an abstract class does not enforce 100% abstraction like an interface (pre–Java 8). Instead, it allows you to hide some details (abstract methods) while also sharing common behavior (concrete methods).
✅ Example:
abstract class Vehicle {
// Abstract method → forces subclass to provide its own logic
public abstract void move();
// Concrete method → shared implementation
public void startEngine() {
System.out.println("Engine started...");
}
}
class Car extends Vehicle {
@Override
public void move() {
System.out.println("Car moves on wheels.");
}
}
➡️ Here:
move()
is abstract → forces subclasses (Car
,Bike
,Truck
) to define their own way of moving.startEngine()
is concrete → shared across all vehicles.
Thus, abstraction is partial.
⚠️ Special Attention (Interview Trap):
“Why not just use interfaces instead of abstract classes?”
👉 Correct Answer:
Use interfaces when you want a pure contract (100% abstraction, multiple inheritance).
Use abstract classes when:
You want shared state (fields).
You need common methods with reusable logic.
The classes are closely related.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: Can abstract classes exist without any abstract methods?
➡️ Answer: Yes. Even if an abstract class has only concrete methods, it’s still abstract if declared with abstract
. This prevents direct instantiation and signals it's meant to be a base class.
🔹 Q: Can abstract classes achieve full abstraction?
➡️ Answer: Yes, if you declare only abstract methods. But in practice, interfaces are the better choice for full abstraction.
🔹 Q: Why is it called partial abstraction?
➡️ Answer: Because it lets you abstract only part of the behavior while still providing default implementations for the rest.
🎯 Key Takeaway for Interviews:
Abstract classes provide partial abstraction, balancing between enforced contracts and shared logic. They’re best when you need a common foundation with flexibility for specialization.
🔵 Q4: Why were default and static methods added to interfaces in Java 8?
💡 Answer:
Prior to Java 8, interfaces only contained abstract methods. This meant if you added a new method to an interface, all implementing classes would break because they had to implement that new method.
To solve this backward compatibility problem, Java 8 introduced:
Default Methods → allow interfaces to provide a default implementation.
Static Methods → allow utility/helper methods inside interfaces.
✅ Example: Default Method
interface Payment {
void process(double amount);
// New feature added in Java 8
default void refund(double amount) {
System.out.println("Refund of $" + amount + " initiated.");
}
}
class CreditCardPayment implements Payment {
public void process(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}
➡️ Even though refund()
was added later, existing classes like CreditCardPayment
won’t break because they inherit the default implementation.
✅ Example: Static Method
interface MathUtils {
static boolean isEven(int num) {
return num % 2 == 0;
}
}
➡️ Accessed directly as MathUtils.isEven(10)
without needing an object.
⚠️ Special Attention (Interview Trap):
“If interfaces can now have default methods, what’s the difference between abstract classes and interfaces?”
👉 Correct Answer:
Abstract classes can hold state (instance variables). Interfaces cannot (only constants).
Abstract classes can have constructors. Interfaces cannot.
Abstract classes support single inheritance; interfaces support multiple inheritance.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: What happens if two interfaces provide the same default method?
➡️ Answer: The implementing class must override the method explicitly.
interface A {
default void hello() { System.out.println("Hello from A"); }
}
interface B {
default void hello() { System.out.println("Hello from B"); }
}
class C implements A, B {
public void hello() { // must resolve conflict
A.hello();
}
}
🔹 Q: Why not just add new abstract methods and let classes implement them?
➡️ Answer: That would break backward compatibility for thousands of Java libraries. Default methods were introduced specifically to evolve interfaces safely.
🔹 Q: Can static methods in interfaces be inherited?
➡️ Answer: No. They belong to the interface itself and must be called with the interface name (InterfaceName.methodName()
).
🎯 Key Takeaway for Interviews:
Default and static methods were added in Java 8 to make interfaces more evolution-friendly, solving the problem of backward compatibility while keeping Java’s OOP principles intact.
🔵 Q5: How does Java handle multiple inheritance via interfaces?
💡 Answer:
In Java, a class can implement multiple interfaces, which allows for multiple inheritance of type.
This solves the problem that Java does not allow multiple inheritance of classes (to avoid ambiguity and the diamond problem).
👉 By restricting multiple inheritance to interfaces only, Java ensures:
Flexibility: A class can behave like many types.
Safety: There’s no state (instance variables) in interfaces (pre-Java 8), so no ambiguity in fields.
✅ Example
interface Printer {
void print();
}
interface Scanner {
void scan();
}
class MultiFunctionDevice implements Printer, Scanner {
public void print() {
System.out.println("Printing document...");
}
public void scan() {
System.out.println("Scanning document...");
}
}
➡️ Here, MultiFunctionDevice
inherits behavior from both Printer
and Scanner
.
⚠️ Special Attention (Java 8 and Beyond):
With Java 8’s default methods, interfaces can now have implementation.
This introduces the diamond problem if two interfaces define the same default method.
Example:
interface A {
default void hello() { System.out.println("Hello from A"); }
}
interface B {
default void hello() { System.out.println("Hello from B"); }
}
class C implements A, B {
@Override
public void hello() {
A.super.hello(); // must resolve explicitly
}
}
➡️ Java forces the class (C
) to override and resolve ambiguity, preventing multiple inheritance conflicts.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: Why does Java allow multiple inheritance of interfaces but not classes?
➡️ Answer:
Multiple class inheritance can lead to ambiguity in state (fields) and constructors.
Interfaces are contracts, not state holders (pre-Java 8), making them safe for multiple inheritance.
🔹 Q: What happens if two interfaces define the same constant?
➡️ Answer: It will cause compile-time ambiguity. You must qualify it explicitly using the interface name.
interface A { int VALUE = 10; }
interface B { int VALUE = 20; }
class Test implements A, B {
public void show() {
System.out.println(A.VALUE); // must specify
}
}
🔹 Q: Can interfaces inherit other interfaces?
➡️ Answer: Yes, interfaces can extend multiple other interfaces. This is also multiple inheritance of type.
interface X { void methodX(); }
interface Y { void methodY(); }
interface Z extends X, Y { void methodZ(); }
🎯 Key Takeaway for Interviews:
Java supports multiple inheritance of type via interfaces while avoiding the pitfalls of multiple class inheritance. Since Java 8, if default methods clash, the implementing class must resolve conflicts explicitly.
🔵 Q6: What is the diamond problem, and how does Java resolve it?
💡 Answer:
The diamond problem occurs in multiple inheritance when a class inherits the same method from two different parent types, leading to ambiguity about which method to use.
In Java:
Multiple class inheritance is not allowed (so diamond problem doesn’t occur with classes).
But since Java 8, interfaces can have default methods, which can create diamond-like situations.
✅ Classic Diamond Problem (in other languages like C++):
A
/ \
B C
\ /
D
➡️ If both B and C inherit A.method()
and D extends both B and C, which method()
should D use?
✅ Diamond Problem in Java Interfaces
interface A {
default void greet() { System.out.println("Hello from A"); }
}
interface B {
default void greet() { System.out.println("Hello from B"); }
}
class C implements A, B {
@Override
public void greet() {
A.super.greet(); // explicitly resolve conflict
}
}
➡️ Here, class C
implements both A
and B
, which define the same default method greet()
.
➡️ Java forces C
to override and decide which version to call.
⚠️ Special Attention (Interview Trap):
“What happens if the implementing class doesn’t override the conflicting method?”
👉 It won’t compile. Java requires explicit resolution to eliminate ambiguity.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: Why doesn’t Java allow multiple class inheritance but allows multiple interface inheritance?
➡️ Answer:
Multiple class inheritance can lead to state and constructor ambiguity.
Interfaces don’t carry state (except constants) and only define contracts, making them safer.
🔹 Q: Can diamond problem occur if one interface has an abstract method and the other has a default method?
➡️ Answer: No. The abstract method doesn’t create conflict. The implementing class simply provides its own implementation.
🔹 Q: What happens if two interfaces extend a third interface and redefine the same default method?
➡️ Answer: Still a conflict. The implementing class must override and choose.
interface A {
default void hello() {}
}
interface B extends A {}
interface C extends A {}
class D implements B, C {
public void hello() { System.out.println("Resolved in D"); }
}
🎯 Key Takeaway for Interviews:
The diamond problem in Java arises only with default methods in interfaces (Java 8+).
Java resolves it by forcing the implementing class to override and explicitly choose which method to use — avoiding ambiguity and keeping multiple inheritance safe.
🔵 Q7: Can interface methods be private or protected? What changed in Java 9?
💡 Answer:
Before Java 9:
All interface methods were implicitly
public
andabstract
(exceptdefault
andstatic
methods in Java 8).You could not declare methods as
private
orprotected
in an interface.
From Java 9 onwards:
Private methods in interfaces were introduced to allow code reusability within the interface itself.
Protected methods are still not allowed — because interfaces are about defining public contracts, not inheritance hierarchies with visibility control.
✅ Example (Java 9 Private Methods in Interfaces)
interface Logger {
default void logInfo(String msg) {
log(msg, "INFO");
}
default void logError(String msg) {
log(msg, "ERROR");
}
// private helper method
private void log(String msg, String level) {
System.out.println(level + ": " + msg);
}
}
➡️ Here, the log()
method is private.
➡️ It cannot be called outside the interface, but it helps default methods reuse logic cleanly.
⚠️ Special Attention (Interview Trap):
“Why allow private methods in interfaces but not protected?”
👉 Correct Answer:
Interfaces define public APIs — behavior that classes must follow.
protected
would contradict this because it restricts access to subclasses only, which is against the contract-first design of interfaces.private
methods are fine since they are helpers only for the interface itself, invisible to implementing classes.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: Can we have private static methods in interfaces?
➡️ Answer: Yes. Since Java 9, both private instance methods and private static methods are allowed.
interface MathHelper {
static int square(int x) {
validate(x);
return x * x;
}
private static void validate(int x) {
if (x < 0) throw new IllegalArgumentException("Negative not allowed");
}
}
🔹 Q: Can an interface private method be overridden in implementing class?
➡️ Answer: No. Private methods are not inherited, so they can’t be overridden.
🔹 Q: If I want some methods to be visible only to implementing classes, can I use protected
in interfaces?
➡️ Answer: No. Interfaces don’t support protected
methods because their purpose is to define public behavior contracts. Use an abstract class in such cases.
🎯 Key Takeaway for Interviews:
Pre–Java 9 → all interface methods were public.
Post–Java 9 → private methods (including private static) allowed for code reuse inside interfaces.
protected
is still not allowed because interfaces are meant to expose public contracts only.
🔵 Q8: Does abstraction introduce runtime performance or memory overhead?
💡 Answer:
Yes — abstraction can introduce some indirect overhead, but usually negligible compared to its benefits.
👉 Overheads:
Method calls through abstract references (dynamic dispatch)
When you call a method on an interface or abstract class reference, the JVM uses dynamic binding (vtable lookups) to resolve which method to call.
This adds a tiny runtime overhead, compared to direct calls.
Memory usage
Interfaces don’t hold state (so no memory issue).
Abstract classes may hold common fields, so memory depends on subclass design, not abstraction itself.
Inlining restrictions
- JVM may not inline calls across abstraction boundaries as aggressively as direct method calls (though modern JIT optimizers handle this well).
✅ Example:
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
System.out.println("Drawing Circle");
}
}
public class Test {
public static void main(String[] args) {
Shape s = new Circle(); // reference via abstraction
s.draw(); // dynamic dispatch
}
}
➡️ JVM resolves s.draw()
at runtime → slight overhead, but usually optimized away.
⚠️ Special Attention:
In interviews, never say “abstraction makes programs slow.”
Correct stance: Abstraction introduces minimal overhead, but modern JVM optimizations make it negligible. The design benefits far outweigh the cost.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: So should we avoid abstraction for performance-critical systems?
➡️ Answer: No. Good design is always preferable. Only in ultra-low latency systems (like HFT trading engines) might you trade abstraction for performance.
🔹 Q: How does JVM optimize abstract calls?
➡️ Answer: JIT (Just-In-Time Compiler) performs inlining and monomorphic call site optimization to eliminate overhead.
🎯 Key Takeaway:
Abstraction introduces negligible overhead, mostly in method dispatch. JVM optimizations ensure real-world performance is rarely affected.
🔵 Q9: Can an abstract class implement an interface without overriding all its methods?
💡 Answer:
Yes — an abstract class can implement an interface without providing implementations for all methods.
It then becomes the responsibility of concrete subclasses to implement the remaining methods.
✅ Example:
interface Drawable {
void draw();
void resize();
}
abstract class AbstractShape implements Drawable {
@Override
public void draw() {
System.out.println("Drawing shape...");
}
// resize() left unimplemented → abstract class
}
class Circle extends AbstractShape {
@Override
public void resize() {
System.out.println("Resizing circle...");
}
}
➡️ AbstractShape
provides partial implementation.
➡️ Circle
must implement the remaining resize()
method.
⚠️ Special Attention (Interview Trap):
“If abstract class doesn’t implement all interface methods, is it valid?”
👉 Yes. The compiler is fine because the abstract class itself is not concrete. The enforcement passes to subclasses.
⚡️ Cross-Questions Interviewers Might Ask
🔹 Q: Why would you design it this way?
➡️ Answer: To provide shared logic for multiple subclasses while leaving customization to concrete classes.
🔹 Q: Can an abstract class implement multiple interfaces?
➡️ Answer: Yes. An abstract class can implement multiple interfaces and selectively implement methods from each.
🎯 Key Takeaway:
Abstract classes can implement interfaces partially. This is a powerful pattern for defining shared behavior + extensibility.
🔵 Q10: What happens if an abstract class does not provide an implementation for all interface methods?
💡 Answer:
If an abstract class implements an interface but does not override all its methods, the abstract class itself remains abstract.
➡️ It cannot be instantiated, and the responsibility shifts to its concrete subclasses to provide the missing implementations.
✅ Example
interface Drawable {
void draw();
void resize();
}
abstract class Shape implements Drawable {
@Override
public void draw() {
System.out.println("Drawing shape...");
}
// resize() not implemented → Shape stays abstract
}
class Circle extends Shape {
@Override
public void resize() {
System.out.println("Resizing circle...");
}
}
Shape
does not implementresize()
→ must remain abstract.Circle
provides the implementation → can be instantiated.
⚠️ Special Attention (Interview Trap):
“Will the compiler throw an error if an abstract class skips some interface methods?”
👉 No error, as long as the abstract class itself is declared abstract
. The compiler only forces concrete classes to implement everything.
⚡️ Cross-Questions
🔹 Q: Can an abstract class implement multiple interfaces but skip methods from both?
➡️ Answer: Yes, as long as the class remains abstract. The subclasses must implement the missing ones.
🔹 Q: Can an abstract class partially implement one interface and fully implement another?
➡️ Answer: Yes. The compiler checks completeness separately for each concrete subclass.
🎯 Key Takeaway:
An abstract class can skip some interface methods, but then it must stay abstract. Concrete subclasses bear the final responsibility.
🔵 Q11: Abstract class vs interface in the context of functional programming (Java 8 Lambdas)
💡 Answer:
In Java 8 functional programming, the role of interfaces changed significantly with the introduction of functional interfaces.
This also highlights the distinction between abstract classes and interfaces in the modern Java world.
✅ Functional Interface Example
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
public class Test {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b; // Lambda expression
System.out.println(add.calculate(5, 3)); // Output: 8
}
}
➡️ Interfaces with exactly one abstract method (SAM) can be implemented using lambdas, enabling functional-style programming.
⚡️ Why Not Abstract Classes?
Lambdas work only with functional interfaces, not abstract classes.
Abstract classes can have multiple methods, state, and constructors, making them unsuitable for lambda shorthand.
Interfaces represent behavioral contracts, aligning perfectly with functional programming.
⚠️ Special Attention (Interview Trap):
“Can an abstract class ever be used like a functional interface?”
👉 No. Abstract classes cannot be targets for lambda expressions. Only functional interfaces qualify.
⚡️ Cross-Questions
🔹 Q: What is the role of @FunctionalInterface
?
➡️ Answer: It’s optional, but ensures the interface has exactly one abstract method. Compiler will error out if you add more.
🔹 Q: Can a functional interface have default or static methods?
➡️ Answer: Yes, as long as it has only one abstract method.
@FunctionalInterface
interface Converter<T, R> {
R convert(T input);
default void log(T input) {
System.out.println("Converting: " + input);
}
}
🎯 Key Takeaway:
Interfaces power functional programming in Java 8+ via lambdas and method references.
Abstract classes cannot be used with lambdas.
This marks a big shift where interfaces gained more practical weight in modern Java design.
🔵 Q12: Can you create objects of an abstract class using an anonymous inner class?
💡 Answer:
You cannot directly instantiate an abstract class, but you can create an object of an anonymous inner class that extends it and provides implementations for abstract methods.
✅ Example
abstract class Animal {
abstract void sound();
}
public class Test {
public static void main(String[] args) {
Animal dog = new Animal() { // anonymous inner class
@Override
void sound() {
System.out.println("Woof Woof");
}
};
dog.sound(); // Output: Woof Woof
}
}
➡️ Here, new Animal()
creates an anonymous subclass of Animal
.
⚠️ Special Attention (Trap):
“Can we instantiate abstract class objects?”
👉 Strict answer: No.
But we can instantiate a concrete anonymous subclass of an abstract class.
⚡️ Cross-Questions
🔹 Why use anonymous inner classes instead of regular subclasses?
➡️ When you need one-time use implementations (e.g., in GUI event handlers).
🎯 Takeaway:
Abstract classes can’t be instantiated directly, but anonymous inner classes allow quick one-off implementations.
🔵 Q13: Can constructors in abstract classes call abstract methods? What are the pitfalls?
💡 Answer:
Yes — an abstract class constructor can call an abstract method, but it’s generally a bad practice.
Why?
When the constructor runs, the subclass part of the object is not yet initialized.
If the abstract method relies on subclass fields, it may behave unpredictably (nulls, defaults).
✅ Example (Pitfall)
abstract class Parent {
Parent() {
callMe(); // calls abstract method
}
abstract void callMe();
}
class Child extends Parent {
private String message = "Hello";
@Override
void callMe() {
System.out.println(message.toUpperCase()); // NPE risk
}
}
public class Test {
public static void main(String[] args) {
new Child(); // Risk: message not initialized when callMe() runs
}
}
⚠️ Special Attention:
This is an anti-pattern.
Constructors should initialize fields, not call abstract/overridable methods.
🎯 Takeaway:
Yes, it’s allowed — but avoid it. It can cause unpredictable behavior due to incomplete subclass initialization.
🔵 Q14: Can abstract classes have main()
methods and be run directly?
💡 Answer:
Yes. An abstract class can have a main()
method and be executed just like any other class.
- You still can’t instantiate it, but you can run static methods, including
main()
.
✅ Example
abstract class Test {
public static void main(String[] args) {
System.out.println("Running abstract class main method!");
}
}
➡️ This compiles and runs fine.
⚡️ Cross-Questions
🔹 If abstract classes can run main, what’s the use case?
➡️ For testing, logging, or providing utility/demo entry points.
🎯 Takeaway:
Abstract classes can’t be instantiated, but they can still contain and run main()
methods.
🔵 Q15: Is it possible to use abstraction in enums in Java?
💡 Answer:
Yes. Enums in Java can implement interfaces and declare abstract methods, which each enum constant must implement.
This is a powerful way to use abstraction in enums.
✅ Example
enum Operation {
ADD {
public int apply(int x, int y) { return x + y; }
},
MULTIPLY {
public int apply(int x, int y) { return x * y; }
};
// abstract method to be implemented by each constant
public abstract int apply(int x, int y);
}
public class Test {
public static void main(String[] args) {
System.out.println(Operation.ADD.apply(2, 3)); // 5
System.out.println(Operation.MULTIPLY.apply(2, 3)); // 6
}
}
➡️ Each enum constant (ADD
, MULTIPLY
) implements the abstract method differently.
⚠️ Special Attention:
Enums can’t extend classes (because they implicitly extend java.lang.Enum
), but they can use abstraction via interfaces and abstract methods.
🎯 Takeaway:
Enums are more than constants. They can leverage abstraction by implementing interfaces or defining abstract methods for custom behavior per constant.
🧠 Abstraction in Java – Part 2 Summary
Advanced Interview Questions (4–8 Years Experience)
In this part of the series, we moved beyond the basics and explored advanced and tricky abstraction scenarios that interviewers love to test with mid-level to senior Java developers. These questions highlight modern Java features (Java 8+), pitfalls, and real-world design considerations.
🔍 Here’s what we covered:
Whether abstraction can exist without abstract classes or interfaces
The deeper distinction between abstraction vs. encapsulation
How abstract classes enable partial abstraction
Why Java 8 introduced default and static methods in interfaces
Multiple inheritance of type via interfaces and the diamond problem
Private methods in interfaces (Java 9+) and why
protected
isn’t allowedPerformance considerations of abstraction (dynamic dispatch, memory)
Abstract classes implementing interfaces partially
Abstract classes skipping interface methods and how responsibility passes to subclasses
Interfaces vs abstract classes in functional programming (lambdas)
Anonymous inner classes instantiating abstract classes
Pitfalls of calling abstract methods inside constructors
Abstract classes with a
main()
methodUsing abstraction inside enums
These are not just theory — they reflect common real interview patterns on multiple platforms.
🙌 Enjoyed this deep dive?
If this helped strengthen your understanding of abstraction for interviews, don’t forget to share it, bookmark it, or leave a ❤️ to support the series.
Nitin
Hashnode | Substack | LinkedIn | GIT | Youtube | Instagram
Subscribe to my newsletter
Read articles from Nitin Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Nitin Singh
Nitin Singh
I'm a passionate Software Engineer with over 12 years of experience working with leading MNCs and big tech companies. I specialize in Java, microservices, system design, data structures, problem solving, and distributed systems. Through this blog, I share my learnings, real-world engineering challenges, and insights into building scalable, maintainable backend systems. Whether it’s Java internals, cloud-native architecture, or system design patterns, my goal is to help engineers grow through practical, experience-backed content.