0Pricing
Java Academy · Lezione

Scegliere la strategia di annidamento più adatta

Scelga tra le varianti delle classi annidate in base all'accoppiamento, alle esigenze di accesso e alla leggibilità.

Scegliere la strategia di annidamento più adatta è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.

Scelta della strategia di annidamento

Java offre quattro opzioni di annidamento: classe di primo livello, classe annidata statica, classe interna (non statica) e classe locale/anonima. La scelta corretta dipende dall'accoppiamento, dalle esigenze di accesso e dall'ambito di riutilizzo.

Albero decisionale

Per scegliere, si ponga queste domande:

  1. La classe viene utilizzata solo all'interno della classe esterna? → Valuti l'annidamento
  2. Ha bisogno dell'istanza esterna? → Classe interna; altrimenti → Classe annidata statica
  3. Viene utilizzata solo in un metodo? → Classe locale o anonima
  4. Implementa un solo metodo? → Lambda

Classe di primo livello

Utilizzi una classe di primo livello quando il tipo ha un'ampia diffusione nella base di codice, rappresenta un concetto fondamentale del dominio o verrà importato da molte altre classi.

// Top-level: used across many packages
public class Product {
    // ...
}

public interface Repository<T, ID> {
    Optional<T> findById(ID id);
    void save(T entity);
}

// These belong in separate .java files and are widely imported

Classe annidata statica

Utilizzi una classe annidata statica quando è significativa solo nel contesto della classe esterna, non ha bisogno dell'istanza esterna e deve essere accessibile dall'esterno.

class Graph {
    // Edge only makes sense in the context of a Graph
    public static class Edge {
        public final int from, to, weight;
        public Edge(int from, int to, int weight) {
            this.from = from; this.to = to; this.weight = weight;
        }
    }

    private List<Edge> edges = new ArrayList<>();

    public void addEdge(int from, int to, int weight) {
        edges.add(new Edge(from, to, weight));
    }
}

Classe interna (non statica)

Utilizzi una classe interna quando ha un forte legame concettuale con l'istanza esterna e deve accedere ai suoi membri privati, ad esempio per iteratori o oggetti di supporto strettamente accoppiati.

class DataStore<T> {
    private final List<T> data;

    DataStore(List<T> data) { this.data = data; }

    // Must access data — inner class makes sense
    class Snapshot {
        private final List<T> copy;

        Snapshot() { this.copy = List.copyOf(data); } // accesses outer

        T get(int idx) { return copy.get(idx); }
        int size()     { return copy.size(); }
    }

    Snapshot snapshot() { return new Snapshot(); }
}

Classe locale

Utilizzi una classe locale quando è necessaria in un solo metodo, è abbastanza complessa da richiedere più metodi o uno stato e si desidera mantenere l'ambito il più ristretto possibile.

static int countWords(String text, boolean caseSensitive) {
    class WordCounter {
        Map<String, Integer> counts = new HashMap<>();

        void count(String word) {
            String key = caseSensitive ? word : word.toLowerCase();
            counts.merge(key, 1, Integer::sum);
        }

        int uniqueCount() { return counts.size(); }
    }

    WordCounter wc = new WordCounter();
    for (String w : text.split("\\s+")) wc.count(w);
    return wc.uniqueCount();
}
System.out.println(countWords("the cat sat on the mat", false)); // 5

Classe anonima o lambda

Utilizzi una classe anonima quando sono necessari più metodi o l'estensione di una classe astratta. Utilizzi una lambda per le interfacce SAM.

// Lambda: clean for SAM
list.sort((a, b) -> a.compareTo(b));

// Anonymous: multi-method, or extending abstract class
java.util.TimerTask task = new java.util.TimerTask() {
    @Override public void run() { System.out.println("Tick!"); }
};
// TimerTask is abstract class — can't use lambda directly

Tabella riepilogativa

