Java Programming Language
Chapter 7: Interfaces and Abstract Classes
Abstraction in Java
Course: 4343203 - Java Programming
What We'll Cover
- Abstract Classes
- Abstract Methods
- Interface Fundamentals
- Interface Implementation
- Multiple Inheritance with Interfaces
- Default and Static Methods in Interfaces
- Abstract Classes vs Interfaces
- Practical Examples
Abstraction Concepts
Abstract Classes
Abstract Class is a class that cannot be instantiated and may contain abstract methods
Abstract Class Characteristics
Key Features:
- Declared with abstract keyword
- Cannot be instantiated directly
- Can have both abstract and concrete methods
- Can have constructors, fields, and static methods
- Must be extended by concrete classes
Abstract Class Example:
abstract class Animal {
// Concrete field
protected String name;
protected int age;
// Constructor
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
// Concrete method
public void sleep() {
System.out.println(name + " is sleeping");
}
// Abstract method (must be implemented)
public abstract void makeSound();
public abstract void move();
}
Concrete Implementation:
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public void makeSound() {
System.out.println(name + " barks: Woof!");
}
@Override
public void move() {
System.out.println(name + " runs on four legs");
}
}
public class TestAbstract {
public static void main(String[] args) {
// Animal animal = new Animal(); // Error!
Dog dog = new Dog("Buddy", 3);
dog.makeSound(); // Buddy barks: Woof!
dog.move(); // Buddy runs on four legs
dog.sleep(); // Buddy is sleeping
}
}
Abstract Methods
Abstract Method Rules:
- Declared with abstract keyword
- No method body (only signature)
- Must be implemented in concrete subclasses
- Cannot be private, final, or static
abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Abstract methods - must be implemented
public abstract double area();
public abstract double perimeter();
// Concrete method
public void displayInfo() {
System.out.println("Color: " + color);
System.out.println("Area: " + area());
System.out.println("Perimeter: " + perimeter());
}
}
class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
class Rectangle extends Shape {
private double width, height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
@Override
public double perimeter() {
return 2 * (width + height);
}
}
Interfaces
Interface defines a contract that implementing classes must follow
Interface Characteristics
Key Features:
- Declared with interface keyword
- All methods are implicitly public and abstract
- All fields are implicitly public, static, and final
- Cannot be instantiated
- Supports multiple inheritance
Interface Definition:
interface Drawable {
// Constant (public static final)
String TYPE = "DRAWABLE";
// Abstract methods (public abstract)
void draw();
void resize(double factor);
}
interface Movable {
void move(int x, int y);
void rotate(double angle);
}
interface Printable {
void print();
boolean canPrint();
}
Interface Implementation:
class Rectangle implements Drawable, Movable {
private int x, y, width, height;
public Rectangle(int x, int y, int w, int h) {
this.x = x; this.y = y;
this.width = w; this.height = h;
}
@Override
public void draw() {
System.out.println("Drawing rectangle at ("
+ x + "," + y + ")");
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
}
@Override
public void move(int newX, int newY) {
this.x = newX;
this.y = newY;
}
@Override
public void rotate(double angle) {
System.out.println("Rotating by " + angle);
}
}
Multiple Interface Implementation
Multiple Interfaces:
interface Flyable {
void fly();
double getAltitude();
}
interface Swimmable {
void swim();
double getDepth();
}
class Duck implements Flyable, Swimmable {
private double altitude = 0;
private double depth = 0;
@Override
public void fly() {
altitude = 100;
System.out.println("Duck is flying");
}
@Override
public double getAltitude() {
return altitude;
}
@Override
public void swim() {
depth = 5;
System.out.println("Duck is swimming");
}
@Override
public double getDepth() {
return depth;
}
public void walk() {
System.out.println("Duck is walking");
}
}
Interface Inheritance:
interface Vehicle {
void start();
void stop();
}
interface LandVehicle extends Vehicle {
void accelerate();
void brake();
}
interface WaterVehicle extends Vehicle {
void sail();
void anchor();
}
// Multiple interface inheritance
interface AmphibiousVehicle
extends LandVehicle, WaterVehicle {
void switchToLandMode();
void switchToWaterMode();
}
class AmphibiousCar
implements AmphibiousVehicle {
@Override
public void start() {
System.out.println("Engine started");
}
@Override
public void stop() {
System.out.println("Engine stopped");
}
// Implement all other methods...
}
Default and Static Methods in Interfaces
Java 8+ introduced default and static methods in interfaces
Default Methods
Default Method Features:
- Provide default implementation in interface
- Can be overridden in implementing classes
- Enable interface evolution without breaking existing code
- Declared with default keyword
Interface with Default Methods:
interface Calculator {
// Abstract methods
double add(double a, double b);
double subtract(double a, double b);
// Default methods
default double multiply(double a, double b) {
return a * b;
}
default double divide(double a, double b) {
if (b == 0) {
throw new ArithmeticException("Division by zero");
}
return a / b;
}
default void printResult(double result) {
System.out.println("Result: " + result);
}
}
Implementation:
class BasicCalculator implements Calculator {
@Override
public double add(double a, double b) {
return a + b;
}
@Override
public double subtract(double a, double b) {
return a - b;
}
// Can override default methods if needed
@Override
public void printResult(double result) {
System.out.println("Calculation result: " + result);
}
// multiply() and divide() are inherited
}
public class TestDefault {
public static void main(String[] args) {
Calculator calc = new BasicCalculator();
double sum = calc.add(10, 5);
calc.printResult(sum); // Uses overridden method
double product = calc.multiply(4, 3);
calc.printResult(product); // Uses default method
}
}
Static Methods in Interfaces
Interface with Static Methods:
interface MathUtils {
// Static constants
double PI = 3.14159;
double E = 2.71828;
// Abstract method
double calculate();
// Static methods
static double square(double x) {
return x * x;
}
static double cube(double x) {
return x * x * x;
}
static double power(double base, double exp) {
return Math.pow(base, exp);
}
static boolean isEven(int num) {
return num % 2 == 0;
}
static boolean isPrime(int num) {
if (num < 2) return false;
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) return false;
}
return true;
}
}
Using Static Methods:
class NumberProcessor implements MathUtils {
private double value;
public NumberProcessor(double value) {
this.value = value;
}
@Override
public double calculate() {
return MathUtils.square(value);
}
}
public class TestStatic {
public static void main(String[] args) {
// Call static methods directly
double result1 = MathUtils.square(5);
double result2 = MathUtils.cube(3);
System.out.println("5² = " + result1);
System.out.println("3³ = " + result2);
// Check if numbers are prime
System.out.println("Is 17 prime? " +
MathUtils.isPrime(17));
System.out.println("Is 20 even? " +
MathUtils.isEven(20));
// Use with implementing class
NumberProcessor processor =
new NumberProcessor(4);
System.out.println("Calculated: " +
processor.calculate());
}
}
Abstract Classes vs Interfaces
Detailed Feature Comparison
| Feature | Abstract Class | Interface |
|---|---|---|
| Keyword | abstract class | interface |
| Inheritance | Single inheritance (extends) | Multiple inheritance (implements) |
| Methods | Abstract and concrete methods | Abstract, default, and static methods |
| Fields | Any type of fields | Only public static final constants |
| Constructor | Can have constructors | Cannot have constructors |
| Access Modifiers | All access modifiers | Methods are public by default |
| Instantiation | Cannot be instantiated | Cannot be instantiated |
| Use Case | When classes share common code | When defining contracts for behavior |
Practical Examples
Real-World Example: Media Player
// Interface for playable media
interface Playable {
void play();
void pause();
void stop();
double getDuration();
// Default method
default void displayInfo() {
System.out.println("Media duration: " + getDuration() + " seconds");
}
}
// Abstract class for media files
abstract class MediaFile implements Playable {
protected String fileName;
protected double fileSize;
protected boolean isPlaying;
public MediaFile(String fileName, double fileSize) {
this.fileName = fileName;
this.fileSize = fileSize;
this.isPlaying = false;
}
// Concrete method
public void displayFileInfo() {
System.out.println("File: " + fileName + " (" + fileSize + " MB)");
}
// Abstract method
public abstract String getFormat();
}
// Concrete implementations
class AudioFile extends MediaFile {
private double duration;
public AudioFile(String fileName, double fileSize, double duration) {
super(fileName, fileSize);
this.duration = duration;
}
@Override
public void play() {
isPlaying = true;
System.out.println("Playing audio: " + fileName);
}
@Override
public void pause() {
System.out.println("Audio paused: " + fileName);
}
@Override
public void stop() {
isPlaying = false;
System.out.println("Audio stopped: " + fileName);
}
@Override
public double getDuration() {
return duration;
}
@Override
public String getFormat() {
return "MP3";
}
}
class VideoFile extends MediaFile {
private double duration;
private String resolution;
public VideoFile(String fileName, double fileSize, double duration, String resolution) {
super(fileName, fileSize);
this.duration = duration;
this.resolution = resolution;
}
@Override
public void play() {
isPlaying = true;
System.out.println("Playing video: " + fileName + " (" + resolution + ")");
}
@Override
public void pause() {
System.out.println("Video paused: " + fileName);
}
@Override
public void stop() {
isPlaying = false;
System.out.println("Video stopped: " + fileName);
}
@Override
public double getDuration() {
return duration;
}
@Override
public String getFormat() {
return "MP4";
}
}
// Usage
public class MediaPlayerDemo {
public static void main(String[] args) {
Playable[] playlist = {
new AudioFile("song1.mp3", 5.2, 210),
new VideoFile("movie.mp4", 1200, 7200, "1080p"),
new AudioFile("song2.mp3", 4.8, 180)
};
for (Playable media : playlist) {
if (media instanceof MediaFile) {
((MediaFile) media).displayFileInfo();
}
media.displayInfo();
media.play();
System.out.println();
}
}
}
Chapter Summary
Abstract Classes:
- Partial implementation with abstract methods
- Cannot be instantiated
- Support constructors and instance variables
- Single inheritance only
- Mix of abstract and concrete methods
Interfaces:
- Pure contracts with method signatures
- Support multiple inheritance
- Default and static methods (Java 8+)
- All fields are constants
- Achieve loose coupling
Next: Packages and Access Control
Thank You!
Questions?
Ready to explore Packages and Access Control!

