> ## Documentation Index
> Fetch the complete documentation index at: https://apuntes.simulab.es/llms.txt
> Use this file to discover all available pages before exploring further.

# Programación orientada a objetos en Java: clases, herencia, interfaces y polimorfismo

> Programación orientada a objetos con Java: clases y objetos, atributos y métodos, constructores, encapsulación con private y getters, static, herencia con extends y super, sobrescritura, clases abstractas, interfaces, polimorfismo, equals y hashCode, y principios de diseño, con ejemplos de código explicados.

La **programación orientada a objetos** (POO) organiza un programa en **objetos**: entidades que juntan unos datos (sus atributos) y las operaciones que se pueden hacer con ellos (sus métodos). Una cuenta bancaria tiene un saldo y se puede ingresar o retirar dinero; un círculo tiene un radio y sabe calcular su área. Java es un lenguaje orientado a objetos desde su base, y es el que se usa en muchas asignaturas de programación de la universidad.

## Lo que vas a aprender

* Qué son las clases, los objetos, los atributos y los métodos.
* Cómo se escriben los constructores.
* La encapsulación y los modificadores de acceso.
* Los miembros `static`.
* La herencia, la sobrescritura y `super`.
* Las clases abstractas, las interfaces y el polimorfismo.

## Fundamentos

### Clases y objetos

Una **clase** es un molde; un **objeto** es un ejemplar concreto creado con `new`.

```java theme={null}
public class CuentaBancaria {
    // Atributos (estado)
    private String titular;
    private double saldo;

    // Constructor
    public CuentaBancaria(String titular, double saldoInicial) {
        this.titular = titular;
        this.saldo = saldoInicial;
    }

    // Métodos (comportamiento)
    public void ingresar(double cantidad) {
        if (cantidad <= 0) throw new IllegalArgumentException("Cantidad no válida");
        saldo += cantidad;
    }

    public boolean retirar(double cantidad) {
        if (cantidad > saldo) return false;
        saldo -= cantidad;
        return true;
    }

    public double getSaldo() { return saldo; }
}
```

```java theme={null}
CuentaBancaria c = new CuentaBancaria("Ana", 100);
c.ingresar(50);
System.out.println(c.getSaldo());   // 150.0
```

`this` se refiere al objeto actual; distingue el atributo `this.titular` del parámetro `titular`.

### Encapsulación

Los atributos se declaran `private` y se accede a ellos con métodos públicos (*getters* y *setters*). Así la clase controla su estado: nadie puede poner un saldo negativo desde fuera.

| Modificador | Visible desde |
| - | - |
| `private` | La propia clase |
| (sin modificador) | El mismo paquete |
| `protected` | El paquete y las subclases |
| `public` | Cualquier sitio |

### static

Un atributo o método `static` pertenece a la **clase**, no a cada objeto. Se usa para contadores compartidos, constantes (`static final double PI`) y funciones de utilidad (`Math.sqrt`). Un método `static` no puede usar `this`.

### Herencia

Una clase puede **heredar** de otra con `extends`: recibe sus atributos y métodos, y puede añadir o cambiar comportamiento.

```java theme={null}
public class CuentaAhorro extends CuentaBancaria {
    private double interes;

    public CuentaAhorro(String titular, double saldo, double interes) {
        super(titular, saldo);           // llama al constructor del padre
        this.interes = interes;
    }

    public void aplicarInteres() {
        ingresar(getSaldo() * interes);
    }
}
```

Java solo permite **una** superclase (herencia simple). Todas las clases heredan, en última instancia, de `Object`.

### Sobrescritura

Una subclase puede redefinir un método del padre con la misma firma. Se marca con `@Override` para que el compilador compruebe que de verdad sobrescribe algo.

```java theme={null}
@Override
public String toString() {
    return titular + ": " + saldo + " €";
}
```

### Clases abstractas e interfaces

```java theme={null}
public abstract class Figura {
    public abstract double area();         // sin cuerpo: cada subclase la define
    public String describir() {
        return "Figura de área " + area();
    }
}

public class Circulo extends Figura {
    private final double r;
    public Circulo(double r) { this.r = r; }
    @Override public double area() { return Math.PI * r * r; }
}

public interface Dibujable {
    void dibujar();
}

public class Cuadrado extends Figura implements Dibujable {
    private final double lado;
    public Cuadrado(double lado) { this.lado = lado; }
    @Override public double area() { return lado * lado; }
    @Override public void dibujar() { System.out.println("[ ]"); }
}
```

| | Clase abstracta | Interfaz |
| - | - | - |
| Se puede instanciar | No | No |
| Atributos | Sí | Solo constantes |
| Métodos con código | Sí | Solo `default` y `static` |
| Una clase puede tener | Una | Varias (`implements A, B`) |
| Expresa | "Es un" (jerarquía) | "Puede hacer" (capacidad) |

