0Pricing
Java Academy · Lekcja

Wybór właściwej strategii zagnieżdżania

Wybieraj między wariantami klas zagnieżdżonych na podstawie sprzężenia, wymagań dotyczących dostępu i czytelności.

Wybór właściwej strategii zagnieżdżania to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Wybór właściwej strategii zagnieżdżania

Java oferuje cztery możliwości zagnieżdżania: klasy najwyższego poziomu, statyczne klasy zagnieżdżone, klasy wewnętrzne (niestatyczne) oraz klasy lokalne i anonimowe. Wybór właściwego rozwiązania zależy od stopnia powiązania, wymagań dotyczących dostępu i zakresu ponownego użycia.

Drzewo decyzyjne

Aby dokonać wyboru, zadaj sobie następujące pytania:

  1. Czy klasa jest używana wyłącznie wewnątrz klasy zewnętrznej? → Rozważ zagnieżdżenie
  2. Czy potrzebuje instancji klasy zewnętrznej? → Klasa wewnętrzna; w przeciwnym razie → statyczna klasa zagnieżdżona
  3. Czy jest używana tylko w jednej metodzie? → Klasa lokalna lub anonimowa
  4. Czy implementuje jedną metodę? → Lambda

Klasa najwyższego poziomu

Użyj klasy najwyższego poziomu, gdy typ ma szerokie zastosowanie w bazie kodu, reprezentuje kluczowe pojęcie domenowe lub będzie importowany przez wiele innych klas.

// 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

Statyczna klasa zagnieżdżona

Użyj statycznej klasy zagnieżdżonej, gdy klasa ma znaczenie wyłącznie w kontekście klasy zewnętrznej, nie potrzebuje jej instancji i powinna być dostępna z zewnątrz.

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));
    }
}

Klasa wewnętrzna (niestatyczna)

Użyj klasy wewnętrznej, gdy klasa jest silnie powiązana pojęciowo z instancją klasy zewnętrznej i musi uzyskiwać dostęp do jej prywatnych składowych — na przykład w przypadku iteratorów lub ściśle powiązanych obiektów pomocniczych.

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(); }
}

Klasa lokalna

Użyj klasy lokalnej, gdy klasa jest potrzebna tylko w jednej metodzie, jest wystarczająco złożona, by mieć wiele metod lub własny stan, a także gdy chcesz ograniczyć jej zakres do minimum.

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

Klasa anonimowa a lambda

Użyj klasy anonimowej, gdy potrzebnych jest wiele metod lub rozszerzenie klasy abstrakcyjnej. Użyj lambdy w przypadku interfejsów 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

Tabela podsumowująca

Szybkie przypomnienie:

  • Najwyższego poziomu: szerokie ponowne użycie, typy publicznego API
  • Statyczna klasa zagnieżdżona: logicznie zgrupowana, nie wymaga instancji klasy zewnętrznej
  • Wewnętrzna: silnie powiązana z instancją klasy zewnętrznej, wymaga dostępu prywatnego
  • Lokalna: ograniczona do metody, wystarczająco złożona, by wymagać klasy
  • Anonimowa: jednorazowa implementacja, krótkotrwała
  • Lambda: interfejs SAM, brak stanu, zwięzła składnia

Praktyka: projekt klienta HTTP

Zastosowanie strategii zagnieżdżania w realistycznym projekcie klienta 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");
    }
}

Unikaj nadmiernego zagnieżdżania

Unikaj zagnieżdżania na więcej niż jednym poziomie. Głęboko zagnieżdżone klasy są trudne w nawigacji i testowaniu. Jeśli staną się złożone, wydziel je do klas najwyższego poziomu lub klas z widocznością pakietową.

Alternatywa: widoczność pakietowa

Zamiast zagnieżdżać klasę, rozważ nadanie jej widoczności pakietowej (bez modyfikatora dostępu). Będzie widoczna tylko w obrębie pakietu, ale łatwiejsza do testowania i utrzymania niż klasa zagnieżdżona.

// 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<>();
    // ...
}

Rekordy i uszczelnianie jako alternatywy

Nowoczesne funkcje języka Java — rekordy i uszczelnione interfejsy — często eliminują potrzebę stosowania złożonych wzorców zagnieżdżania.

// 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();
    };
}

Szybkie sprawdzenie

Kiedy klasa wewnętrzna (niestatyczna) jest lepszym wyborem niż statyczna klasa zagnieżdżona?

Podsumowanie: wybór właściwej strategii zagnieżdżania

Najważniejsze informacje:

  • Klasa najwyższego poziomu: typy publiczne używane w wielu miejscach bazy kodu
  • Statyczna klasa zagnieżdżona: logicznie powiązana z klasą zewnętrzną, nie wymaga jej instancji
  • Klasa wewnętrzna: silnie powiązana z instancją klasy zewnętrznej, uzyskuje dostęp do prywatnych składowych
  • Klasa lokalna: ograniczona do metody, wystarczająco złożona, by mieć wiele metod
  • Klasa anonimowa: jednorazowa, łączy deklarację z utworzeniem instancji
  • Lambda: najczytelniejsze rozwiązanie dla interfejsów SAM; warto ją rozważyć jako zamiennik klasy anonimowej

Często zadawane pytania

Czy lekcja „Wybór właściwej strategii zagnieżdżania” jest bezpłatna?

Tak — pełny tekst „Wybór właściwej strategii zagnieżdżania” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wybór właściwej strategii zagnieżdżania”?

Wybieraj między wariantami klas zagnieżdżonych na podstawie sprzężenia, wymagań dotyczących dostępu i czytelności. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Wybór właściwej strategii zagnieżdżania”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Statyczne klasy zagnieżdżone
  2. Klasy wewnętrzne i dostęp do klasy zewnętrznej
  3. Klasy lokalne i anonimowe
  4. Wybór właściwej strategii zagnieżdżania
← Powrót do Java Academy