Menu
Coddy logo textTech

Clases internas, anidadas y anónimas

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 49 de 87.

Java permite definir clases dentro de otras clases. Estas clases internas ayudan a organizar el código agrupando funcionalidades relacionadas y pueden acceder directamente a los miembros de la clase externa.

Una clase interna anidada se define como un miembro de otra clase. Tiene acceso a todos los campos y métodos de la clase externa, incluidos los privados:

class Outer {
    private String message = "Hello";
    
    class Inner {
        void display() {
            System.out.println(message);  // Puede acceder al campo privado
        }
    }
}

// Uso
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display();  // Imprime: Hello

Una clase interna local se define dentro de un método. Solo se puede utilizar dentro de ese método y puede acceder a variables locales que son efectivamente finales:

void process() {
    String prefix = "Result: ";
    
    class LocalHelper {
        void print(int value) {
            System.out.println(prefix + value);
        }
    }
    
    new LocalHelper().print(42);
}

Una clase interna anónima es una clase sin nombre, creada e instanciada en una sola expresión. Se utiliza comúnmente para implementar interfaces o extender clases sobre la marcha:

Comparator<String> comp = new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
};

Las clases internas son particularmente útiles cuando una clase solo es relevante para otra clase, manteniendo su código organizado y encapsulado.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de carrito de compras que muestre los tres tipos de clases internas! Crearás un ShoppingCart que utiliza una clase interna anidada para representar artículos, una clase interna local para calcular descuentos y una clase interna anónima para formatear el recibo final.

Organizarás tu código en dos archivos:

  • ShoppingCart.java: Crea la clase externa que gestiona una experiencia de compra. Tu ShoppingCart debe tener un campo privado customerName (String).

    Dentro de ShoppingCart, define una clase interna anidada llamada Item con dos campos privados: name (String) y price (double). Dale a Item un constructor para inicializar ambos campos y un método getDetails() que devuelva: [name]: $[price]

    Tu ShoppingCart necesita un constructor que reciba el nombre del cliente, y un método llamado checkout() que acepte un Item y un porcentaje de descuento (double). Dentro de checkout():

    1. Crea una clase interna local llamada DiscountCalculator con un método applyDiscount(double originalPrice) que devuelva el precio después de aplicar el porcentaje de descuento.
    2. Usa la clase local para calcular el precio final.
    3. Crea una clase interna anónima que implemente la interfaz Formatter (la cual definirás) para formatear el recibo. La clase anónima debe sobrescribir un método format() que devuelva una cadena de recibo multilínea.

    El método checkout() debe devolver la cadena del recibo formateada con este formato exacto:

    --- Receipt ---
    Customer: [customerName]
    Item: [item details from getDetails()]
    Discount: [discount]%
    Final Price: $[calculated price]
  • Formatter.java: Define una interfaz simple con un único método: String format(). Esta interfaz será implementada por tu clase interna anónima dentro del método checkout.
  • Main.java: ¡Dale vida a tu carrito de compras! Recibirás tres entradas: nombre del cliente (String), nombre del artículo (String) y precio del artículo (double). El porcentaje de descuento es fijo en 10.0.

    Crea un ShoppingCart con el nombre del cliente. Luego crea un Item usando la sintaxis de referencia de la clase externa: cart.new Item(name, price). Llama a checkout() con el artículo y el descuento, e imprime el recibo devuelto.

Recibirás tres entradas en orden: nombre del cliente, nombre del artículo y precio del artículo.

Por ejemplo, si las entradas son Alice, Laptop, y 1000.0, el precio final después de un descuento del 10% sería 900.0.

¡Observa cómo cada tipo de clase interna sirve para un propósito diferente: la clase anidada agrupa datos relacionados con la clase externa, la clase local encapsula la lógica necesaria solo dentro de un método, y la clase anónima proporciona una implementación rápida y de un solo uso de una interfaz!

Hoja de referencia

Java permite definir clases dentro de otras clases. Estas clases internas ayudan a organizar el código agrupando la funcionalidad relacionada y pueden acceder directamente a los miembros de la clase externa.

Clase Interna Anidada

Una clase interna anidada se define como un miembro de otra clase. Tiene acceso a todos los campos y métodos de la clase externa, incluidos los privados:

class Outer {
    private String message = "Hello";
    
    class Inner {
        void display() {
            System.out.println(message);  // Can access private field
        }
    }
}

// Usage
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display();  // Prints: Hello

Clase Interna Local

Una clase interna local se define dentro de un método. Solo se puede utilizar dentro de ese método y puede acceder a variables locales que sean efectivamente finales:

void process() {
    String prefix = "Result: ";
    
    class LocalHelper {
        void print(int value) {
            System.out.println(prefix + value);
        }
    }
    
    new LocalHelper().print(42);
}

Clase Interna Anónima

Una clase interna anónima es una clase sin nombre, creada e instanciada en una sola expresión. Se utiliza comúnmente para implementar interfaces o extender clases sobre la marcha:

Comparator<String> comp = new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
};

Las clases internas son particularmente útiles cuando una clase solo es relevante para otra clase, manteniendo su código organizado y encapsulado.

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leer las entradas
        String customerName = scanner.nextLine();
        String itemName = scanner.nextLine();
        double itemPrice = scanner.nextDouble();
        
        double discount = 10.0;
        
        // TODO: Crear un ShoppingCart con el nombre del cliente
        
        // TODO: Crear un Item usando: cart.new Item(itemName, itemPrice)
        
        // TODO: Llamar a checkout() con el item y discount, luego imprimir el resultado
        
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos