Programación Orientada a Objetos
¿Qué es la POO?
La Programación Orientada a Objetos es un paradigma que organiza el código en objetos que tienen:
- Atributos (datos): Características del objeto
- Métodos (comportamiento): Acciones que puede realizar
Clases y Objetos
Definir una clase
public class Persona { // Atributos (campos) private String nombre; private int edad;
// Constructor public Persona(String nombre, int edad) { this.nombre = nombre; this.edad = edad; }
// Métodos public void saludar() { System.out.println("Hola, soy " + nombre); }
public String getNombre() { return nombre; }
public void setNombre(String nombre) { this.nombre = nombre; }}Crear objetos (instancias)
Persona persona1 = new Persona("Juan", 25);Persona persona2 = new Persona("María", 30);
persona1.saludar(); // "Hola, soy Juan"persona2.saludar(); // "Hola, soy María"Los 4 pilares de la POO
1. Encapsulación
Ocultar los detalles internos y exponer solo lo necesario:
public class CuentaBancaria { private double saldo; // ❌ No accesible directamente desde fuera
public CuentaBancaria(double saldoInicial) { this.saldo = saldoInicial; }
// ✅ Acceso controlado mediante métodos 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; }
public double getSaldo() { return saldo; }}Modificadores de acceso:
private: Solo accesible desde la misma clasedefault(sin modificador): Accesible en el mismo packageprotected: Accesible en el mismo package y subclasespublic: Accesible desde cualquier lugar
2. Herencia
Una clase puede heredar atributos y métodos de otra:
public class Animal { protected String nombre;
public Animal(String nombre) { this.nombre = nombre; }
public void comer() { System.out.println(nombre + " está comiendo"); }}
public class Perro extends Animal { private String raza;
public Perro(String nombre, String raza) { super(nombre); // Llama al constructor de Animal this.raza = raza; }
public void ladrar() { System.out.println(nombre + " está ladrando"); }
@Override public void comer() { System.out.println(nombre + " come croquetas"); }}Uso:
Perro perro = new Perro("Max", "Labrador");perro.comer(); // "Max come croquetas"perro.ladrar(); // "Max está ladrando"3. Polimorfismo
Un objeto puede tomar muchas formas:
Animal animal1 = new Perro("Max", "Labrador");Animal animal2 = new Gato("Luna", "Persa");
animal1.comer(); // Llama al método de Perroanimal2.comer(); // Llama al método de GatoCon interfaces:
public interface Volador { void volar();}
public class Avion implements Volador { @Override public void volar() { System.out.println("Avión volando"); }}
public class Pajaro implements Volador { @Override public void volar() { System.out.println("Pájaro volando"); }}
// Uso polimórficoList<Volador> voladores = List.of(new Avion(), new Pajaro());for (Volador v : voladores) { v.volar(); // Llama al método correcto según el tipo real}4. Abstracción
Mostrar solo lo esencial, ocultar la complejidad:
public abstract class FiguraGeometrica { protected String nombre;
public FiguraGeometrica(String nombre) { this.nombre = nombre; }
// Método abstracto (sin implementación) public abstract double calcularArea();
// Método concreto public void mostrarInfo() { System.out.println("Figura: " + nombre); System.out.println("Área: " + calcularArea()); }}
public class Circulo extends FiguraGeometrica { private double radio;
public Circulo(double radio) { super("Círculo"); this.radio = radio; }
@Override public double calcularArea() { return Math.PI * radio * radio; }}Constructores
Constructor por defecto
public class Coche { private String marca;
// Si no defines constructor, Java crea uno vacío automáticamente}
Coche coche = new Coche(); // ✅ FuncionaConstructores personalizados
public class Coche { private String marca; private String modelo; private int año;
// Constructor con todos los parámetros public Coche(String marca, String modelo, int año) { this.marca = marca; this.modelo = modelo; this.año = año; }
// Constructor con algunos parámetros public Coche(String marca, String modelo) { this(marca, modelo, 2024); // Llama al otro constructor }}Constructor copia
public class Punto { private int x, y;
public Punto(int x, int y) { this.x = x; this.y = y; }
// Constructor copia public Punto(Punto otro) { this.x = otro.x; this.y = otro.y; }}
Punto p1 = new Punto(10, 20);Punto p2 = new Punto(p1); // Copia de p1Métodos
Métodos de instancia
public class Calculadora { private int resultado = 0;
public void sumar(int valor) { resultado += valor; }
public int getResultado() { return resultado; }}
Calculadora calc = new Calculadora();calc.sumar(5);calc.sumar(3);System.out.println(calc.getResultado()); // 8Métodos estáticos
Pertenecen a la clase, no a instancias:
public class Utilidades { public static int sumar(int a, int b) { return a + b; }
public static double areaCirculo(double radio) { return Math.PI * radio * radio; }}
// Uso sin crear instanciasint suma = Utilidades.sumar(5, 3);double area = Utilidades.areaCirculo(10);Sobrecarga de métodos
Varios métodos con el mismo nombre pero diferentes parámetros:
public class Impresora { public void imprimir(int numero) { System.out.println("Número: " + numero); }
public void imprimir(String texto) { System.out.println("Texto: " + texto); }
public void imprimir(int numero, String texto) { System.out.println("Número: " + numero + ", Texto: " + texto); }}Interfaces
Una interfaz define un contrato que las clases deben cumplir:
public interface Reproducible { void reproducir(); void pausar(); void detener();
// Método default (Java 8+) default void info() { System.out.println("Reproductor de medios"); }}
public class ReproductorMP3 implements Reproducible { @Override public void reproducir() { System.out.println("Reproduciendo MP3..."); }
@Override public void pausar() { System.out.println("MP3 pausado"); }
@Override public void detener() { System.out.println("MP3 detenido"); }}Una clase puede implementar múltiples interfaces:
public class SmartTV implements Reproducible, Conectable { // Implementa métodos de ambas interfaces}Clases abstractas vs Interfaces
Cuándo usar clases abstractas:
- Cuando tienes código común que compartir
- Cuando necesitas campos no estáticos
- Relación "es un" clara
public abstract class Vehiculo { protected int velocidad = 0;
public abstract void acelerar();
public void mostrarVelocidad() { System.out.println("Velocidad: " + velocidad); }}Cuándo usar interfaces:
- Para definir capacidades que pueden tener clases no relacionadas
- Para soporte de herencia múltiple
- Relación "puede hacer"
public interface Volador { void volar();}
// Tanto aviones como pájaros pueden volar,// pero no están relacionados jerárquicamenteRecords (Java 14+)
Para clases de datos inmutables:
public record Punto(int x, int y) { }
// Equivalente a una clase con:// - Campos finales// - Constructor// - Getters (x(), y())// - equals, hashCode, toStringCon validación:
public record Email(String direccion) { public Email { if (!direccion.contains("@")) { throw new IllegalArgumentException("Email inválido"); } }}Buenas prácticas
- Principio de responsabilidad única: Una clase debe hacer una cosa bien.
- Favorece la composición sobre la herencia: En lugar de heredar, usa objetos.
- Programa contra interfaces, no implementaciones.
- Encapsula lo que varía: Lo que puede cambiar debe estar protegido.
- KISS: Keep It Simple, Stupid. No compliques innecesariamente.
Próximo paso
Aprende a manejar errores de forma efectiva: Excepciones →