Java Academy · Pelajaran

Wildcard dalam API

Rancang method generik yang fleksibel.

Pelajaran 4 dari 413 langkah

Wildcard dalam API adalah pelajaran Java Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Java Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Java Academy mencakup 4 pelajaran total.

Merancang Metode yang Fleksibel

Karakter pengganti terutama merupakan alat bagi perancang antarmuka pemrograman aplikasi. Karakter pengganti yang ditempatkan dengan tepat memungkinkan pemanggil meneruskan lebih banyak tipe tanpa melakukan konversi.

Tujuannya adalah fleksibilitas maksimum bagi pemanggil dan keamanan tipe penuh di dalamnya.

import java.util.List;

public class Main {
    static double total(List<? extends Number> items) {
        double sum = 0;
        for (Number n : items) sum += n.doubleValue();
        return sum;
    }
    public static void main(String[] args) {
        System.out.println(total(List.of(1, 2, 3)));
        System.out.println(total(List.of(1.5, 2.5)));
    }
}

Karakter Pengganti Tanpa Batas

List<?> adalah karakter pengganti tanpa batas: daftar dengan suatu tipe yang tidak diketahui.

Gunakan ini ketika metode Anda tidak memedulikan tipe elemen, misalnya untuk menghitung elemen atau memeriksa apakah daftar kosong.

import java.util.List;

public class Main {
    static int size(List<?> any) {
        return any.size();
    }
    public static void main(String[] args) {
        System.out.println(size(List.of("a", "b")));
        System.out.println(size(List.of(1, 2, 3)));
    }
}

List<?> vs List<Object>

Keduanya berbeda. List<Object> hanya menerima daftar yang dideklarasikan sebagai Object. List<?> menerima daftar dengan tipe apa pun.

Anda dapat meneruskan List<String> ke parameter List<?>, tetapi tidak ke parameter List<Object>.

import java.util.List;

public class Main {
    static void printAll(List<?> list) {
        for (Object o : list) System.out.println(o);
    }
    public static void main(String[] args) {
        List<String> names = List.of("Ada", "Linus");
        printAll(names); // works; List<Object> would reject this
    }
}

Kapan Parameter Tipe Lebih Jelas

Jika Anda perlu merujuk ke tipe elemen lebih dari sekali, parameter tipe yang diberi nama lebih mudah dipahami daripada karakter pengganti.

Bandingkan void swap(List<?> l, int i, int j) (yang memerlukan penolong privat) dengan versi generik yang lebih rapi.

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

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

Trik Penangkapan dengan Penolong

Jika API publik harus menggunakan List<?>, Anda dapat mendelegasikan tugas ke penolong generik privat untuk menangkap karakter pengganti tersebut.

Penolong itu menamai tipe T sehingga dapat menulis kembali ke dalam daftar.

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

public class Main {
    public static void reverse(List<?> list) { reverseHelper(list); }
    private static <T> void reverseHelper(List<T> list) {
        for (int i = 0, j = list.size() - 1; i < j; i++, j--) {
            T tmp = list.get(i);
            list.set(i, list.get(j));
            list.set(j, tmp);
        }
    }
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4));
        reverse(list);
        System.out.println(list);
    }
}

Parameter Produsen dalam API Nyata

Merancang addAll yang mengambil elemen dari sumber kompatibel apa pun menggunakan batas atas pada sumber tersebut.

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

public class Main {
    static <T> void addAll(List<T> target, Collection<? extends T> source) {
        for (T t : source) target.add(t);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        addAll(nums, List.of(1, 2, 3));
        System.out.println(nums);
    }
}

Parameter Konsumen dalam API Nyata

API penampung yang menulis hasil menggunakan batas bawah pada tujuan, sehingga pemanggil dapat menyediakan wadah yang lebih luas.

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

public class Main {
    static <T> void repeat(T value, int times, List<? super T> sink) {
        for (int i = 0; i < times; i++) sink.add(value);
    }
    public static void main(String[] args) {
        List<Object> out = new ArrayList<>();
        repeat("hi", 3, out);
        System.out.println(out);
    }
}

