Generics ในคลาส Java Comparator T และ U คืออะไร?

Sep 09 2020

พิจารณาสองวิธีต่อไปนี้ ความแตกต่างเพียงอย่างเดียวคือในการประกาศฟังก์ชันประเภททั่วไป <>

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor)
{
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
public static <T, U extends Comparable<? super U>> Comparator<T> comparingT(
        Function<T, ? extends U> keyExtractor) <-- Check here! T instead of ? super T
{
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}

สมมติว่าผมมีList<GamingComputer> = { ASUS, MSI }ที่ยื่นออกมาGamingComputer Computerตอนนี้ฉันต้องการเรียงลำดับ

List.sort( comparing( Computer::getProperty ) )

T คืออะไร?

สัญชาตญาณของฉัน: T=GamingComputer. comparing()ใช้เวลาในการที่มีประเภทคือkeyExtractor Function<Computer super GamingComputer, Property>ในที่สุดผลตอบแทนcomparing()Comparator<GamingComputer>

รหัสนี้พิสูจน์สัญชาตญาณของฉันรวบรวมอย่างสมบูรณ์แบบ:

Function<Computer, Property> f1 = Computer::getProperty;
Comparator<GamingComputer> c1 = comparing(f1);

ตอนนี้จากเต้าตั้งแต่c1, c2จะถูกเพิ่มเข้าไปในคอลเลกชัน / คอนสตรัค / วิธีตราบใดที่การเก็บรวบรวมการจัดการเรียนผู้ปกครองของพวกเขาก็สามารถจัดการกับระดับเด็ก ๆ <? super T>นั่นเป็นเหตุผลที่อยู่เบื้องหลัง

ดังที่แสดงในรหัสนี้:

Function<Computer, Property> f2 = Computer::getProperty;
Comparator<GamingComputer> c2 = comparingT(f2); // FAILS to compile. Required Type: Comparator<GamingComputer>, Provided Comparator<Computer>
Comparator<Computer> c2 = comparingT(f2); // compiles successfuly

เนื่องจากใช้f2งานได้กับทุกคนComputerก็ควรจะสามารถทำงานร่วมกับทุกGamingComputerอย่างได้เช่นกัน แต่เพราะเราไม่ได้ประกาศเป็นประเภท<? super T>ที่เราไม่สามารถที่จะสร้างของComparatorGamingComputers

มีเหตุผล. จากนั้น ...

Comparator<GamingComputer> c22 = comparingT(Computer::getProperty); // compiles successfuly... WT, excuse mi French, heck???

ฉันเดา: comparingT()ชนิดที่T=GamingComputerกองกำลังตาละห้อยบนซึ่งเป็นkeyExtractor Computer::getPropertyมันบังคับให้ทุกComputersการใช้งานGamingComputer::getPropertyซึ่งอาจจะเป็นไม่เป็นปัญหาเนื่องจากไม่เปรียบเทียบComparator<GamingComputer>GamingComputers

แต่ทำไมสิ่งนี้ไม่รวบรวม?

Function<Computer, Property> f22 = GamingComputer::getProperty;

ข้อผิดพลาดแปลกมาก:

วิธีการแบบไม่คงที่ไม่สามารถอ้างอิงจากบริบทคงที่ซึ่งอาจเป็นข้อบกพร่องจาก Intellij

วิธีการแบบไม่คงที่ไม่สามารถอ้างอิงจากบริบทแบบคงที่ในสตรีม java 8

ถึงกระนั้นเมื่อรวบรวม:

java: incompatible types: invalid method reference
    method getPart in class function.GamingComputer cannot be applied to given types
      required: no arguments
      found: function.Computer
      reason: actual and formal argument lists differ in length

คำตอบ

1 Sweeper Sep 09 2020 at 09:48

สัญชาตญาณของฉัน: T=GamingComputer

สัญชาตญาณของคุณถูกต้อง


ทำไมComparator<GamingComputer> c22 = comparingT(Computer::getProperty);คอมไพล์?

เนื่องจากไม่เหมือนกับอินสแตนซ์ของอินเทอร์เฟซที่ใช้งานได้ซึ่งไม่แปรผัน โดยใช้ตัวอย่างจากที่นี่คุณสามารถทำสิ่งต่างๆเช่น:

// in SomeClass
public static Integer function(Object o) {
    return 2;
}

// ...
Function<String, Object> function = SomeCLass::function;

หรือใช้ชั้นเรียนของคุณคุณสามารถทำได้:

Function<GamingComputer, Property> f = Computer::getProperty;

การอ้างอิงเมธอด "ราวกับว่า" มี? superอยู่ในพารามิเตอร์และ? extendsประเภทผลตอบแทน! รายละเอียดของสิ่งที่ใช้ได้ผลและสิ่งที่ไม่ได้ระบุไว้ในส่วนที่15.13.2ของข้อกำหนดภาษา Java

ดังนั้นสำหรับc22, ยังคงเป็นT GamingComputerการอ้างอิงเมธอดComputer::getPropertyสามารถแปลงFunction<GamingComputer, Property>เป็นการอ้างอิงเมธอดได้

สิ่งนี้ไม่ได้รวบรวมแม้ว่าf2"ร้านค้า" Computer::getProperty:

Comparator<GamingComputer> c2 = comparingT(f2);

เนื่องจากf2ไม่ใช่วิธีการอ้างอิงเอง มันเป็นตัวแปร

ทำไมFunction<Computer, Property> f22 = GamingComputer::getProperty;ไม่คอมไพล์?

f22จะสามารถที่จะยอมรับทุกชนิดของใด ๆเพราะมันยอมรับComputer Computerถ้าคุณให้f22คอมพิวเตอร์ชนิดอื่น (ไม่GamingComputer) GamingComputer.getPropertyแน่นอนจะไม่สามารถจัดการได้หรือไม่?