Saltar a contenido

Semana 9 Polimorfismo en Java

El polimorfismo es una característica de la programación orientada a objetos que permite que un mismo nombre, como el de un método, tenga diferentes comportamientos según el contexto. La palabra "polimorfismo" significa "muchas formas", lo que refleja su capacidad para adaptarse a distintas situaciones.

Analogía Simple

Piensa en un interruptor de luz. Al presionarlo, enciende una lámpara, pero en otro contexto podría activar un ventilador. Aunque el acción es la misma ("presionar"), el resultado depende del dispositivo conectado. El polimorfismo funciona de manera similar: un mismo nombre produce resultados diferentes según cómo se use.

Propósito

  • Flexibilidad: Permite usar un nombre común para varias tareas, haciendo el código más claro.
  • Reutilización: Reduce la necesidad de escribir código repetitivo.
  • Mantenimiento: Facilita actualizar o modificar el código sin afectar otras partes.

En Java, el polimorfismo se presenta en dos formas: 1. En tiempo de compilación: Sobrecarga de métodos. 2. En tiempo de ejecución: Sobreescritura de métodos.

A continuación, se explica cada tipo con ejemplos prácticos.


1. Polimorfismo en Tiempo de Compilación: Sobrecarga de Métodos

La sobrecarga de métodos consiste en definir varios métodos con el mismo nombre dentro de una misma clase, pero con diferentes parámetros (en cantidad o tipo). Java selecciona el método adecuado según los argumentos proporcionados, y esta decisión se toma al compilar el programa.

Ejemplo: Clase para Sumar Números

Se creará una clase Calculadora que suma números de diferentes formas: dos enteros, tres enteros o dos decimales.

Código

public class Calculadora {
    // Método 1: Suma dos números enteros
    public int sumar(int a, int b) {
        return a + b;
    }

    // Método 2: Suma tres números enteros
    public int sumar(int a, int b, int c) {
        return a + b + c;
    }

    // Método 3: Suma dos números decimales
    public double sumar(double a, double b) {
        return a + b;
    }

    // Método principal para probar
    public static void main(String[] args) {
        Calculadora calc = new Calculadora();

        // Suma de dos enteros
        System.out.println("Resultado de 5 + 3: " + calc.sumar(5, 3));

        // Suma de tres enteros
        System.out.println("Resultado de 5 + 3 + 2: " + calc.sumar(5, 3, 2));

        // Suma de dos decimales
        System.out.println("Resultado de 5.5 + 3.2: " + calc.sumar(5.5, 3.2));
    }
}

Salida

Resultado de 5 + 3: 8
Resultado de 5 + 3 + 2: 10
Resultado de 5.5 + 3.2: 8.7

Explicación Paso a Paso

  1. Definición de la Clase:
  2. La clase Calculadora tiene tres métodos llamados sumar:

    • Uno para dos enteros (int).
    • Otro para tres enteros (int).
    • Otro para dos decimales (double).
  3. Selección del Método:

  4. Al llamar sumar(5, 3), Java identifica que se usan dos enteros y ejecuta sumar(int, int).
  5. Con sumar(5, 3, 2), detecta tres enteros y usa sumar(int, int, int).
  6. Para sumar(5.5, 3.2), selecciona sumar(double, double) por los decimales.

  7. Relación con el Polimorfismo:

  8. El nombre sumar es el mismo, pero cada versión realiza una tarea distinta según los parámetros. Esto simplifica el uso del código, ya que solo se necesita un nombre.

Representación Visual

Imagina los métodos como versiones de una misma función:

sumar(int, int)        → Para 2 enteros
sumar(int, int, int)   → Para 3 enteros
sumar(double, double)  → Para 2 decimales


2. Polimorfismo en Tiempo de Ejecución: Sobreescritura de Métodos

La sobreescritura de métodos ocurre cuando una clase hija redefine un método heredado de su clase padre, cambiando su comportamiento. Java determina qué método ejecutar cuando el programa está corriendo, según el tipo real del objeto.

Ejemplo: Animales con Sonidos

Se creará una clase padre Animal y dos clases hijas, Perro y Gato. Cada una tendrá un método hablar, pero con un comportamiento específico.

Código

// Clase padre
public class Animal {
    public void hablar() {
        System.out.println("Soy un animal y emito un sonido.");
    }
}

// Clase hija: Perro
class Perro extends Animal {
    @Override
    public void hablar() {
        System.out.println("Guau, guau");
    }
}

// Clase hija: Gato
class Gato extends Animal {
    @Override
    public void hablar() {
        System.out.println("Miau, miau");
    }
}

// Clase principal para probar
class Main {
    public static void main(String[] args) {
        // Creación de objetos
        Animal animalGenerico = new Animal();
        Animal perro = new Perro();
        Animal gato = new Gato();

        // Ejecución del método hablar
        System.out.println("Animal genérico:");
        animalGenerico.hablar();

        System.out.println("Perro:");
        perro.hablar();

        System.out.println("Gato:");
        gato.hablar();
    }
}

