2017-08-09 16 views
12

tôi có dưới đây kịch bản:phương pháp tĩnh trong lớp có cùng chữ ký như phương pháp mặc định trong giao diện

class C { 
    static void m1() {} 
} 

interface I { 
    default void m1() {} 
} 

//this will give compilation error : inherited method from C cannot hide public abstract method in I 
class Main extends C implements I { 

} 

Dưới đây là những câu hỏi của tôi:

  1. Tôi biết rằng phương pháp dụ sẽ ghi đè lên các phương pháp mặc định nhưng nếu phương thức tĩnh trong lớp có cùng chữ ký như phương thức mặc định trong Giao diện thì sao?

  2. Nếu tĩnh phương pháp m1() trong class C sẽ được công khai sau đó lỗi biên dịch sẽ là:

    tĩnh phương pháp m1() mâu thuẫn với phương pháp trừu tượng trong I.

vì vậy khi sửa đổi lần truy cập đã được mặc định nó đã cố gắng để ẩn và khi nó được công khai nó là mâu thuẫn. tại sao sự khác biệt này? khái niệm đằng sau nó là gì?

+0

Trình biên dịch nào bạn đang sử dụng? – Hulk

+1

Điều này không nên phụ thuộc vào sự hiện diện của việc triển khai mặc định hoặc mức truy cập - lỗi biên dịch phải giống nhau, theo ý kiến ​​của tôi. Trong nhật thực, luôn luôn là "Phương thức tĩnh này không thể ẩn phương thức cá thể của tôi", với oracle jdk 1.8.0_121 "[đường dẫn] /A.java: [5,17] m1() trong [đường dẫn] .A không thể triển khai m1() trong [path] .I phương thức ghi đè là tĩnh " – Hulk

+0

Tôi đang sử dụng 1.8 là tốt, nó cho thấy lỗi biên dịch khác nhau – user2185089

Trả lời

0

Bởi vì phương pháp lớp trong java cũng có thể được gọi là sử dụng các biến Ví dụ, cấu trúc này sẽ dẫn đến sự mơ hồ:

Main m = new Main(); 

m.m1(); 

Không rõ nếu báo cáo kết quả cuối cùng nên gọi phương thức lớp C.m1() hoặc phương pháp dụ I.m1().

1

Trả lời câu hỏi 1 của bạn:

Cả "phương pháp tĩnh trong lớp học" và "phương pháp mặc định trong giao diện" có sẵn để lớp Main, và do đó nếu họ có cùng một chữ ký, nó sẽ tạo ra sự mơ hồ.

Ví dụ:

class C{ 
    static void m1(){System.out.println("m1 from C");} 
} 

public class Main extends C{ 
    public static void main(String[] args) { 
     Main main=new Main(); 
     main.m1(); 
    } 
} 

Output: m1 from C

Tương tự,

interface I{ 
    default void m1(){System.out.println("m1 from I");} 
} 

public class Main implements I{ 
    public static void main(String[] args) { 
     Main main=new Main(); 
     main.m1(); 
    } 
} 

Output: m1 from I

Như bạn có thể thấy, cả hai có thể được truy cập tương tự. Vì vậy, đây cũng là lý do cho cuộc xung đột khi bạn thực hiện I và mở rộng C.

Trả lời câu hỏi thứ hai của bạn:

Nếu bạn phân loại và giao diện là trong cùng một gói, mặc định và sửa đổi lần truy cập công cộng nên làm việc tương tự.

Ngoài ra, m1() trong C là tĩnh không thể ghi đè và do đó không thể coi là triển khai m1() trong I và do đó vấn đề biên dịch.

Hy vọng điều đó sẽ hữu ích!

+0

lớp và giao diện trong cùng một gói, vẫn còn hành vi là khác nhau – user2185089

+0

Bạn có thể hiển thị cho tôi toàn bộ mã? – OutOfMind

+0

Nếu có bất cứ điều gì nhiều hơn bạn đã đề cập – OutOfMind

1

Tôi sẽ trả lời câu hỏi đầu tiên của bạn kể từ thứ hai đã được trả lời

Tôi biết rằng phương pháp dụ sẽ ghi đè lên các phương pháp mặc định nhưng gì nếu phương pháp tĩnh trong lớp có cùng chữ ký như phương pháp mặc định trong giao diện ?

