0Pricing
Java Academy · Lekcja

Symbole wieloznaczne z dolnym ograniczeniem

? super T dla konsumentów

Symbole wieloznaczne z dolnym ograniczeniem to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 2 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.

Wildcard z dolnym ograniczeniem

? super T to wildcard z dolnym ograniczeniem. Oznacza „jakiś nieznany typ, który jest typem T lub jego nadtypem”.

List<? super Integer> może wskazywać na List<Integer>, List<Number> albo List<Object>.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? super Integer> a = new ArrayList<Number>();
        List<? super Integer> b = new ArrayList<Object>();
        a.add(1);
        b.add(2);
        System.out.println(a + " " + b);
    }
}

Zapisywanie do konsumenta

W przypadku ? super Integer można bezpiecznie dodawać dowolne wartości typu Integer (lub podtypu Integer).

Niezależnie od rzeczywistego typu listy jest ona co najmniej listą pewnego nadtypu Integer, więc wartość Integer zawsze będzie do niej pasować.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static void addNumbers(List<? super Integer> dest) {
        for (int i = 1; i <= 3; i++) dest.add(i);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        addNumbers(nums);
        System.out.println(nums);
    }
}

Odczyt daje Object

Kompromis polega na tym, że podczas odczytu z listy ? super T kompilator wie jedynie, że elementy są pewnym nieznanym nadtypem T.

Jedynym bezpiecznym typem używanym przy odczycie jest Object.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? super Integer> list = new ArrayList<Number>();
        list.add(10);
        Object o = list.get(0); // only Object is guaranteed
        // Integer i = list.get(0); // would NOT compile
        System.out.println(o);
    }
}

Dlaczego odczyt jest ograniczony

List<? super Integer> może w rzeczywistości być obiektem typu List<Object> zawierającym napisy.

Odczyt może więc zwrócić dowolny obiekt typu Object. Kompilator nie może zagwarantować wartości typu Integer, dlatego przy odczycie otrzymujemy tylko Object.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Object> raw = new ArrayList<>();
        raw.add("a string");
        List<? super Integer> view = raw; // legal: Object is a supertype of Integer
        view.add(5);
        System.out.println(view.get(0).getClass().getSimpleName());
    }
}

Przypadek użycia konsumenta

Należy używać ? super T, gdy metoda tylko konsumuje wartości, czyli zapisuje je w kolekcji.

Klasycznym przykładem jest metoda wypełniająca docelową kolekcję.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static void fill(List<? super String> dest, int count) {
        for (int i = 0; i < count; i++) dest.add("item" + i);
    }
    public static void main(String[] args) {
        List<Object> objs = new ArrayList<>();
        fill(objs, 3);
        System.out.println(objs);
    }
}

Dodawanie podtypów również działa

W przypadku ? super Number można dodawać dowolny typ Number lub jego podtypy: Integer, Double i Long.

Dolne ograniczenie gwarantuje, że lista przyjmuje co najmniej wartości typu Number, więc wszystkie podtypy będą pasować.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? super Number> list = new ArrayList<Object>();
        list.add(1);      // Integer
        list.add(2.5);    // Double
        list.add(3L);     // Long
        System.out.println(list);
    }
}

Styl Collections.addAll

JDK używa dolnych ograniczeń w przypadku miejsc docelowych, do których trafiają wartości. Przykładem jest metoda generyczna umieszczająca elementy w kolekcji docelowej.

import java.util.ArrayList;
import java.util.List;

public class Main {
    @SafeVarargs
    static <T> void addAll(List<? super T> dest, T... items) {
        for (T item : items) dest.add(item);
    }
    public static void main(String[] args) {
        List<Object> sink = new ArrayList<>();
        addAll(sink, "a", "b", "c");
        System.out.println(sink);
    }
}

Comparator z super

Praktyczne zastosowanie: Comparator<? super T> pozwala, aby sortowanie przyjęło komparator napisany dla nadtypu.

Komparator porównujący dowolne obiekty za pomocą toString może posortować listę napisów typu String.

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Comparator<Object> byString = Comparator.comparing(Object::toString);
        List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
        names.sort(byString); // List<String>.sort accepts Comparator<? super String>
        System.out.println(names);
    }
}

super i extends są swoim lustrzanym odbiciem

Te dwa wildcardy są przeciwieństwami:

  • ? extends T: odczyt T, brak możliwości zapisu. Jest producentem.
  • ? super T: zapis T, a przy odczycie tylko Object. Jest konsumentem.

Ta symetria stanowi podstawę reguły PECS, którą poznają Państwo w następnej części.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? super Integer> consumer = new ArrayList<Number>();
        consumer.add(1);
        System.out.println("consumer can write: " + consumer);
    }
}

Kopiowanie między ograniczeniami

Metoda kopiująca pokazuje oba wildcardy jednocześnie: odczytuje z ? extends T i zapisuje do ? super T.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void copy(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Integer> src = List.of(1, 2, 3);
        List<Number> dest = new ArrayList<>();
        copy(src, dest);
        System.out.println(dest);
    }
}

Kiedy nie używać wildcarda

Jeśli metoda zarówno odczytuje, jak i zapisuje wartości typu T, nie należy używać wildcarda. Należy użyć dokładnego typu albo nazwanego parametru typu.

Wildcardy służą właśnie do przypadków tylko do odczytu albo tylko do zapisu.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void swapFirstTwo(List<T> list) {
        T tmp = list.get(0);
        list.set(0, list.get(1));
        list.set(1, tmp);
    }
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("a", "b"));
        swapFirstTwo(list);
        System.out.println(list);
    }
}

Szybkie sprawdzenie

Proszę sprawdzić, jak dobrze rozumieją Państwo dolne ograniczenia.

Podsumowanie

Poznali Państwo wildcardy z dolnym ograniczeniem:

  • ? super T oznacza nieznany nadtyp T.
  • Można zapisywać T i jego podtypy — kolekcja jest konsumentem.
  • Odczyt zwraca wyłącznie Object.
  • Jest to dokładne lustrzane odbicie ? extends T.

Następnie poznamy regułę, która łączy oba przypadki: PECS.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? super Integer> list = new ArrayList<Number>();
        list.add(42);
        System.out.println("Lower bound recap: " + list);
    }
}

Często zadawane pytania

Czy lekcja „Symbole wieloznaczne z dolnym ograniczeniem” jest bezpłatna?

Tak — pełny tekst „Symbole wieloznaczne z dolnym ograniczeniem” 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 „Symbole wieloznaczne z dolnym ograniczeniem”?

? super T dla konsumentów Ć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 2 z 4.

Ile czasu zajmuje lekcja „Symbole wieloznaczne z dolnym ograniczeniem”?

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. Symbole wieloznaczne z górnym ograniczeniem
  2. Symbole wieloznaczne z dolnym ograniczeniem
  3. Zasada PECS
  4. Symbole wieloznaczne w API
← Powrót do Java Academy