Object-oriented programming in Java

Classes, objects, constructors, encapsulation, inheritance, polymorphism and interfaces, with interactive examples.

Introduction to OOP

Object-Oriented Programming (OOP) is a programming paradigm that organizes code into "objects" that combine related data and behaviors. In Java, everything is an object (except primitive types).

Class

A template or mold that defines the properties and behaviors of an object. It's like a blueprint.

Analogy: The "Coche" (Car) class defines that all cars have a brand, model, and can accelerate.

Object

A concrete instance of a class. It's the "real thing" created from the mold.

Example: A specific car: "Toyota Corolla 2023" with license plate ABC123.

Classes and Objects

Class and Object Simulator

public class Coche { // Atributos (propiedades) private String marca; private String modelo; private int año; private double velocidad; // Constructor public Coche(String marca, String modelo, int año) { this.marca = marca; this.modelo = modelo; this.año = año; this.velocidad = 0.0; } // Métodos (comportamientos) public void acelerar(double incremento) { velocidad += incremento; } public void frenar(double decremento) { velocidad = Math.max(0, velocidad - decremento); } public void mostrarInfo() { System.out.println("Coche: " + marca + " " + modelo + " (" + año + ") - Velocidad: " + velocidad + " km/h"); } }
Object: miCoche
marca "Toyota"
modelo "Corolla"
año 2023
velocidad 0.0

// Crear un objeto (instancia) de la clase CocheCoche miCoche = new Coche("Toyota", "Corolla", 2023);

// Usar métodos del objetomiCoche.acelerar(50);
miCoche.mostrarInfo();

Constructors


public class Estudiante {
    private String nombre;
    private int edad;
    private String carrera;
    
    // 1. Constructor por defecto (sin parámetros)    public Estudiante() {
        this.nombre = "Sin nombre";
        this.edad = 18;
        this.carrera = "No asignada";
    }
    
    // 2. Constructor con parámetros    public Estudiante(String nombre, int edad, String carrera) {
        this.nombre = nombre;
        this.edad = edad;
        this.carrera = carrera;
    }
    
    // 3. Constructor de copia    public Estudiante(Estudiante otro) {
        this.nombre = otro.nombre;
        this.edad = otro.edad;
        this.carrera = otro.carrera;
    }
    
    // 4. Constructor con algunos parámetros (sobrecarga)    public Estudiante(String nombre, int edad) {
        this(nombre, edad, "Ingeniería"); // Llama a otro constructor    }
}

Interactive Demonstration

Access Modifiers

public

Public

Accessible from any class in any package

public class MiClase {
    public int valor; // Accesible desde cualquier parte}
private

Private

Only accessible within the same class

public class MiClase {
    private int secreto; // Solo esta clase puede acceder}
protected

Protected

Accessible in the same class, package and subclasses

public class MiClase {
    protected int familiar; // Clase, paquete y herederas}
(default)

Default

Only accessible in the same package (no modifier)

public class MiClase {
    int paquete; // Solo clases en el mismo paquete}
Modifier Same Class Same Package Subclass Anywhere
private
(default)
protected
public

Encapsulation

Getters and Setters: Protecting the Data

Encapsulation hides a class's internal details and only exposes a controlled interface through public methods (getters and setters).


public class CuentaBancaria {
    // Atributos PRIVADOS (encapsulados)    private String titular;
    private double saldo;
    private String numeroCuenta;
    
    // Constructor
    public CuentaBancaria(String titular, double saldoInicial) {
        this.titular = titular;
        this.saldo = saldoInicial;
        this.numeroCuenta = generarNumeroCuenta();
    }
    
    // GETTERS (métodos para leer)    public String getTitular() {
        return titular;
    }
    
    public double getSaldo() {
        return saldo;
    }
    
    public String getNumeroCuenta() {
        return numeroCuenta;
    }
    
    // SETTERS con validación (métodos para modificar)    public void setTitular(String titular) {
        if (titular != null && !titular.trim().isEmpty()) {
            this.titular = titular;
        }
    }
    
    public void depositar(double cantidad) {
        if (cantidad > 0) {
            saldo += cantidad;
        }
    }
    
    public boolean retirar(double cantidad) {
        if (cantidad > 0 && cantidad <= saldo) {
            saldo -= cantidad;
            return true;
        }
        return false;
    }
    
    private String generarNumeroCuenta() {
        // Método privado, solo usado internamente        return "ES" + (int)(Math.random() * 1000000000);
    }
}
Bank Account
titular "Juan Pérez"
saldo 1000.0 €
numeroCuenta "ES123456789"

Inheritance

Inheritance Tree: People System

Inheritance allows creating new classes based on existing ones, reusing and extending their functionality.

Person

Base Class
nombre String
edad int
presentarse()
caminar()

Student

extends Persona
matricula String
promedio double
estudiar()
presentarse()

Teacher

extends Persona
especialidad String
salario double
enseñar()
calificar()

// CLASE BASEpublic class Persona {
    protected String nombre;
    protected int edad;
    
