Gọi một cách rõ ràng một phương thức mặc định trong Java


247

Java 8 giới thiệu các phương thức mặc định để cung cấp khả năng mở rộng giao diện mà không cần sửa đổi các triển khai hiện có.

Tôi tự hỏi liệu có thể gọi một cách rõ ràng việc triển khai mặc định của một phương thức khi phương thức đó đã bị ghi đè hoặc không khả dụng do các xung đột triển khai mặc định trong các giao diện khác nhau.

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?
    }
}

Xem xét mã ở trên, bạn sẽ gọi A.foo()từ một phương thức của lớp B như thế nào?


Bạn có thể cho tôi biết lý do tại sao bạn triển khai phương thức foo () bên trong giao diện của bạn A ??.
Maciej Cygan

20
@MaciejCygan Nó được cho phép trong Java 8
Rohit Jain

Câu trả lời:


330

Theo bài viết này, bạn truy cập phương thức mặc định trong giao diện Abằng cách sử dụng

A.super.foo();

Điều này có thể được sử dụng như sau (giả sử giao diện ACcả hai đều có phương thức mặc định 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
    }
}

ACcả hai có thể có .foo()các phương thức và việc triển khai mặc định cụ thể có thể được chọn hoặc bạn có thể sử dụng một (hoặc cả hai) như một phần của foo()phương thức mới của mình . Bạn cũng có thể sử dụng cùng một cú pháp để truy cập các phiên bản mặc định trong các phương thức khác trong lớp triển khai của bạn.

Mô tả chính thức của cú pháp gọi phương thức có thể được tìm thấy trong chương 15 của JLS .


14
Cũng lưu ý rằng nếu A extends SomeOtherInterfaceSomeOtherInterfacedefault Type method(), thì bạn không thể gọi SomeOtherInterface.super.method()từ ChildClass. Bạn chỉ có thể gọi các phương thức mặc định của giao diện liệt kê trong ChildClass's implementskhoản, chứ không phải giao diện cha mẹ' phương pháp.
gvlasov

1
@Suseika điểm tốt, giống như không có super.super.someMethod();(vì điều đó sẽ rất kinh khủng)
Richard Tingle

@gvlasov điểm tốt, nhưng làm thế nào để truy cập phương thức mặc định của giao diện cha mẹ từ giao diện con, có được không ?? Cập nhật .......... Có Có thể, phần giải thích cụ thể hơn tại đây stackoverflow.com/a/24280376/3791156
Raaghu

@RichardTingle câu trả lời hoàn hảo!
gaurav

17

Mã dưới đây sẽ hoạt động.

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

Đầu ra:

B.foo
A.foo

Tôi nghĩ rằng đây là ví dụ tốt nhất mô tả câu hỏi trên. Cảm ơn
Hemanth Peela

8

Câu trả lời này được viết chủ yếu cho người dùng đến từ câu hỏi 45047550 đã bị đóng.

Các giao diện Java 8 giới thiệu một số khía cạnh của nhiều kế thừa. Các phương thức mặc định có một thân hàm thực hiện. Để gọi một phương thức từ siêu hạng, bạn có thể sử dụng từ khóa super, nhưng nếu bạn muốn thực hiện điều này với một giao diện siêu thì bắt buộc phải đặt tên rõ ràng.

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

Đầu ra:

Xin chào phụ huynh!
Xin chào InterfaceFoo!
Xin chào InterfaceBar!


3

Bạn không cần ghi đè phương thức mặc định của giao diện. Chỉ cần gọi nó như sau:

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

Đầu ra:

A.foo


9
OP nói: "[có thể] gọi một cách rõ ràng việc triển khai mặc định của một phương thức khi phương thức đó đã bị ghi đè"
dasblinkenlight 14/11/13
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.