¿Te han explicado POO con ejemplos de "animales" y "figuras geométricas" que no entiendes cómo aplicar? ¿Sientes que la Programación Orientada a Objetos es solo teoría sin sentido práctico?
Este tutorial es diferente. Vamos a aprender POO en Java creando cosas del mundo real que usas todos los días: cuentas bancarias, coches, sistemas de empleados. Código que funciona, ejemplos que entiendes.
Al final tendrás tu propia mini-aplicación bancaria funcionando. Sin teoría aburrida, solo práctica que te sirve.
🤔 ¿Qué vamos a aprender?
🎯 Al terminar este tutorial sabrás:
📦 ¿Qué es POO realmente?
Imagínate que tienes que describir un coche a alguien que nunca ha visto uno:
Eso es POO: Organizar el código como objetos del mundo real, con características (propiedades) y comportamientos (métodos).
🚗 Tu primera clase: Coche
Vamos a crear una clase Coche. Abre tu IDE (Eclipse, IntelliJ, VS Code) y crea un archivo Coche.java:
public class Coche {
// ✅ PROPIEDADES (lo que tiene un coche)
private String marca;
private String modelo;
private String color;
private int velocidad;
private boolean encendido;
// ✅ CONSTRUCTOR (cómo crear un coche)
public Coche(String marca, String modelo, String color) {
this.marca = marca;
this.modelo = modelo;
this.color = color;
this.velocidad = 0;
this.encendido = false;
}
// ✅ MÉTODOS (lo que puede hacer un coche)
public void encender() {
this.encendido = true;
System.out.println("🚗 El " + marca + " " + modelo + " está encendido");
}
public void acelerar(int incremento) {
if (!encendido) {
System.out.println("❌ Primero debes encender el coche");
return;
}
velocidad += incremento;
System.out.println("🏎️ Velocidad actual: " + velocidad + " km/h");
}
public void frenar(int decremento) {
velocidad -= decremento;
if (velocidad < 0) velocidad = 0;
System.out.println("🛑 Frenando... Velocidad: " + velocidad + " km/h");
}
// ✅ GETTERS (para ver las propiedades desde fuera)
public String getInfo() {
return marca + " " + modelo + " " + color + " - " + velocidad + " km/h";
}
}
💡 ¿Por qué "private"?
Encapsulación: Protegemos los datos internos del coche. No puedes cambiar directamente la velocidad desde fuera - tienes que usar acelerar() o frenar(), como en un coche real.
🏃♂️ Creando objetos (coches reales)
Ahora vamos a crear coches específicos. Crea Main.java:
public class Main {
public static void main(String[] args) {
// ✅ Crear coches específicos
Coche miCoche = new Coche("Toyota", "Corolla", "Rojo");
Coche cocheAmigo = new Coche("BMW", "X5", "Negro");
// ✅ Usar los coches
System.out.println("=== MI COCHE ===");
miCoche.encender();
miCoche.acelerar(50);
miCoche.acelerar(30);
miCoche.frenar(20);
System.out.println(miCoche.getInfo());
System.out.println("\n=== COCHE DEL AMIGO ===");
cocheAmigo.acelerar(60); // ❌ Sin encender primero
cocheAmigo.encender();
cocheAmigo.acelerar(60);
System.out.println(cocheAmigo.getInfo());
}
}
Ejecuta el código (botón Run o F5). Deberías ver:
=== MI COCHE ===
🚗 El Toyota Corolla está encendido
🏎️ Velocidad actual: 50 km/h
🏎️ Velocidad actual: 80 km/h
🛑 Frenando... Velocidad: 60 km/h
Toyota Corolla Rojo - 60 km/h
=== COCHE DEL AMIGO ===
❌ Primero debes encender el coche
🚗 El BMW X5 está encendido
🏎️ Velocidad actual: 60 km/h
BMW X5 Negro - 60 km/h
🏦 Ejemplo real: Sistema bancario
Vamos con algo más útil: una cuenta bancaria. Crea CuentaBancaria.java:
public class CuentaBancaria {
// ✅ Propiedades privadas (nadie puede tocar tu saldo directamente)
private String numeroCuenta;
private String titular;
private double saldo;
private boolean activa;
// ✅ Constructor
public CuentaBancaria(String numeroCuenta, String titular) {
this.numeroCuenta = numeroCuenta;
this.titular = titular;
this.saldo = 0.0;
this.activa = true;
System.out.println("✅ Cuenta creada para: " + titular);
}
// ✅ Depositar dinero
public void depositar(double cantidad) {
if (!activa) {
System.out.println("❌ Cuenta inactiva");
return;
}
if (cantidad <= 0) {
System.out.println("❌ La cantidad debe ser positiva");
return;
}
saldo += cantidad;
System.out.println("💰 Depósito exitoso: €" + cantidad + ". Nuevo saldo: €" + saldo);
}
// ✅ Retirar dinero
public boolean retirar(double cantidad) {
if (!activa) {
System.out.println("❌ Cuenta inactiva");
return false;
}
if (cantidad <= 0) {
System.out.println("❌ La cantidad debe ser positiva");
return false;
}
if (cantidad > saldo) {
System.out.println("❌ Fondos insuficientes. Saldo actual: €" + saldo);
return false;
}
saldo -= cantidad;
System.out.println("💳 Retiro exitoso: €" + cantidad + ". Nuevo saldo: €" + saldo);
return true;
}
// ✅ Transferir a otra cuenta
public void transferir(CuentaBancaria destino, double cantidad) {
System.out.println("🔄 Iniciando transferencia de €" + cantidad + " a " + destino.titular);
if (this.retirar(cantidad)) {
destino.depositar(cantidad);
System.out.println("✅ Transferencia completada");
} else {
System.out.println("❌ Transferencia fallida");
}
}
// ✅ Getters
public double getSaldo() { return saldo; }
public String getTitular() { return titular; }
public String getNumeroCuenta() { return numeroCuenta; }
public void mostrarInfo() {
System.out.println("=== CUENTA " + numeroCuenta + " ===");
System.out.println("👤 Titular: " + titular);
System.out.println("💰 Saldo: €" + saldo);
System.out.println("🔄 Estado: " + (activa ? "Activa" : "Inactiva"));
}
}
🎮 Probando el sistema bancario
Actualiza tu Main.java:
public class Main {
public static void main(String[] args) {
System.out.println("🏦 === SISTEMA BANCARIO === 🏦\n");
// ✅ Crear cuentas
CuentaBancaria cuentaAna = new CuentaBancaria("12345", "Ana García");
CuentaBancaria cuentaLuis = new CuentaBancaria("67890", "Luis Martínez");
System.out.println("\n--- Ana deposita dinero ---");
cuentaAna.depositar(1000);
cuentaAna.depositar(500);
System.out.println("\n--- Luis también deposita ---");
cuentaLuis.depositar(800);
System.out.println("\n--- Ana intenta retirar ---");
cuentaAna.retirar(200);
cuentaAna.retirar(2000); // ❌ No tiene suficiente
System.out.println("\n--- Transferencia entre cuentas ---");
cuentaAna.transferir(cuentaLuis, 300);
System.out.println("\n--- Estado final de las cuentas ---");
cuentaAna.mostrarInfo();
System.out.println();
cuentaLuis.mostrarInfo();
}
}
🧬 Herencia: Tipos de cuentas especializadas
Las cuentas de ahorro tienen intereses, las cuentas corrientes tienen sobregiro. Herencia nos permite crear tipos especializados sin repetir código.
Crea CuentaAhorro.java:
public class CuentaAhorro extends CuentaBancaria {
// ✅ Nueva propiedad específica para ahorro
private double tasaInteres;
// ✅ Constructor que llama al padre
public CuentaAhorro(String numeroCuenta, String titular, double tasaInteres) {
super(numeroCuenta, titular); // Llama al constructor padre
this.tasaInteres = tasaInteres;
System.out.println("💰 Cuenta de ahorro creada con " + (tasaInteres*100) + "% interés anual");
}
// ✅ Método nuevo: calcular intereses
public void aplicarInteres() {
double interes = getSaldo() * tasaInteres;
depositar(interes);
System.out.println("📈 Interés aplicado: €" + interes);
}
// ✅ Sobreescribir método: restricción de retiros
@Override
public boolean retirar(double cantidad) {
if (cantidad > 500) {
System.out.println("⚠️ Las cuentas de ahorro no permiten retiros mayores a €500 por transacción");
return false;
}
return super.retirar(cantidad); // Llama al método padre
}
public double getTasaInteres() { return tasaInteres; }
}
🏃♀️ Polimorfismo en acción
El polimorfismo permite que diferentes tipos de objetos respondan al mismo método de forma diferente. Actualiza Main.java:
public class Main {
public static void main(String[] args) {
System.out.println("🏦 === SISTEMA BANCARIO AVANZADO === 🏦\n");
// ✅ Polimorfismo: diferentes tipos, misma referencia
CuentaBancaria cuenta1 = new CuentaBancaria("001", "Pedro");
CuentaBancaria cuenta2 = new CuentaAhorro("002", "María", 0.03); // 3%
// ✅ Array de cuentas diferentes
CuentaBancaria[] cuentas = {cuenta1, cuenta2};
// ✅ Depositar en todas las cuentas
for (CuentaBancaria cuenta : cuentas) {
cuenta.depositar(1000);
}
System.out.println("\n--- Probando comportamiento diferente ---");
// ✅ Misma acción, comportamiento diferente (POLIMORFISMO)
cuenta1.retirar(600); // ✅ Cuenta normal: OK
cuenta2.retirar(600); // ❌ Cuenta ahorro: Límite
System.out.println("\n--- Aplicando intereses (solo ahorro) ---");
// ✅ Verificar tipo específico para método específico
if (cuenta2 instanceof CuentaAhorro) {
CuentaAhorro cuentaAhorro = (CuentaAhorro) cuenta2;
cuentaAhorro.aplicarInteres();
}
System.out.println("\n--- Estado final ---");
for (CuentaBancaria cuenta : cuentas) {
cuenta.mostrarInfo();
System.out.println();
}
}
}
🎯 Los 4 pilares de POO explicados
🛠️ Proyecto final: Banco completo
Vamos a crear un sistema que gestione múltiples cuentas. Crea Banco.java:
import java.util.ArrayList;
import java.util.Scanner;
public class Banco {
private String nombre;
private ArrayList<CuentaBancaria> cuentas;
private Scanner scanner;
public Banco(String nombre) {
this.nombre = nombre;
this.cuentas = new ArrayList<>();
this.scanner = new Scanner(System.in);
}
public void crearCuenta() {
System.out.println("\n=== CREAR NUEVA CUENTA ===");
System.out.print("Nombre del titular: ");
String titular = scanner.nextLine();
System.out.print("Número de cuenta: ");
String numeroCuenta = scanner.nextLine();
System.out.println("Tipo de cuenta:");
System.out.println("1. Cuenta Normal");
System.out.println("2. Cuenta de Ahorro");
System.out.print("Selecciona (1-2): ");
int tipo = scanner.nextInt();
scanner.nextLine(); // Limpiar buffer
CuentaBancaria nuevaCuenta;
if (tipo == 2) {
System.out.print("Tasa de interés (ej: 0.03 para 3%): ");
double tasa = scanner.nextDouble();
scanner.nextLine();
nuevaCuenta = new CuentaAhorro(numeroCuenta, titular, tasa);
} else {
nuevaCuenta = new CuentaBancaria(numeroCuenta, titular);
}
cuentas.add(nuevaCuenta);
System.out.println("✅ Cuenta creada exitosamente!");
}
public void mostrarCuentas() {
if (cuentas.isEmpty()) {
System.out.println("❌ No hay cuentas registradas");
return;
}
System.out.println("\n=== TODAS LAS CUENTAS ===");
for (int i = 0; i < cuentas.size(); i++) {
System.out.println((i+1) + ". ");
cuentas.get(i).mostrarInfo();
System.out.println();
}
}
public void mostrarMenu() {
System.out.println("\n🏦 === " + nombre + " ===");
System.out.println("1. Crear cuenta");
System.out.println("2. Ver todas las cuentas");
System.out.println("3. Salir");
System.out.print("Selecciona una opción: ");
}
public void ejecutar() {
while (true) {
mostrarMenu();
int opcion = scanner.nextInt();
scanner.nextLine();
switch (opcion) {
case 1:
crearCuenta();
break;
case 2:
mostrarCuentas();
break;
case 3:
System.out.println("👋 ¡Gracias por usar " + nombre + "!");
return;
default:
System.out.println("❌ Opción inválida");
}
}
}
public static void main(String[] args) {
Banco miBanco = new Banco("StudyCode Bank");
miBanco.ejecutar();
}
}
🎉 ¡Ya dominas POO en Java!
🏆 Lo que has aprendido:
- Clases y objetos: Crear plantillas y usar instancias específicas
- Encapsulación: Proteger datos con private y métodos públicos
- Herencia: Reutilizar código con extends
- Polimorfismo: Diferentes comportamientos según el tipo
- Aplicación real: Sistema bancario funcional
🚀 Próximos pasos
💡 Consejos para seguir practicando:
- Crea más clases: Estudiante, Producto, Empleado
- Practica herencia: Vehículo → Coche, Moto, Camión
- Experimenta: Modifica el código, rompe cosas, arregla cosas
- Proyectos reales: Sistema de biblioteca, inventario, etc.
🎯 ¿Listo para crear aplicaciones completas?
Ya dominas POO. Es hora de crear aplicaciones web profesionales con bases de datos y APIs.
👉 Java Spring Boot: Tu primera API REST desde ceroAprende a crear APIs profesionales con Spring Boot, conectar bases de datos y desplegar en producción