Inheritance lets one class reuse and extend another. Polymorphism lets you treat different subclasses through a single shared type. Together they are how Java models "is-a" relationships.
Inheritance with extends
public class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
Dog inherits everything Animal has, and @Override replaces makeSound() with its own version - this is method overriding.
Polymorphism in action
Animal a = new Dog();
a.makeSound(); // "Woof!" - Java calls Dog's version at runtime
The variable's declared type is Animal, but the actual object is a Dog - Java always calls the real object's method, not the declared type's. This is what lets you write code that works with any Animal subclass without knowing which one in advance.
Abstract classes
An abstract class cannot be instantiated directly and can declare methods with no body, forcing subclasses to implement them:
public abstract class Shape {
public abstract double area(); // no body - subclasses must implement this
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public double area() {
return Math.PI * radius * radius;
}
}
Interfaces
An interface is a pure contract - it says what a class must be able to do, without any implementation. A class can implement multiple interfaces, even though it can only extend one class:
public interface Payable {
double calculatePay();
}
public class Employee implements Payable {
@Override
public double calculatePay() {
return 50000.0;
}
}