Laboratorio 04 — Herencia en Java - jorgealbertopineda78-del/java GitHub Wiki

Laboratorio 04 — Herencia en Java

Unidad: 4 — Herencia
Duración estimada: 90 minutos
Nivel: Intermedio


Objetivo

Aplicar el concepto de herencia en Java creando jerarquías de clases usando extends e implements, sobreescribiendo métodos con @Override y reutilizando comportamiento de la clase padre con super.


Contexto del problema

Estás desarrollando el motor de personajes para un videojuego de rol (RPG). El juego tiene distintos tipos de personajes: Guerrero, Mago y Arquero. Todos comparten características básicas como nombre, nivel y puntos de vida, pero cada uno tiene habilidades y atributos únicos que los diferencian en combate.

Tu tarea es modelar esta jerarquía usando herencia correctamente.


Diagrama UML

                  «interface»
               ┌──────────────┐
               │  Combatiente │
               ├──────────────┤
               │ + atacar()   │
               │ + defender() │
               └──────┬───────┘
                      │ implements
                      ▼
        ┌─────────────────────────────┐
        │           Personaje         │
        ├─────────────────────────────┤
        │ - nombre      : String      │
        │ - nivel       : int         │
        │ - puntosVida  : int         │
        │ - estaVivo    : boolean     │
        ├─────────────────────────────┤
        │ + Personaje(nombre, nivel,  │
        │             puntosVida)     │
        │ + getNombre()  : String     │
        │ + getNivel()   : int        │
        │ + getPuntosVida(): int      │
        │ + isEstaVivo() : boolean    │
        │ + recibirDanio(int): void   │
        │ + atacar()     : void       │
        │ + defender()   : void       │
        │ + toString()   : String     │
        └──────────────┬──────────────┘
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
  ┌──────────────┐  ┌──────────┐  ┌──────────────┐
  │   Guerrero   │  │  Mago    │  │   Arquero    │
  ├──────────────┤  ├──────────┤  ├──────────────┤
  │ - fuerza: int│  │ (tus     │  │ (tus         │
  │ - armadura:  │  │  atribs) │  │  atribs)     │
  │   String     │  └──────────┘  └──────────────┘
  ├──────────────┤
  │ + Guerrero(.)│
  │ + atacar()   │
  │ + defender() │
  │ + toString() │
  └──────────────┘

Nota: Combatiente es una interfaz — define el contrato que todos los personajes deben cumplir. Personaje la implementa con un comportamiento base, y las subclases lo sobreescriben con comportamiento propio.


Instrucciones

Parte 1 — Interfaz Combatiente (se construye en clase con el profesor)

Crea Combatiente.java:

  1. Declara la interfaz con dos métodos abstractos:
    • atacar() — sin cuerpo, sin parámetros, retorna void
    • defender() — sin cuerpo, sin parámetros, retorna void
public interface Combatiente {
    void atacar();
    void defender();
}

💡 En una interfaz los métodos son implícitamente public abstract — no necesitas escribirlo.


Parte 2 — Clase Personaje (se construye en clase con el profesor)

Crea Personaje.java que implements Combatiente:

  1. Atributos todos private:

    • nombre : String
    • nivel : int
    • puntosVida : int
    • estaVivo : boolean (inicializa en true en el constructor)
  2. Constructor con nombre, nivel y puntosVida.

  3. Getters para todos los atributos.

  4. Método recibirDanio(int danio):

    • Resta danio a puntosVida
    • Si puntosVida llega a 0 o menos, asigna puntosVida = 0 y estaVivo = false
    • Imprime: [nombre] recibe [danio] puntos de daño. Vida restante: [puntosVida]
    • Si muere: imprime además [nombre] ha sido derrotado.
  5. Implementa atacar() y defender() con comportamiento genérico:

    • atacar() → imprime: [nombre] ataca con un golpe básico.
    • defender() → imprime: [nombre] se pone en guardia.
  6. Sobreescribe toString().


Parte 3 — Clase Guerrero (se construye en clase con el profesor)

Crea Guerrero.java que extienda de Personaje:

  1. Atributos propios private:

    • fuerza : int
    • armadura : String
  2. Constructor usando super().

  3. Getters: getFuerza(), getArmadura()

  4. Sobreescribe atacar():

    • Usa super.atacar() primero
    • Luego imprime: ¡[nombre] golpea con su espada causando [fuerza] de daño!
  5. Sobreescribe defender():

    • Imprime: [nombre] bloquea con su armadura de [armadura].
  6. Sobreescribe toString() usando super.toString().