Riferimento rapido:

  • Classe di primo livello: ampio riutilizzo, tipi dell'API pubblica
  • Classe annidata statica: raggruppamento logico, nessuna istanza esterna necessaria
  • Classe interna: forte legame con l'istanza esterna, accesso ai membri privati necessario
  • Classe locale: ambito del metodo, complessità sufficiente a richiedere una classe
  • Classe anonima: implementazione una tantum, di breve durata
  • Lambda: interfaccia SAM, nessuno stato, sintassi concisa

Esercitazione pratica: progettazione di un client HTTP

Applicazione della strategia di annidamento alla progettazione realistica di un client HTTP.

class HttpClient {
    // Static nested: request config has no outer reference
    public static class RequestConfig {
        public final int timeoutMs;
        public final String userAgent;
        RequestConfig(int timeout, String ua) { this.timeoutMs = timeout; this.userAgent = ua; }
    }

    // Static nested: response is standalone data carrier
    public static class Response {
        public final int statusCode;
        public final String body;
        Response(int code, String body) { this.statusCode = code; this.body = body; }
    }

    private final RequestConfig config;
    HttpClient(RequestConfig config) { this.config = config; }

    public Response get(String url) {
        // Implementation using this.config
        return new Response(200, "body");
    }
}

Evitare un annidamento eccessivo

Eviti di annidare le classi a più di un livello di profondità. Le classi profondamente annidate diventano difficili da consultare e testare. Le estragga in classi di primo livello o con visibilità package-private se diventano complesse.

Alternativa package-private

Invece di annidare una classe, valuti di renderla package-private (senza modificatore di accesso). Sarà visibile solo all'interno del package, ma sarà più facile da testare e mantenere rispetto a una classe annidata.

// In package com.example.order:

// Package-private: visible in package, no nesting
class OrderLine {  // no 'public' modifier
    final String sku;
    final int qty;
    OrderLine(String sku, int qty) { this.sku = sku; this.qty = qty; }
}

// Public class in same package can use OrderLine freely
public class Order {
    private List<OrderLine> lines = new ArrayList<>();
    // ...
}

Record e sealed come alternative

Le funzionalità moderne di Java, come record e interfacce sealed, eliminano spesso la necessità di schemi di annidamento complessi.

// Instead of nested inner class hierarchy:
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double r) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double b, double h) implements Shape {}

static double area(Shape s) {
    return switch (s) {
        case Circle c      -> Math.PI * c.r() * c.r();
        case Rectangle r   -> r.w() * r.h();
        case Triangle t    -> 0.5 * t.b() * t.h();
    };
}

Verifica rapida

Quando è preferibile una classe interna (non statica) a una classe annidata statica?

Riepilogo: scelta della strategia di annidamento

Punti chiave:

  • Classe di primo livello: tipi pubblici utilizzati in modo esteso nella base di codice
  • Classe annidata statica: raggruppata logicamente con la classe esterna, senza necessità di un'istanza esterna
  • Classe interna: fortemente legata all'istanza esterna, accede ai membri privati
  • Classe locale: con ambito limitato al metodo, abbastanza complessa da richiedere più metodi
  • Classe anonima: implementazione una tantum, combina dichiarazione e istanziazione
  • Lambda: la scelta più semplice per le interfacce SAM; da considerare in sostituzione delle classi anonime

Domande Frequenti

La lezione «Scegliere la strategia di annidamento più adatta» è gratuita?

Sì — il testo completo di «Scegliere la strategia di annidamento più adatta» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.

Cosa imparerò in «Scegliere la strategia di annidamento più adatta»?

Scelga tra le varianti delle classi annidate in base all'accoppiamento, alle esigenze di accesso e alla leggibilità. Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Java Academy?

Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Scegliere la strategia di annidamento più adatta»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Java Academy?

Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Classi annidate statiche
  2. Classi interne e accesso alla classe esterna
  3. Classi locali e anonime
  4. Scegliere la strategia di annidamento più adatta
← Torna a Java Academy