Tôi giả sử bạn đang sử dụng JDK 1.8 và do đó sự nhầm lẫn. default công cụ sửa đổi trong một phương thức giao diện không nói về các đặc điểm truy cập của nó. Thay vào đó nó đề cập rằng giao diện chính nó cần phải thực hiện phương pháp này. Đặc tả truy cập cho phương thức này vẫn là công khai. Bắt đầu từ JDK8, các giao diện cho phép bạn chỉ định các phương thức với modifer mặc định để cho phép mở rộng các giao diện theo cách tương thích ngược.

Trong giao diện của bạn, bạn phải cung cấp cho default void m1() {} để biên soạn thành công. Thông thường chúng ta chỉ định nghĩa chúng theo cách trừu tượng như void m1(); trong một giao diện Bạn phải thực hiện phương thức này vì bạn đã chỉ định phương thức này làm mặc định. Mong là bạn hiểu.

+0

* "Bắt đầu từ JDK8, giao diện cho phép bạn chỉ định phương pháp với modifer mặc định" * - Điều gì ist này về? Các phương thức trong giao diện luôn là 'công khai' (ngay cả khi không có công cụ sửa đổi truy cập) – Marco13

+0

Nếu bạn đọc câu trả lời đầy đủ, bạn sẽ hiểu những gì tôi đang cố truyền tải. Nếu bạn định nghĩa một phương thức với công cụ sửa đổi mặc định, trình biên dịch sẽ buộc bạn phải thực hiện phương thức trong chính giao diện đó. Tôi nghĩ OP đã bỏ lỡ tính năng này vì đây là tính năng mới. – Fayaz

+0

Nếu bạn cảm thấy tôi không đặt đúng cách hoặc bạn có thể làm tốt hơn, hãy làm điều đó – Fayaz

4

Cuối cùng đó nắm để thực tế là khi bạn có một cái gì đó như thế này:

class Me { 
    public static void go() { 
     System.out.println("going"); 
    } 
} 

Những cả sẽ được phép:

Me.go(); 
Me meAgain = new Me(); 
meAgain.go(); // with a warning here 

intersting là điều này sẽ làm việc quá ví dụ:

Me meAgain = null; 
meAgain.go(); 

Cá nhân tôi vẫn thấy đây là lỗi thiết kế không thể rút lại được e để tương thích - nhưng tôi muốn trình biên dịch sẽ không cho phép tôi truy cập vào phương thức tĩnh từ một cá thể.

câu hỏi đầu tiên của bạn không liên quan đến java-8 cho mỗi gia nhập, nó đã được như thế này trước khi java-8:

interface ITest { 
    public void go(); 
} 

class Test implements ITest { 
    public static void go() { // fails to compile 

    } 
} 

phương pháp mặc định chỉ cần làm theo các quy tắc tương tự ở đây. Tại sao điều này xảy ra thực sự chi tiết khá nhiều trên ngăn xếp tràn - nhưng ý tưởng cơ bản là khả năng điều này sẽ gây nhầm lẫn về phương thức gọi (tưởng tượng ITest sẽ là một lớp mà Test sẽ mở rộng và bạn làm ITest test = new Test(); test.go(); -> phương pháp được bạn gọi?)

tôi nghĩ rằng vì những lý do tương tự này không được phép cũng (mà về cơ bản là câu hỏi thứ hai của bạn, nếu không bạn sẽ có một phương pháp tĩnh và không tĩnh có chữ ký giống nhau)

static class Me { 
    static void go() { 

    } 

    void go() { 

    } 
} 

Thật thú vị rằng đây là loại cố định (tôi đoán rằng họ nhận ra nó sẽ là rea lly xấu để làm cùng một sai lầm một lần nữa) trong phương pháp tham khảo:

static class Mapper { 
    static int increment(int x) { 
     return x + 1; 
    } 

    int decrement(int x) { 
     return x - 1; 
    } 
} 


Mapper m = new Mapper(); 
IntStream.of(1, 2, 3).map(m::increment); // will not compile 
IntStream.of(1, 2, 3).map(m::decrement); // will compile 
Các vấn đề liên quan