OOP in Java: Inheritance, Polymorphism and Abstraction
Codevity Admin · 10/25/2026
Step 8 of 38 · Java Interview Preparation for Beginners · Stage 2: Object-oriented programming
Codevity Admin · 10/25/2026
Object-oriented programming (OOP) is the biggest topic in Java interviews, and it hides many "tricky" questions. This article follows them in the order interviewers usually ask.
| Pillar | Idea | How Java expresses it |
|---|---|---|
| Encapsulation | Hide internal state behind a controlled interface | private fields with getters and methods |
| Inheritance | Reuse and extend a class | class Dog extends Animal (one superclass only) |
| Polymorphism | One call, different behaviour depending on the actual object | Method overriding and interfaces |
| Abstraction | Show what an object does, hide how | abstract classes and interfaces |
Overriding rules: the method must be visible and not final, it may return a narrower (covariant) type, it cannot reduce access (a public method cannot become package-private), and it cannot throw broader checked exceptions. Always add @Override so the compiler checks the signature for you.
Only instance methods take part in dynamic dispatch. static methods belong to the class, so a subclass method with the same signature hides the parent's method. private methods are not inherited at all. And fields are never polymorphic: a field access uses the variable's declared type.
public class Polymorphism {
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(animal.speak()); // Woof overriding: the object's real type decides
System.out.println(animal.name); // Animal fields are not polymorphic: the variable's type decides
System.out.println(Animal.kind()); // Animal static methods belong to the class
System.out.println(Dog.kind()); // Dog
}
}
class Animal {
String name = "Animal";
String speak() { return "..."; }
static String kind() { return "Animal"; }
}
class Dog extends Animal {
String name = "Dog"; // hides the field, does not override it
@Override String speak() { return "Woof"; }
static String kind() { return "Dog"; } // hides the static method
}Try it in the override versus hiding snippet.
| Abstract class | Interface | |
|---|---|---|
| Purpose | A partly built base for closely related classes | A contract that unrelated classes can implement |
| Instance state (fields) | Yes | No. Fields are implicitly constants |
| Constructors | Yes | No |
| Method bodies | Yes, mixed with abstract methods | Abstract by default. , (Java 8) and (Java 9) methods may have a body |
| Inheritance | A class extends one class | A class can implement many interfaces |
| Access modifiers on members | Any | Methods are |
Use an interface for a capability (, , ), and an abstract class when subclasses share state or code.
Can an abstract class have a constructor? Yes. It runs (through ) whenever a subclass object is created, and it initializes the shared state. You just cannot call on the abstract class itself.
| Modifier | Visible to |
|---|---|
| Everyone | |
| The same package and subclasses in any package | |
| (none) package-private | The same package only. This is the default |
| The declaring class only |
Keep fields and expose behaviour, so you can validate input now and change the internals later without breaking callers:
public static finaldefaultstaticprivatepublicComparableRunnableDescribablesuper(...)newpublicprotectedprivateprivatefinalStringObjecttoString()equals()hashCode()@OverrideDog.speak()EmployeecalculatePay()public class Shapes {
public static void main(String[] args) {
Shape shape = new Circle(2);
System.out.printf("%s: %.2f%n", shape.name(), shape.area()); // Circle: 12.57
System.out.println(shape.describe()); // I am a Circle
}
}
interface Describable {
String name();
default String describe() { return "I am a " + name(); } // default method (Java 8)
}
abstract class Shape implements Describable {
private final String name;
protected Shape(String name) { this.name = name; } // abstract classes can have constructors
public String name() { return name; }
abstract double area();
}
class Circle extends Shape {
private final double radius;
Circle(double radius) { super("Circle"); this.radius = radius; }
double area() { return Math.PI * radius * radius; }
}public class Bank {
public static void main(String[] args) {
Account account = new Account();
account.deposit(50);
System.out.println(account.getBalance()); // 50
}
}
class Account {
private long balance;
public long getBalance() { return balance; }
public void deposit(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount must be positive");
balance += amount;
}
}