Salida

Animal genérico:
Soy un animal y emito un sonido.
Perro:
Guau, guau
Gato:
Miau, miau

Explicación Paso a Paso

  1. Clase Padre Animal:
  2. Define el método hablar con un mensaje genérico.

  3. Clases Hijas Perro y Gato:

  4. Heredan de Animal con la palabra extends.
  5. Cada una redefine hablar:
    • Perro imprime "Guau, guau".
    • Gato imprime "Miau, miau".
  6. La anotación @Override indica que se está reemplazando el método del padre.

  7. Funcionamiento del Polimorfismo:

  8. En main, se crean tres objetos:
    • animalGenerico es un Animal.
    • perro es un Perro, pero se almacena como Animal.
    • gato es un Gato, pero se almacena como Animal.
  9. Al llamar hablar, Java verifica el tipo real del objeto (Animal, Perro o Gato) y ejecuta el método correspondiente.

  10. Relación con el Polimorfismo:

  11. El método hablar tiene un solo nombre, pero su resultado varía según el objeto. Esto permite trabajar con objetos genéricos (Animal) y obtener comportamientos específicos.

Representación Visual

Estructura de clases:

       Animal
      /      \
    Perro    Gato
- Animal: hablar genérico. - Perro: hablar → "Guau, guau". - Gato: hablar → "Miau, miau".


Actividad Guiada: Aplicando Polimorfismo en Java

Esta actividad tiene como objetivo ayudarte a comprender y practicar el polimorfismo en Java mediante un ejercicio estructurado. Crearás un programa que implementa sobrecarga de métodos (polimorfismo en tiempo de compilación) y sobreescritura de métodos (polimorfismo en tiempo de ejecución). Está diseñada para principiantes, con pasos claros, plantillas de código y explicaciones detalladas. Al finalizar, tendrás un programa funcional que aplica ambos tipos de polimorfismo.


Parte 1: Configuración Inicial

Instrucciones

Crea un proyecto Java con estas clases: - Producto: Clase padre con un método para describir un producto genérico. - Libro y Electronico: Clases hijas que heredan de Producto. - Tienda: Clase para manejar descuentos. - Main: Clase para ejecutar pruebas.

Código Inicial

Archivo Producto.java:

public class Producto {
    public String describir() {
        return "Este es un producto genérico.";
    }
}

Tarea

  1. Crea las clases Libro y Electronico, haciendo que hereden de Producto. No modifiques el método describir por ahora.
  2. Crea la clase Tienda vacía.
  3. Crea la clase Main con un método main vacío.

Plantilla para Libro

public class Libro extends Producto {
    // No agregues código aquí todavía
}

Plantilla para Main

public class Main {
    public static void main(String[] args) {
        // Las pruebas se agregarán después
    }
}

Verificación

  • Confirma que los archivos compilen sin errores. No ejecutarán nada aún, pero las clases deben estar definidas correctamente.

Explicación

  • Producto actúa como clase base para Libro y Electronico.
  • La herencia (extends) permitirá a las clases hijas modificar el método describir más adelante.
  • Tienda y Main se usarán en las siguientes partes.

Parte 2: Sobrecarga de Métodos en la Clase Tienda

Instrucciones

En la clase Tienda, implementa métodos sobrecargados llamados calcularDescuento para tres casos: - Descuento fijo del 10% sobre un precio. - Descuento personalizado basado en un porcentaje. - Descuento según el nivel del precio (20% si es alto, 5% si no).

Código Inicial

Archivo Tienda.java:

public class Tienda {
    // Aquí se definirán los métodos calcularDescuento
}

Tarea

Completa Tienda con estos métodos: 1. calcularDescuento(double precio): Devuelve el precio con un 10% de descuento. 2. calcularDescuento(double precio, double porcentaje): Aplica un porcentaje de descuento específico. 3. calcularDescuento(double precio, boolean esPrecioAlto): Aplica un 20% de descuento si esPrecioAlto es true, o un 5% si es false.

Plantilla

public class Tienda {
    // Método 1: Descuento fijo del 10%
    public double calcularDescuento(double precio) {
        // TODO: Implementar descuento del 10%
        return 0;
    }

    // Método 2: Descuento personalizado
    public double calcularDescuento(double precio, double porcentaje) {
        // TODO: Implementar descuento según porcentaje
        return 0;
    }

    // Método 3: Descuento según precio alto
    public double calcularDescuento(double precio, boolean esPrecioAlto) {
        // TODO: Implementar 20% o 5% según esPrecioAlto
        return 0;
    }
}

Verificación

Actualiza Main para probar los métodos:

public class Main {
    public static void main(String[] args) {
        Tienda tienda = new Tienda();

        // Prueba método 1
        System.out.println("Precio 100 con 10% descuento: " + tienda.calcularDescuento(100));

        // Prueba método 2
        System.out.println("Precio 100 con 25% descuento: " + tienda.calcularDescuento(100, 25));

        // Prueba método 3
        System.out.println("Precio 200 (alto) con descuento: " + tienda.calcularDescuento(200, true));
        System.out.println("Precio 50 (normal) con descuento: " + tienda.calcularDescuento(50, false));
    }
}

