ไวลด์การ์ดใน API
ออกแบบเมธอด泛型ที่ยืดหยุ่น
ไวลด์การ์ดใน API เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
การออกแบบเมธอดที่ยืดหยุ่น
ไวลด์การ์ดเป็นเครื่องมือหลักสำหรับผู้ออกแบบส่วนติดต่อโปรแกรม ไวลด์การ์ดที่วางไว้อย่างเหมาะสมช่วยให้ผู้เรียกส่งชนิดข้อมูลได้มากขึ้นโดยไม่ต้องแปลงชนิด
เป้าหมายคือให้ผู้เรียกมีความยืดหยุ่นสูงสุด ขณะที่ภายในยังปลอดภัยด้านชนิดข้อมูลอย่างสมบูรณ์
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)));
}
}ไวลด์การ์ดแบบไม่มีขอบเขต
List<?> คือไวลด์การ์ดแบบไม่มีขอบเขต หมายถึงรายการของชนิดข้อมูลบางชนิดที่ไม่ทราบแน่ชัด
ใช้เมื่อเมธอดไม่สนใจชนิดข้อมูลขององค์ประกอบ เช่น การนับองค์ประกอบหรือการตรวจสอบว่ารายการว่างหรือไม่
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<?> เทียบกับ List<Object>
สองอย่างนี้แตกต่างกัน List<Object> รับเฉพาะรายการที่ประกาศเป็น Object ส่วน List<?> รับรายการของชนิดข้อมูลใดก็ได้
คุณสามารถส่ง List<String> ไปยังพารามิเตอร์ List<?> ได้ แต่ส่งไปยังพารามิเตอร์ 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
}
}เมื่อพารามิเตอร์ชนิดข้อมูลชัดเจนกว่า
หากคุณต้องอ้างอิงถึงชนิดข้อมูลขององค์ประกอบมากกว่าหนึ่งครั้ง การใช้พารามิเตอร์ชนิดข้อมูลที่มีชื่อจะอ่านเข้าใจได้ดีกว่าไวลด์การ์ด
ลองเปรียบเทียบ void swap(List<?> l, int i, int j) (ซึ่งต้องใช้ตัวช่วยส่วนตัว) กับรุ่นทั่วไปที่เขียนได้สะอาดกว่า
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);
}
}เทคนิคการจับไวลด์การ์ดด้วยตัวช่วย
หากส่วนติดต่อโปรแกรมสาธารณะจำเป็นต้องใช้ List<?> คุณสามารถมอบหมายงานให้ตัวช่วยทั่วไปแบบส่วนตัวเพื่อจับไวลด์การ์ดได้
ตัวช่วยจะตั้งชื่อชนิดข้อมูลเป็น T เพื่อให้สามารถเขียนค่ากลับลงในรายการได้
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);
}
}พารามิเตอร์ผู้ผลิตในส่วนติดต่อโปรแกรมจริง
การออกแบบ addAll ที่ดึงข้อมูลจากแหล่งข้อมูลที่เข้ากันได้ทุกชนิดจะใช้ขอบเขตบนกับแหล่งข้อมูล
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);
}
}พารามิเตอร์ผู้บริโภคในส่วนติดต่อโปรแกรมจริง
ส่วนติดต่อโปรแกรมสำหรับรับข้อมูลที่เขียนผลลัพธ์จะใช้ขอบเขตล่างกับปลายทาง เพื่อให้ผู้เรียกส่งภาชนะที่รองรับชนิดข้อมูลกว้างกว่าได้
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);
}
}ไวลด์การ์ดกับชนิดข้อมูลทั่วไปซ้อนกัน
ชนิดข้อมูลทั่วไปที่ซ้อนกันมักต้องใช้ไวลด์การ์ด เมธอดที่รับรายการซึ่งแต่ละองค์ประกอบเป็นรายการชนิดใดก็ได้จะใช้ 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"))));
}
}หลีกเลี่ยงการใช้ชนิดข้อมูลทั่วไปเกินจำเป็น
ไม่ใช่ทุกเมธอดที่ต้องใช้ไวลด์การ์ด หากผู้เรียกส่งชนิดข้อมูลเพียงชนิดเดียวเสมอ การใช้พารามิเตอร์ธรรมดาจะชัดเจนกว่า
เพิ่มไวลด์การ์ดเมื่อพบว่าผู้เรียกจริงถูกขัดขวางด้วยความไม่แปรผัน ไม่ใช่เพิ่มไว้ล่วงหน้า
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")));
}
}การอธิบายเจตนาของไวลด์การ์ด
ไวลด์การ์ดสื่อถึงเจตนา ? extends T บอกผู้อ่านว่า “ฉันอ่านค่านี้เท่านั้น” ส่วน ? super T บอกว่า “ฉันเขียนค่านี้เท่านั้น”
การเลือกไวลด์การ์ดที่เหมาะสมเป็นรูปแบบหนึ่งของโค้ดที่อธิบายตัวเอง และยังบังคับใช้สัญญาการทำงานด้วย
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);
}
}ส่วนติดต่อโปรแกรม Stack แบบทั่วไป
ตัวอย่าง Stack อันโด่งดังของ Bloch: pushAll รับข้อมูลจากผู้ผลิต (ขอบเขตบน) ส่วน popAll สร้างข้อมูลให้ผู้บริโภค (ขอบเขตล่าง)
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);
}
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบสัญชาตญาณของคุณในการออกแบบส่วนติดต่อโปรแกรม
ทบทวน
คุณได้เรียนรู้การออกแบบส่วนติดต่อโปรแกรมด้วยไวลด์การ์ดแล้ว:
List<?>สำหรับเมธอดแบบอ่านอย่างเดียวที่ไม่ขึ้นกับชนิดข้อมูล- ใช้ PECS กับพารามิเตอร์เพื่อเพิ่มความยืดหยุ่น
- ใช้เทคนิคจับไวลด์การ์ดด้วยตัวช่วยส่วนตัวเมื่อจำเป็นต้องเขียนผ่านไวลด์การ์ด
- หลีกเลี่ยงไวลด์การ์ดในชนิดผลลัพธ์และอย่าใช้ชนิดข้อมูลทั่วไปเกินจำเป็น
คุณเรียนจบหลักสูตรไวลด์การ์ดและ PECS แล้ว
public class Main {
public static void main(String[] args) {
System.out.println("Wildcards in APIs course complete");
}
}คำถามที่พบบ่อย
บทเรียน “ไวลด์การ์ดใน API” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ไวลด์การ์ดใน API” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ไวลด์การ์ดใน API”
ออกแบบเมธอด泛型ที่ยืดหยุ่น คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ไวลด์การ์ดใน API” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ไวลด์การ์ดขอบเขตบน
- ไวลด์การ์ดขอบเขตล่าง
- หลักการ PECS
- ไวลด์การ์ดใน API