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:
Combatientees una interfaz — define el contrato que todos los personajes deben cumplir.Personajela 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:
- Declara la interfaz con dos métodos abstractos:
atacar()— sin cuerpo, sin parámetros, retornavoiddefender()— sin cuerpo, sin parámetros, retornavoid
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:
-
Atributos todos
private:nombre: Stringnivel: intpuntosVida: intestaVivo: boolean (inicializa entrueen el constructor)
-
Constructor con
nombre,nivelypuntosVida. -
Getters para todos los atributos.
-
Método
recibirDanio(int danio):- Resta
danioapuntosVida - Si
puntosVidallega a0o menos, asignapuntosVida = 0yestaVivo = false - Imprime:
[nombre] recibe [danio] puntos de daño. Vida restante: [puntosVida] - Si muere: imprime además
[nombre] ha sido derrotado.
- Resta
-
Implementa
atacar()ydefender()con comportamiento genérico:atacar()→ imprime:[nombre] ataca con un golpe básico.defender()→ imprime:[nombre] se pone en guardia.
-
Sobreescribe
toString().
Parte 3 — Clase Guerrero (se construye en clase con el profesor)
Crea Guerrero.java que extienda de Personaje:
-
Atributos propios
private:fuerza: intarmadura: String
-
Constructor usando
super(). -
Getters:
getFuerza(),getArmadura() -
Sobreescribe
atacar():- Usa
super.atacar()primero - Luego imprime:
¡[nombre] golpea con su espada causando [fuerza] de daño!
- Usa
-
Sobreescribe
defender():- Imprime:
[nombre] bloquea con su armadura de [armadura].
- Imprime:
-
Sobreescribe
toString()usandosuper.toString().
Parte 4 — Clase Mago (trabajo independiente)
Crea Mago.java que extienda de Personaje:
-
Define al menos 2 atributos propios
private(ejemplos:mana,escuelaMagia,nivelMagia,varita) -
Constructor usando
super(). -
Getters para tus atributos.
-
Sobreescribe
atacar()— el mago usa hechizos, no golpes físicos. Usasuper.atacar()y luego agrega el comportamiento del mago. -
Sobreescribe
defender()— el mago usa escudos mágicos. -
Sobreescribe
toString()usandosuper.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:
-
Define al menos 2 atributos propios
private(ejemplos:tipArco,flechasDisponibles,precision,alcance) -
Constructor usando
super(). -
Getters para tus atributos.
-
Sobreescribe
atacar()— el arquero dispara flechas a distancia. -
Sobreescribe
defender()— el arquero esquiva o se repliega. -
Sobreescribe
toString()usandosuper.toString().
Parte 6 — Clase principal Main
- Crea un objeto de cada tipo:
Guerrero,MagoyArquero. - Llama a
atacar()ydefender()en cada uno — observa cómo cada clase responde diferente al mismo mensaje. - Prueba
recibirDanio()en al menos dos personajes, incluyendo uno que llegue a0de vida. - 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:
- ¿Cuál es la diferencia entre
extendseimplements? ¿Cuándo usas cada uno? - ¿Qué ventaja tiene llamar
super.atacar()dentro deGuerrero.atacar()en lugar de reescribir todo? - Si declaras una variable
Personaje p = new Guerrero(...)y llamasp.atacar(), ¿qué método se ejecuta, el dePersonajeo el deGuerrero? ¿Por qué? - 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