Classi interne, annidate e anonime
Fa parte della sezione Programmazione orientata agli oggetti del percorso Java di Coddy. Lezione 49 di 87.
Java ti permette di definire classi all'interno di altre classi. Queste classi interne aiutano a organizzare il codice raggruppando insieme funzionalità correlate e possono accedere direttamente ai membri della classe esterna.
Una classe interna annidata è definita come membro di un’altra classe. Ha accesso a tutti i campi e metodi della classe esterna, inclusi quelli privati:
class Outer {
private String message = "Hello";
class Inner {
void display() {
System.out.println(message); // Può accedere al campo privato
}
}
}
// Utilizzo
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display(); // Stampa: HelloUna classe interna locale è definita all'interno di un metodo. Può essere usata solo all'interno di quel metodo e può accedere alle variabili locali che sono effettivamente finali:
void process() {
String prefix = "Result: ";
class LocalHelper {
void print(int value) {
System.out.println(prefix + value);
}
}
new LocalHelper().print(42);
}Una classe interna anonima è una classe senza nome, creata e istanziata in un’unica espressione. È comunemente usata per implementare interfacce o estendere classi al volo:
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};Le classi interne sono particolarmente utili quando una classe è rilevante solo per un'altra classe, mantenendo il codice organizzato ed incapsulato.
Sfida
FacileCreiamo un sistema di carrello della spesa che mostri tutti e tre i tipi di classi interne. Creerai uno ShoppingCart che usa una classe interna annidata per rappresentare gli articoli, una classe interna locale per calcolare gli sconti e una classe interna anonima per formattare lo scontrino finale.
Organizzerai il codice in due file:
ShoppingCart.java: crea la classe esterna che gestisce l'esperienza di acquisto. Il tuo ShoppingCart dovrebbe avere un campo privatocustomerName(String).All'interno di ShoppingCart, definisci una classe interna annidata chiamata
Itemcon due campi privati:name(String) eprice(double). Assegna a Item un costruttore per inizializzare entrambi i campi e un metodogetDetails()che restituisce:[name]: $[price]Il tuo ShoppingCart deve avere un costruttore che accetta il nome del cliente e un metodo chiamato
checkout()che accetta un Item e una percentuale di sconto (double). All'interno dicheckout():- Crea una classe interna locale chiamata
DiscountCalculatorcon un metodoapplyDiscount(double originalPrice)che restituisce il prezzo dopo aver applicato la percentuale di sconto. - Usa la classe locale per calcolare il prezzo finale.
- Crea una classe interna anonima che implementa l'interfaccia
Formatter(che definirai) per formattare lo scontrino. La classe anonima dovrebbe sovrascrivere un metodoformat()che restituisce una stringa di scontrino su più righe.
Il metodo
checkout()dovrebbe restituire la stringa dello scontrino formattata con questo formato esatto:--- Receipt --- Customer: [customerName] Item: [item details from getDetails()] Discount: [discount]% Final Price: $[calculated price]- Crea una classe interna locale chiamata
Formatter.java: definisci una semplice interfaccia con un solo metodo:String format(). Questa interfaccia sarà implementata dalla tua classe interna anonima all'interno del metodo checkout.Main.java: dai vita al tuo carrello della spesa! Riceverai tre input: nome del cliente (String), nome dell'articolo (String) e prezzo dell'articolo (double). La percentuale di sconto è fissata a10.0.Crea uno ShoppingCart con il nome del cliente. Poi crea un Item usando la sintassi di riferimento alla classe esterna:
cart.new Item(name, price). Chiamacheckout()con l'articolo e lo sconto, quindi stampa lo scontrino restituito.
Riceverai tre input, in quest'ordine: nome del cliente, nome dell'articolo e prezzo dell'articolo.
Per esempio, se gli input sono Alice, Laptop e 1000.0, il prezzo finale dopo uno sconto del 10% sarà 900.0.
Nota come ogni tipo di classe interna abbia uno scopo diverso: la classe annidata raggruppa i dati correlati con la classe esterna, la classe locale incapsula la logica necessaria solo all'interno di un metodo e la classe anonima fornisce un'implementazione rapida e occasionale di un'interfaccia!
Provalo tu
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Leggi i dati di input
String customerName = scanner.nextLine();
String itemName = scanner.nextLine();
double itemPrice = scanner.nextDouble();
double discount = 10.0;
// TODO: Crea un ShoppingCart con il nome del cliente
// TODO: Crea un Item usando: cart.new Item(itemName, itemPrice)
// TODO: Chiama checkout() con l'articolo e lo sconto, poi stampa il risultato
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione a oggetti
File esterniIntroduzione alla programmazione a oggettiClassi e oggettiLa parola chiave thisMetodiCampi (attributi)Metodo costruttoreSovraccarico dei costruttoriRipasso - Calcolatrice semplice4Ereditarietà
Ereditarietà di base (extends)La parola chiave superSovrascrittura dei metodi (@Override)Concatenamento dei costruttoriLa classe ObjectEreditarietà singola e multilivelloPerché non esiste l'ereditarietà multipla delle classiRiepilogo: gerarchia dei dipendenti7Metodi speciali e classe Object
Metodo toString()equals() e hashCode()Metodo clone()compareTo() e ComparableInterfaccia ComparatorRiepilogo - Ordinamento personalizzato2Modificatori di accesso e incapsulamento
Panoramica dei livelli di accessoMetodi getter e setterNascondimento delle informazioniLa parola chiave finalRiepilogo - Gestore di conti bancari5Polimorfismo
Nozioni di base sull'overloading dei metodiOverride dei metodi (a runtime)Upcasting e downcastingL'operatore instanceofClassi e metodi astrattiRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàAggregazione vs composizioneClassi interne, annidate e anonimeEnum e metodi degli EnumRecord (Java 16+)Classi sealed (Java 17+)11Modelli di progettazione Parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern BuilderPattern ObserverPattern Strategy3Proprietà di classe e membri statici
Variabili di istanza e staticheMetodi staticiBlocchi staticiCostanti (static final)Riepilogo - Contatore e utility6Interfacce e classi astratte
Introduzione alle interfacceImplementazione delle interfacceImplementazione di più interfacceMetodi default e static nelle interfacceClassi astratte e interfacce a confrontoInterfacce funzionaliRiepilogo: sistema di pagamento9Tipi generici
Introduzione ai tipi genericiClassi genericheMetodi genericiParametri di tipo con limitiCaratteri jolly (?, extends, super)Riepilogo - Contenitore generico12Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern IteratorEsercitati da solo: Compilatore Java online