    public void presentarse() {
        System.out.println("Hola, soy " + nombre);
    }
}

// HERENCIA: Estudiante ES UNA Personapublic class Estudiante extends Persona {
    private String matricula;
    
    // Sobrescritura de método    @Override
    public void presentarse() {
        super.presentarse(); // Llama al método de la clase base        System.out.println("Soy estudiante con matrícula: " + matricula);
    }
    
    public void estudiar() {
        System.out.println(nombre + " está estudiando...");
    }
}

// HERENCIA: Profesor ES UNA Personapublic class Profesor extends Persona {
    private String especialidad;
    
    @Override
    public void presentarse() {
        System.out.println("Soy el profesor " + nombre + 
                         ", especialista en " + especialidad);
    }
    
    public void enseñar() {
        System.out.println(nombre + " está enseñando " + especialidad);
    }
}

Polymorphism

One Name, Multiple Forms

Polymorphism allows objects of different classes to be treated as objects of a common class.

Rectangle

Class that calculates area and perimeter

Circle

Class that calculates area and perimeter

Triangle

Class that calculates area and perimeter


// INTERFAZ COMÚNpublic interface Figura {
    double calcularArea();
    double calcularPerimetro();
}

// CLASES QUE IMPLEMENTAN LA INTERFAZpublic class Rectangulo implements Figura {
    private double base, altura;
    
    @Override
    public double calcularArea() {
        return base * altura;
    }
    
    @Override
    public double calcularPerimetro() {
        return 2 * (base + altura);
    }
}

public class Circulo implements Figura {
    private double radio;
    
    @Override
    public double calcularArea() {
        return Math.PI * radio * radio;
    }
    
    @Override
    public double calcularPerimetro() {
        return 2 * Math.PI * radio;
    }
}

// USO POLIMÓRFICOFigura[] figuras = new Figura[3];
figuras[0] = new Rectangulo();
figuras[1] = new Circulo();
figuras[2] = new Triangulo();

// Mismo método, diferentes comportamientosfor (Figura figura : figuras) {
    System.out.println("Área: " + figura.calcularArea());
    System.out.println("Perímetro: " + figura.calcularPerimetro());
}

Abstract Classes and Interfaces

Comparison: Abstract vs Interfaces


// EJEMPLO DE CLASE ABSTRACTApublic abstract class Animal {
    // Attributes    protected String nombre;
    protected int edad;
    
    // Constructor
    public Animal(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }
    
    // Método abstracto (DEBE ser implementado)    public abstract void hacerSonido();
    
    // Método concreto (YA está implementado)    public void dormir() {
        System.out.println(nombre + " está durmiendo...");
    }
    
    // Método final (NO puede ser sobrescrito)    public final void respirar() {
        System.out.println(nombre + " está respirando");
    }
}

// EJEMPLO DE INTERFACEpublic interface Volador {
    // Constante (implícitamente public static final)    int ALTURA_MAXIMA = 10000;
    
    // Método abstracto (implícitamente public abstract)    void volar();
    
    // Método default (Java 8+)    default void aterrizar() {
        System.out.println("Aterrizando...");
    }
    
    // Método static (Java 8+)    static void mostrarInfo() {
        System.out.println("Interface para objetos que vuelan");
    }
    
    // Método private (Java 9+)    private void logVuelo() {
        System.out.println("Registrando vuelo...");
    }
}

// CLASE QUE USA AMBOSpublic class Pajaro extends Animal implements Volador {
    
    public Pajaro(String nombre, int edad) {
        super(nombre, edad);
    }
    
    @Override
    public void hacerSonido() {
        System.out.println("¡Pío pío!");
    }
    
    @Override
    public void volar() {
        System.out.println(nombre + " está volando a gran altura");
    }
}
Feature Abstract Class Interface
Attributes ✓ (cualquier modificador) Solo constantes (public static final)
Constructors
Abstract methods ✓ (0 or more) ✓ (todos hasta Java 8)
Concrete methods ✓ (default/static desde Java 8)
Multiple inheritance ✗ (solo una clase) ✓ (múltiples interfaces)
Modifiers Any Solo public (implícitamente)

Overloading vs Overriding

Game: Spot the Difference

Drag the methods to the correct category:

sumar(int a, int b)
Same name, different signature
@Override toString()
Same name and signature in child class
calcular(double x, double y)
Different parameters
@Override equals(Object obj)
Specific implementation
imprimir(String texto, int veces)
Multiple versions
@Override hacerSonido()
Polymorphic behavior
Overloading (Overloading)