Karakter Pengganti dengan Generik Bersarang

Generik bersarang sering memerlukan karakter pengganti. Metode yang menerima daftar berisi jenis daftar apa pun menggunakan List<? extends List<?>>.

import java.util.List;

public class Main {
    static int countAll(List<? extends List<?>> lists) {
        int total = 0;
        for (List<?> inner : lists) total += inner.size();
        return total;
    }
    public static void main(String[] args) {
        System.out.println(countAll(List.of(List.of(1, 2), List.of("a", "b", "c"))));
    }
}

Menghindari Penggunaan Generik yang Berlebihan

Tidak semua metode memerlukan karakter pengganti. Jika pemanggil selalu meneruskan satu tipe saja, parameter biasa lebih jelas.

Tambahkan karakter pengganti ketika Anda melihat pemanggil nyata terhambat oleh invarian, bukan sebagai tindakan pencegahan.

import java.util.List;

public class Main {
    // Simple and clear; no wildcard needed for this internal use
    static String joinStrings(List<String> parts) {
        return String.join(", ", parts);
    }
    public static void main(String[] args) {
        System.out.println(joinStrings(List.of("a", "b", "c")));
    }
}

Mendokumentasikan Maksud Karakter Pengganti

Karakter pengganti menyampaikan maksud. ? extends T memberi tahu pembaca, "Saya hanya membaca ini". ? super T menyatakan, "Saya hanya menulis ini".

Memilih karakter pengganti yang tepat merupakan bentuk kode yang mendokumentasikan dirinya sendiri sekaligus menegakkan kontraknya.

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

public class Main {
    // src: read-only producer; dest: write-only consumer
    static <T> void transfer(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Number> dest = new ArrayList<>();
        transfer(List.of(1, 2), dest);
        System.out.println(dest);
    }
}

API Stack Generik

Contoh stack terkenal karya Bloch: pushAll mengonsumsi dari produsen (extends), sedangkan popAll menghasilkan ke dalam konsumen (super).

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.ArrayList;
import java.util.List;

public class Main {
    static class Stack<E> {
        private final Deque<E> items = new ArrayDeque<>();
        void pushAll(Collection<? extends E> src) { for (E e : src) items.push(e); }
        void popAll(Collection<? super E> dst) { while (!items.isEmpty()) dst.add(items.pop()); }
    }
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        s.pushAll(List.of(1, 2, 3));
        List<Number> out = new ArrayList<>();
        s.popAll(out);
        System.out.println(out);
    }
}

Pemeriksaan Singkat

Uji naluri Anda dalam merancang API.

Ringkasan

Anda telah mempelajari cara merancang API dengan karakter pengganti:

  • List<?> untuk metode hanya-baca yang tidak bergantung pada tipe.
  • Terapkan PECS pada parameter untuk mendapatkan fleksibilitas.
  • Gunakan trik penangkapan dengan penolong privat ketika Anda harus menulis melalui karakter pengganti.
  • Hindari karakter pengganti dalam tipe pengembalian dan jangan menggunakan generik secara berlebihan.

Anda telah menyelesaikan kursus karakter pengganti dan PECS.

public class Main {
    public static void main(String[] args) {
        System.out.println("Wildcards in APIs course complete");
    }
}
Gratis untuk memulai

Belajar Java dengan tutor AI — gratis

Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.

Kursus
104
Pelajaran
374

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Wildcard dalam API” gratis?

Ya — teks lengkap “Wildcard dalam API” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Java Academy, upgrade ke CoddyKit PRO. Kursus Java Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Wildcard dalam API”?

Rancang method generik yang fleksibel. Kamu berlatih Java Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Java Academy?

Tidak diperlukan pengalaman sebelumnya. Java Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Wildcard dalam API” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Java Academy ini?

Ya. Setiap pelajaran Java Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Wildcard Berbatas Atas
  2. Wildcard Berbatas Bawah
  3. Prinsip PECS
  4. Wildcard dalam API
← Kembali ke Java Academy