### Polimorfismo

Una variable de un tipo general puede guardar objetos de cualquier subtipo, y al llamar a un método se ejecuta **la versión del objeto real**:

```java theme={null}
Figura[] figuras = { new Circulo(1), new Cuadrado(2) };
double total = 0;
for (Figura f : figuras) {
    total += f.area();      // llama a Circulo.area() o Cuadrado.area()
}
System.out.println(total);  // 7.14159...
```

El código que recorre las figuras no necesita saber de qué tipo es cada una: si mañana se añade un `Triangulo`, sigue funcionando sin cambios.

### equals y hashCode

`==` compara **referencias** (si son el mismo objeto). Para comparar contenido se sobrescribe `equals`, y siempre a la vez `hashCode`, para que el objeto funcione bien en un `HashMap` o `HashSet` (ver [tablas hash](https://apuntes.simulab.es/programacion/java/tablas-hash.md)).

### Principios de diseño

* **Encapsula** lo que cambia y oculta los detalles.
* **Prefiere la composición a la herencia:** que una clase *tenga* otra en vez de heredar de ella, salvo que sea de verdad un "es un".
* **Programa contra interfaces:** declara variables como `List<String>` en lugar de `ArrayList<String>`.
* **Una clase, una responsabilidad.**

## Ejemplos resueltos

> [accordion] Ejemplo 1 · Contador de objetos con static
>
> ```java theme={null}
> public class Alumno {
>     private static int total = 0;
>     private final int id;
>     public Alumno() { total++; id = total; }
>     public static int getTotal() { return total; }
> }
> ```
>
> Tras `new Alumno(); new Alumno();`, `Alumno.getTotal()` devuelve 2, y cada alumno tiene su propio `id`.

> [accordion] Ejemplo 2 · Polimorfismo con una lista
>
> ```java theme={null}
> List<Figura> lista = new ArrayList<>();
> lista.add(new Circulo(2));
> lista.add(new Cuadrado(3));
> for (Figura f : lista) System.out.println(f.describir());
> ```
>
> Imprime "Figura de área 12.566…" y "Figura de área 9.0". El método `describir` es del padre, pero llama al `area()` de cada hijo.

> [accordion] Ejemplo 3 · equals mal y bien
>
> ```java theme={null}
> String a = new String("hola");
> String b = new String("hola");
> System.out.println(a == b);        // false: objetos distintos
> System.out.println(a.equals(b));   // true: mismo contenido
> ```

> [accordion] Ejemplo 4 · Composición en vez de herencia
>
> Un `Coche` no **es** un `Motor`, pero **tiene** uno: `private Motor motor;` y métodos que delegan en él (`arrancar()` llama a `motor.encender()`). Así se puede cambiar de motor sin tocar la jerarquía.

## Errores frecuentes

* **Comparar objetos con `==`**, sobre todo cadenas. Usa `equals`.
* **Hacer públicos los atributos.** Se pierde el control del estado del objeto.
* **Sobrescribir `equals` sin `hashCode`.**
* **Olvidar llamar a `super(...)`** cuando el padre no tiene constructor sin parámetros.
* **Abusar de la herencia** para reutilizar código cuando no hay una relación "es un".
* **Confundir sobrecarga** (mismo nombre, distintos parámetros, en la misma clase) **con sobrescritura** (misma firma, en una subclase).

## Preguntas frecuentes

> [accordion] ¿Para qué sirve la POO si se puede programar con funciones?
>
> Para organizar programas grandes: agrupa datos y operaciones relacionados, oculta los detalles internos y permite extender el comportamiento (con herencia e interfaces) sin modificar el código que ya funciona. En programas pequeños la diferencia es menor.

> [accordion] ¿Qué son los patrones de diseño?
>
> Soluciones probadas a problemas habituales de diseño orientado a objetos, recogidas en 1994 por la "banda de los cuatro": Singleton, Factory, Observer, Strategy, Decorator… Por ejemplo, Strategy encapsula un algoritmo en una interfaz para poder cambiarlo en tiempo de ejecución.

## Temas relacionados

> [card] [ArrayList y lista enlazada](https://apuntes.simulab.es/programacion/java/listas.md)
>
> Las colecciones de Java por dentro.

> [card] [Tablas hash](https://apuntes.simulab.es/programacion/java/tablas-hash.md)
>
> Por qué equals y hashCode van juntos.

> [card] [POO en Python](https://apuntes.simulab.es/programacion/python/poo-python.md)
>
> Los mismos conceptos en Python.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.