การเรียกเมธอดดีฟอลต์อย่างชัดเจนใน Java


247

Java 8 แนะนำวิธีการเริ่มต้นเพื่อให้ความสามารถในการขยายส่วนต่อประสานโดยไม่จำเป็นต้องแก้ไขการใช้งานที่มีอยู่

ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะเรียกใช้การเริ่มต้นของวิธีการอย่างชัดเจนเมื่อวิธีการนั้นถูกเขียนทับหรือไม่พร้อมใช้งานเนื่องจากการใช้งานเริ่มต้นที่ขัดแย้งกันในอินเตอร์เฟสที่ต่างกัน

interface A {
    default void foo() {
        System.out.println("A.foo");
    }
}

class B implements A {
    @Override
    public void foo() {
        System.out.println("B.foo");
    }
    public void afoo() {
        // how to invoke A.foo() here?
    }
}

เมื่อพิจารณาจากโค้ดด้านบนคุณจะโทรA.foo()จากวิธีการของคลาส B ได้อย่างไร


คุณช่วยบอกฉันหน่อยได้ไหมว่าทำไมคุณถึงติดตั้งวิธีการ foo () ภายในอินเทอร์เฟซของคุณ
Maciej Cygan

20
@MaciejCygan ได้รับอนุญาตใน Java 8
Rohit Jain

คำตอบ:


330

ตามบทความนี้คุณเข้าถึงวิธีการเริ่มต้นในการAใช้อินเตอร์เฟซ

A.super.foo();

สิ่งนี้สามารถใช้ดังนี้ (สมมติว่าอินเตอร์เฟสAและCทั้งสองมีวิธีการเริ่มต้นfoo())

public class ChildClass implements A, C {
    @Override    
    public void foo() {
       //you could completely override the default implementations
       doSomethingElse();
       //or manage conflicts between the same method foo() in both A and C
       A.super.foo();
    }
    public void bah() {
       A.super.foo(); //original foo() from A accessed
       C.super.foo(); //original foo() from C accessed
    }
}

AและCทั้งสองสามารถมี.foo()วิธีการและสามารถเลือกการใช้งานเริ่มต้นเฉพาะหรือคุณสามารถใช้หนึ่ง (หรือทั้งสอง) เป็นส่วนหนึ่งของfoo()วิธีการใหม่ของคุณ นอกจากนี้คุณยังสามารถใช้ไวยากรณ์เดียวกันเพื่อเข้าถึงเวอร์ชันเริ่มต้นในวิธีการอื่นในชั้นเรียนของคุณ

คำอธิบายอย่างเป็นทางการของไวยากรณ์วิธีการอุทธรณ์ที่สามารถพบได้ในบทที่ 15 ของ JLS


14
โปรดทราบด้วยว่าหากA extends SomeOtherInterfaceและSomeOtherInterfaceมีdefault Type method()แล้วคุณจะไม่สามารถโทรSomeOtherInterface.super.method()จาก ChildClass ได้ คุณสามารถเรียกวิธีการเริ่มต้นของอินเตอร์เฟซที่ระบุในChildClass's implementsข้อไม่อินเตอร์เฟซที่พ่อแม่ของพวกเขา' วิธีการ
gvlasov

1
@Suseika จุดที่ดีเช่นเดียวกับไม่มีsuper.super.someMethod();(เพราะที่จะน่ากลัว)
ริชาร์ดซ่า

@gvlasov จุดที่ดี แต่วิธีการเข้าถึงวิธีการเริ่มต้นของอินเตอร์เฟซผู้ปกครองจากอินเตอร์เฟซเด็กมันเป็นไปได้หรือไม่? อัปเดต .......... ใช่เป็นไปได้คำอธิบายที่เป็นรูปธรรมมากขึ้นที่นี่stackoverflow.com/a/24280376/3791156
Raaghu

@ Richard คำตอบไร้ที่ติเดียว!
gaurav

17

รหัสด้านล่างควรใช้งานได้

public class B implements A {
    @Override
    public void foo() {
        System.out.println("B.foo");
    }

    void aFoo() {
        A.super.foo();
    }

    public static void main(String[] args) {
        B b = new B();
        b.foo();
        b.aFoo();
    }
}

interface A {
    default void foo() {
        System.out.println("A.foo");
    }
}

เอาท์พุท:

B.foo
A.foo

ฉันคิดว่านี่เป็นตัวอย่างที่ดีที่สุดซึ่งอธิบายถึงคำถามข้างต้น ขอบคุณ
Hemanth Peela

8

คำตอบนี้เขียนขึ้นสำหรับผู้ใช้ที่มาจากคำถาม45047550ซึ่งปิด

Java 8 อินเตอร์เฟสแนะนำบางแง่มุมของการสืบทอดหลายแบบ วิธีการเริ่มต้นมีการใช้งานฟังก์ชั่นร่างกาย ในการเรียกใช้เมธอดจากคลาส super คุณสามารถใช้คีย์เวิร์ดsuperได้ แต่ถ้าคุณต้องการทำให้เป็นอินเทอร์เฟซพิเศษนั้นจำเป็นต้องตั้งชื่อให้ชัดเจน

class ParentClass {
    public void hello() {
        System.out.println("Hello ParentClass!");
    }
}

interface InterfaceFoo {
    default public void hello() {
        System.out.println("Hello InterfaceFoo!");
    }
}

interface InterfaceBar {
    default public void hello() {
        System.out.println("Hello InterfaceBar!");
    }
}

public class Example extends ParentClass implements InterfaceFoo, InterfaceBar {
    public void hello() {
        super.hello(); // (note: ParentClass.super is wrong!)
        InterfaceFoo.super.hello();
        InterfaceBar.super.hello();
    }

    public static void main(String[] args) {
        new Example().hello();
    }
}

เอาท์พุท:

สวัสดี ParentClass!
สวัสดี InterfaceFoo!
สวัสดี InterfaceBar!


3

คุณไม่จำเป็นต้องแทนที่วิธีการเริ่มต้นของอินเทอร์เฟซ เพียงแค่เรียกมันว่าดังต่อไปนี้:

public class B implements A {

    @Override
    public void foo() {
        System.out.println("B.foo");
    }

    public void afoo() {
        A.super.foo();
    }

    public static void main(String[] args) {
       B b=new B();
       b.afoo();
    }
}

เอาท์พุท:

A.foo


9
OP กล่าวว่า: "เป็นไปได้หรือไม่ที่จะเรียกใช้การเริ่มต้นของเมธอดอย่างชัดเจนเมื่อเมธอดนั้นถูกแทนที่"
dasblinkenlight
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.