Parte 4 — Clase Mago (trabajo independiente)

Crea Mago.java que extienda de Personaje:

  1. Define al menos 2 atributos propios private (ejemplos: mana, escuelaMagia, nivelMagia, varita)

  2. Constructor usando super().

  3. Getters para tus atributos.

  4. Sobreescribe atacar() — el mago usa hechizos, no golpes físicos. Usa super.atacar() y luego agrega el comportamiento del mago.

  5. Sobreescribe defender() — el mago usa escudos mágicos.

  6. Sobreescribe toString() usando super.toString().

💡 Pista: Puedes acceder al nombre del personaje con getNombre() desde la subclase.


Parte 5 — Clase Arquero (trabajo independiente)

Crea Arquero.java que extienda de Personaje:

  1. Define al menos 2 atributos propios private (ejemplos: tipArco, flechasDisponibles, precision, alcance)

  2. Constructor usando super().

  3. Getters para tus atributos.

  4. Sobreescribe atacar() — el arquero dispara flechas a distancia.

  5. Sobreescribe defender() — el arquero esquiva o se repliega.

  6. Sobreescribe toString() usando super.toString().


Parte 6 — Clase principal Main

  1. Crea un objeto de cada tipo: Guerrero, Mago y Arquero.
  2. Llama a atacar() y defender() en cada uno — observa cómo cada clase responde diferente al mismo mensaje.
  3. Prueba recibirDanio() en al menos dos personajes, incluyendo uno que llegue a 0 de vida.
  4. Imprime la información de cada personaje con toString().

Ejemplo de salida esperada:

=== Batalla RPG ===

-- Ronda 1: Ataques --
[Thorin] ataca con un golpe básico.
¡Thorin golpea con su espada causando 85 de daño!

[Gandalf] ataca con un golpe básico.
¡Gandalf lanza una bola de fuego causando 120 de maná!

[Legolas] dispara una flecha con precisión del 95%.

-- Ronda 2: Defensas --
Thorin bloquea con su armadura de Cota de Malla.
Gandalf invoca un escudo arcano.
Legolas se desplaza ágilmente esquivando el ataque.

-- Daño recibido --
Thorin recibe 60 puntos de daño. Vida restante: 140
Gandalf recibe 200 puntos de daño. Vida restante: 0
Gandalf ha sido derrotado.

-- Estado final --
Nombre: Thorin | Nivel: 5 | Vida: 140 | Vivo: Sí
Nombre: Gandalf | Nivel: 8 | Vida: 0 | Vivo: No
Nombre: Legolas | Nivel: 6 | Vida: 120 | Vivo: Sí

¿Qué está pasando con super?

// En Guerrero.atacar():
@Override
public void atacar() {
    super.atacar();   // ejecuta el atacar() de Personaje primero
    System.out.println("¡" + getNombre() + " golpea con su espada!");
    // Agrega comportamiento propio encima del heredado
}

super te permite reutilizar el comportamiento del padre en lugar de reescribirlo desde cero. Es la diferencia entre extender y reemplazar.


Criterios de evaluación

Criterio Puntos
Interfaz Combatiente declarada correctamente 10
Clase Personaje implementa Combatiente, atributos y métodos correctos 15
Método recibirDanio() con lógica de muerte funcionando 10
Clase Guerrero con super(), @Override y super.atacar() 15
Clase Mago con atributos propios, @Override y super.toString() 20
Clase Arquero con atributos propios, @Override y super.toString() 20
Main demuestra polimorfismo y prueba recibirDanio() hasta muerte 10
Total 100

Preguntas de reflexión

Responde en un archivo respuestas.docx:

  1. ¿Cuál es la diferencia entre extends e implements? ¿Cuándo usas cada uno?
  2. ¿Qué ventaja tiene llamar super.atacar() dentro de Guerrero.atacar() en lugar de reescribir todo?
  3. Si declaras una variable Personaje p = new Guerrero(...) y llamas p.atacar(), ¿qué método se ejecuta, el de Personaje o el de Guerrero? ¿Por qué?
  4. agrega la explicacion de conceptos y temas vistos en clase

Entregable

Sube al repositorio en la carpeta lab04_herencia:

lab04_herencia/
├── Combatiente.java
├── Personaje.java
├── Guerrero.java
├── Mago.java
├── Arquero.java
└── Main.java

Laboratorio preparado para el curso de Programación Orientada a Objetos — Ago-Dic 2025