Same method name, different signature (parameters)

Overriding (Overriding)

Same name and signature in child class (inheritance)

Score: 0/6

// SOBRECARGA (OVERLOADING) - En la MISMA clasepublic class Calculadora {
    
    // Versión 1: dos enteros    public int sumar(int a, int b) {
        return a + b;
    }
    
    // Versión 2: tres enteros    public int sumar(int a, int b, int c) {
        return a + b + c;
    }
    
    // Versión 3: dos doubles    public double sumar(double a, double b) {
        return a + b;
    }
    
    // Versión 4: array de enteros    public int sumar(int[] numeros) {
        int total = 0;
        for (int num : numeros) {
            total += num;
        }
        return total;
    }
}

// SOBRESCRITURA (OVERRIDING) - En clase HIJApublic class Animal {
    public void hacerSonido() {
        System.out.println("El animal hace un sonido");
    }
}

public class Perro extends Animal {
    @Override  // Anotación recomendada    public void hacerSonido() {
        System.out.println("¡Guau guau!");
    }
}

public class Gato extends Animal {
    @Override
    public void hacerSonido() {
        System.out.println("¡Miau miau!");
    }
}

// USO POLIMÓRFICOAnimal miAnimal = new Perro();
miAnimal.hacerSonido();  // Output: ¡Guau guau!

Practical Exercises

Library System

Create a system for a library with the following classes:

  1. Book: Base class with title, author, ISBN and status attributes (available/borrowed)
  2. LibroDigital: Inherits from Libro, adds format (PDF, EPUB) and size in MB
  3. Username: Class with name, ID and list of borrowed books
  4. Library: Main class that manages books and users

Requirements: Encapsulation, inheritance, polymorphism and method overriding.

Geometric Shapes System

Implement a geometric shapes system using interfaces and abstract classes:

  1. Interface Figura with methods calcularArea() and calcularPerimetro()
  2. Abstract class FiguraGeometrica that implements some common methods
  3. Concrete classes: Circulo, Rectangulo, Triangulo
  4. Class CalculadoraAreas that uses polymorphism

Employee System

Create a payroll system for different employee types:

  1. Abstract class Empleado with basic attributes and abstract method calcularSalario()
  2. Concrete classes: EmpleadoTiempoCompleto, EmpleadoPorHoras, EmpleadoComision
  3. Interface Bonificable with method aplicarBonificacion()
  4. Method overloading for different hiring types

Card Game with OOP

Implement a card game system using all OOP concepts:

  1. Class Carta with rank and suit
  2. Abstract class Jugador with game strategies
  3. Interfaces: Jugable, Barajable
  4. Class Mazo that uses composition (list of Cartas)
  5. Overloading for different game rules
  6. Polymorphism for different player types

Concept Quiz

Question 1: What is a class in OOP?

A specific object with concrete values
A blueprint or mold for creating objects
A method that runs when an object is created
A variable that stores data

Summary and Best Practices

Key OOP Concepts

  • Class: Mold/blueprint for creating objects
  • Object: A concrete instance of a class
  • Encapsulation: Hide internal details (private + getters/setters)
  • Inheritance: Reuse and extend functionality (extends)
  • Polymorphism: Multiple forms through a common interface
  • Abstraction: Show only what's essential, hide complexity

OOP Best Practices

  • Use descriptive names for classes and methods
  • Follow the single responsibility principle
  • Prefer composition over inheritance when possible
  • Use appropriate access modifiers
  • Document your classes and methods with JavaDoc
  • Use interfaces to define clear contracts
  • Avoid overly large classes ("god classes")

Common Errors

  • Forgetting encapsulation (public attributes)
  • Excessive inheritance (too many levels)
  • Not using @Override when overriding
  • Confusing overloading with overriding
  • Creating "all-in-one" classes
  • Not validating data in setters
  • Using inheritance to share code instead of for "is-a" relationships

Quick Reference Sheet - POO

Define Class:
public class MiClase {
    private atributo;
    
    public MiClase() {}
    
    public void metodo() {}
}
Inheritance:
public class Hijo extends Padre {
    @Override
    public void metodo() {
        super.metodo(); // Llama al padre    }
}
Interface:
public interface MiInterface {
    void metodo();
}

public class Clase implements MiInterface {
    @Override
    public void metodo() {}
}
Abstract:
public abstract class Abstracta {
    public abstract void metodo();
    
    public void concreto() {}
}

Final OOP Test

Question 1 expression in 5

Which of these is NOT a pillar of OOP?

Encapsulation
Inheritance
Polymorphism
Iteration