Salida Esperada

Precio 100 con 10% descuento: 90.0
Precio 100 con 25% descuento: 75.0
Precio 200 (alto) con descuento: 160.0
Precio 50 (normal) con descuento: 47.5

Explicación

  • Sobrecarga: Los métodos calcularDescuento comparten el mismo nombre pero tienen diferentes parámetros.
  • Polimorfismo en tiempo de compilación: Java selecciona el método correcto según los argumentos al compilar.
  • Esto permite usar un solo nombre para diferentes cálculos, simplificando el código.

Parte 3: Sobreescritura de Métodos en la Jerarquía de Productos

Instrucciones

Modifica Libro y Electronico para que sobreescriban el método describir de Producto. Cada clase debe devolver una descripción única: - Producto: Descripción genérica. - Libro: Indica que es un libro con páginas. - Electronico: Menciona que es un dispositivo con batería.

Código Inicial

Ya tienes Producto.java:

public class Producto {
    public String describir() {
        return "Este es un producto genérico.";
    }
}

Tarea

  1. En Libro, sobreescribe describir para que devuelva: "Este es un libro con páginas interesantes."
  2. En Electronico, sobreescribe describir para que devuelva: "Este es un dispositivo electrónico con batería."

Plantilla para Libro

public class Libro extends Producto {
    // TODO: Sobreescribir describir
}

Plantilla para Electronico

public class Electronico extends Producto {
    // TODO: Sobreescribir describir
}

Verificación

Actualiza Main para probar la jerarquía:

public class Main {
    public static void main(String[] args) {
        Tienda tienda = new Tienda();
        System.out.println("Precio 100 con 10% descuento: " + tienda.calcularDescuento(100));
        System.out.println("Precio 100 con 25% descuento: " + tienda.calcularDescuento(100, 25));
        System.out.println("Precio 200 (alto) con descuento: " + tienda.calcularDescuento(200, true));
        System.out.println("Precio 50 (normal) con descuento: " + tienda.calcularDescuento(50, false));

        System.out.println("\nDescripciones de productos:");
        Producto producto = new Producto();
        Producto libro = new Libro();
        Producto electronico = new Electronico();

        System.out.println("Producto genérico: " + producto.describir());
        System.out.println("Libro: " + libro.describir());
        System.out.println("Electrónico: " + electronico.describir());
    }
}

Salida Esperada

Precio 100 con 10% descuento: 90.0
Precio 100 con 25% descuento: 75.0
Precio 200 (alto) con descuento: 160.0
Precio 50 (normal) con descuento: 47.5

Descripciones de productos:
Producto genérico: Este es un producto genérico.
Libro: Este es un libro con páginas interesantes.
Electrónico: Este es un dispositivo electrónico con batería.

Explicación

  • Sobreescritura: Libro y Electronico redefinen describir con mensajes específicos.
  • Polimorfismo en tiempo de ejecución: Java selecciona el método correcto según el tipo real del objeto, aunque la variable sea de tipo Producto.
  • Esto permite manejar objetos de forma genérica con comportamientos específicos.

Código Completo

Archivo completo para referencia:

// Producto.java
public class Producto {
    public String describir() {
        return "Este es un producto genérico.";
    }
}

// Libro.java
public class Libro extends Producto {
    @Override
    public String describir() {
        return "Este es un libro con páginas interesantes.";
    }
}

// Electronico.java
public class Electronico extends Producto {
    @Override
    public String describir() {
        return "Este es un dispositivo electrónico con batería.";
    }
}

// Tienda.java
public class Tienda {
    public double calcularDescuento(double precio) {
        return precio * 0.9;
    }

    public double calcularDescuento(double precio, double porcentaje) {
        return precio * (1 - porcentaje / 100);
    }

    public double calcularDescuento(double precio, boolean esPrecioAlto) {
        if (esPrecioAlto) {
            return precio * 0.8;
        } else {
            return precio * 0.95;
        }
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        Tienda tienda = new Tienda();
        System.out.println("Precio 100 con 10% descuento: " + tienda.calcularDescuento(100));
        System.out.println("Precio 100 con 25% descuento: " + tienda.calcularDescuento(100, 25));
        System.out.println("Precio 200 (alto) con descuento: " + tienda.calcularDescuento(200, true));
        System.out.println("Precio 50 (normal) con descuento: " + tienda.calcularDescuento(50, false));

        System.out.println("\nDescripciones de productos:");
        Producto producto = new Producto();
        Producto libro = new Libro();
        Producto electronico = new Electronico();

        System.out.println("Producto genérico: " + producto.describir());
        System.out.println("Libro: " + libro.describir());
        System.out.println("Electrónico: " + electronico.describir());
    }
}