Java Academy · บทเรียน

ไวลด์การ์ดขอบเขตล่าง

? super T สำหรับผู้บริโภคข้อมูล

บทเรียน 2 จาก 413 ขั้นตอน

ไวลด์การ์ดขอบเขตล่าง เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

ไวลด์การ์ดที่มีขอบเขตล่าง

? super T คือไวลด์การ์ดที่มีขอบเขตล่าง หมายถึง “ชนิดข้อมูลบางชนิดที่ไม่ทราบแน่ชัด ซึ่งเป็น T หรือชนิดข้อมูลที่อยู่เหนือกว่า T”

List<? super Integer> อาจอ้างอิงถึง List<Integer>, List<Number> หรือ 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);
    }
}

การเขียนลงในผู้บริโภค

เมื่อใช้ ? super Integer คุณสามารถเพิ่มค่าจำนวนเต็มใด ๆ (หรือชนิดย่อยของค่าจำนวนเต็ม) ได้อย่างปลอดภัย

ไม่ว่าชนิดข้อมูลจริงของรายการจะเป็นอะไร รายการนั้นก็เป็นรายการของชนิดข้อมูลที่อยู่เหนือกว่าค่าจำนวนเต็มอย่างน้อย ดังนั้นค่าจำนวนเต็มจึงใส่ลงไปได้เสมอ

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

การอ่านจะได้ Object

ข้อแลกเปลี่ยนคือ เมื่อคุณอ่านจากรายการ ? super T คอมไพเลอร์จะทราบเพียงว่าองค์ประกอบเป็นชนิดข้อมูลที่อยู่เหนือกว่า T บางชนิดที่ไม่ทราบแน่ชัด

ชนิดข้อมูลเดียวที่ปลอดภัยสำหรับการอ่านคือ 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);
    }
}

เหตุใดการอ่านจึงมีข้อจำกัด

List<? super Integer> อาจเป็น List<Object> ที่เก็บค่า String อยู่จริงก็ได้

ดังนั้นการอ่านจึงอาจคืนค่าออบเจ็กต์ใด ๆ ก็ได้ คอมไพเลอร์ไม่สามารถรับรองได้ว่าจะเป็นค่าจำนวนเต็ม จึงให้ผลการอ่านเป็น 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());
    }
}

กรณีใช้งานสำหรับผู้บริโภค

ใช้ ? super T เมื่อเมธอดทำหน้าที่รับค่าเพียงอย่างเดียว (เขียนค่าเข้าไป)

เมธอดที่เติมข้อมูลลงในชุดข้อมูลปลายทางเป็นกรณีใช้งานแบบคลาสสิก

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

การเพิ่มชนิดย่อยก็ทำได้เช่นกัน

เมื่อใช้ ? super Number คุณสามารถเพิ่มค่าชนิดตัวเลขหรือชนิดย่อยของมันได้ทุกชนิด เช่น ค่าจำนวนเต็ม ค่าทศนิยม และจำนวนเต็มขนาดยาว

ขอบเขตล่างรับรองว่ารายการจะยอมรับชนิดตัวเลขเป็นอย่างน้อย ดังนั้นชนิดย่อยทั้งหมดจึงใส่ลงไปได้

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

รูปแบบ Collections.addAll

JDK ใช้ขอบเขตล่างสำหรับส่วนรับข้อมูล ตัวอย่างเช่น เมธอดทั่วไปที่นำองค์ประกอบใส่ลงในปลายทาง

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

ตัวเปรียบเทียบกับ super

การใช้งานในโลกจริงคือ Comparator<? super T> ซึ่งทำให้การเรียงลำดับยอมรับตัวเปรียบเทียบที่เขียนไว้สำหรับชนิดข้อมูลที่อยู่เหนือกว่าได้

ตัวเปรียบเทียบที่เปรียบเทียบออบเจ็กต์ใด ๆ ด้วย toString สามารถเรียงรายการของ 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);
    }
}

ขอบเขตล่างและขอบเขตบนเป็นภาพสะท้อนกัน

ไวลด์การ์ดทั้งสองชนิดเป็นแนวคิดตรงข้ามกัน:

  • ? extends T: อ่านค่าเป็น T แต่เขียนไม่ได้ เป็นผู้ผลิต
  • ? super T: เขียนค่าเป็น T และอ่านได้เพียง Object เป็นผู้บริโภค

ความสมมาตรนี้เป็นหัวใจของกฎ PECS ที่คุณจะได้เรียนรู้ต่อไป

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

การคัดลอกระหว่างขอบเขต

เมธอด copy แสดงการใช้ไวลด์การ์ดทั้งสองชนิดพร้อมกัน: อ่านจาก ? extends T และเขียนลงใน ? 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);
    }
}

กรณีที่ไม่ควรใช้ไวลด์การ์ด

หากเมธอดทั้งอ่านและเขียนค่า T อย่าใช้ไวลด์การ์ด ให้ใช้ชนิดข้อมูลที่ระบุแน่นอนหรือพารามิเตอร์ชนิดข้อมูลที่มีชื่อ

ไวลด์การ์ดมีไว้โดยเฉพาะสำหรับกรณีที่อ่านอย่างเดียวหรือเขียนอย่างเดียว

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

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับขอบเขตล่าง

ทบทวน

คุณได้เรียนรู้เกี่ยวกับไวลด์การ์ดที่มีขอบเขตล่างแล้ว:

  • ? super T หมายถึงชนิดข้อมูลที่อยู่เหนือกว่า T ซึ่งไม่ทราบแน่ชัด
  • คุณสามารถเขียนค่า T และชนิดย่อยของมันได้ (ผู้บริโภค)
  • การอ่านจะคืนค่าเป็น Object เท่านั้น
  • แนวคิดนี้เป็นภาพสะท้อนของ ? extends T โดยตรง

ถัดไปคือกฎที่เชื่อมโยงทั้งสองแนวคิดเข้าด้วยกัน: 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);
    }
}
เริ่มต้นได้ฟรี

เรียนรู้ Java ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
104
บทเรียน
374

คำถามที่พบบ่อย

บทเรียน “ไวลด์การ์ดขอบเขตล่าง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ไวลด์การ์ดขอบเขตล่าง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ไวลด์การ์ดขอบเขตล่าง”

? super T สำหรับผู้บริโภคข้อมูล คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ไวลด์การ์ดขอบเขตล่าง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ไวลด์การ์ดขอบเขตบน
  2. ไวลด์การ์ดขอบเขตล่าง
  3. หลักการ PECS
  4. ไวลด์การ์ดใน API
← กลับไปที่ Java Academy