2008-10-13 40 views
99

Điều kỳ lạ xảy ra trong Java khi bạn sử dụng lớp trừu tượng để thực hiện giao diện: một số phương thức của giao diện có thể bị mất hoàn toàn (nghĩa là không khai báo trừu tượng hoặc triển khai thực tế), nhưng trình biên dịch không phàn nàn.Tại sao một lớp trừu tượng thực hiện một giao diện có thể bỏ lỡ việc khai báo/thực hiện một trong các phương thức của giao diện?

Ví dụ, với giao diện:

public interface IAnything { 
    void m1(); 
    void m2(); 
    void m3(); 
} 

lớp trừu tượng sau đây được vui vẻ biên soạn mà không có một cảnh báo hoặc một lỗi:

public abstract class AbstractThing implements IAnything { 
    public void m1() {} 
    public void m3() {} 
} 

bạn có thể giải thích tại sao?

+0

Không thể tạo đối tượng của lớp trừu tượng. Vì vậy, miễn là một thực hiện không được cung cấp cho một lớp trừu tượng, các đối tượng không thể được tạo ra cho IAnything. Vì vậy, điều này là hoàn toàn tốt cho trình biên dịch. Trình biên dịch mong rằng, bất kỳ lớp không trừu tượng nào triển khai thực hiện IAnything đều phải thực hiện tất cả các phương thức được khai báo trong IAnything. Và vì người ta phải mở rộng và triển khai AbstractThing để có thể tạo ra các đối tượng, trình biên dịch sẽ ném một lỗi, nếu việc triển khai đó không thực hiện các phương thức của IAnything được AbstractThing bỏ ra. – VanagaS

+0

CHÚNG TÔI CÓ THỂ GỌI R THNG "Mẫu thiết kế bộ điều hợp" không? nếu chúng ta giữ m1, m2, m3 cơ thể trống trong lớp trừu tượng. thì MyMainClass mở rộng lớp trừu tượng đó và tôi sẽ tự do ghi đè bất kỳ phương thức nào tôi muốn, Không bắt buộc phải ghi đè tất cả các phương thức. Vui lòng thông báo !! –

Trả lời

130

Đó là vì nếu một lớp là trừu tượng, thì theo định nghĩa, bạn được yêu cầu tạo các lớp con của lớp đó để khởi tạo. Các lớp con sẽ được yêu cầu (bởi trình biên dịch) để thực hiện bất kỳ phương thức giao diện nào mà lớp trừu tượng còn lại.

Làm theo mã mẫu của bạn, hãy thử tạo một lớp con của AbstractThing mà không cần triển khai phương thức m2 và xem lỗi trình biên dịch cung cấp cho bạn những gì. Nó sẽ buộc bạn phải thực hiện phương pháp này.

+0

Tôi nghĩ rằng trình biên dịch vẫn nên ném cảnh báo về các lớp trừu tượng triển khai giao diện không đầy đủ, đơn giản vì bạn cần xem qua 2 định nghĩa lớp thay vì 1 để xem những gì bạn cần trong lớp con. Đây là một giới hạn ngôn ngữ/trình biên dịch mặc dù. – workmad3

+3

Đó sẽ không phải là một ý tưởng hay, vì thường có thể có nhiều lớp trừu tượng và cảnh báo 'giả' sẽ sớm áp đảo bạn, khiến bạn bỏ lỡ những cảnh báo 'đúng'. Nếu bạn nghĩ về nó, từ khóa 'trừu tượng' là có cụ thể để nói với trình biên dịch để ngăn chặn cảnh báo cho lớp đó. – belugabob

+4

@workmad - nếu bạn có triển khai chung cho một tập hợp con của các phương thức giao diện, bạn nên đưa nó vào một lớp cơ sở riêng biệt (DRY trumps one-place-code) – Gishu

30

Hoàn toàn ổn. Bạn không thể khởi tạo các lớp trừu tượng .. nhưng các lớp trừu tượng có thể được sử dụng để triển khai thực hiện phổ biến cho m1() và m3().
Vì vậy, nếu m2() thực hiện khác nhau đối với mỗi triển khai nhưng m1 và m3 thì không. Bạn có thể tạo các triển khai IAnything cụ thể khác nhau chỉ với thực thi m2 khác nhau và lấy được từ AbstractThing - tôn trọng nguyên tắc DRY. Đang xác thực nếu giao diện được triển khai hoàn toàn cho lớp trừu tượng là vô ích ..

Cập nhật: Thật thú vị, tôi thấy C# thực thi đây là lỗi biên dịch. Bạn buộc phải sao chép chữ ký của phương thức và đặt trước chúng với 'abstract public' trong lớp cơ sở trừu tượng trong trường hợp này .. (một cái gì đó mới hàng ngày :)

1

Lớp trừu tượng không bắt buộc phải thực hiện các phương thức. Vì vậy, mặc dù nó thực hiện một giao diện, các phương thức trừu tượng của giao diện có thể vẫn còn trừu tượng. Nếu bạn cố gắng thực hiện một giao diện trong một lớp cụ thể (tức là không trừu tượng) và bạn không thực hiện các phương thức trừu tượng mà trình biên dịch sẽ cho bạn biết: Thực hiện các phương thức trừu tượng hoặc khai báo lớp là trừu tượng.

2

Giao diện nghĩa là một lớp không triển khai phương pháp của nó, nhưng chỉ với khai báo.
Mặt khác, lớp trừu tượng là một lớp có thể thực hiện một số phương thức cùng với một số phương thức chỉ với khai báo, không thực hiện.
Khi chúng ta triển khai một giao diện cho một lớp trừu tượng, nó có nghĩa là lớp trừu tượng kế thừa tất cả các phương thức của giao diện. Vì, nó không quan trọng để thực hiện tất cả các phương thức trong lớp trừu tượng tuy nhiên nó đến lớp trừu tượng (bởi thừa kế quá), vì vậy lớp trừu tượng có thể để lại một số phương thức trong giao diện mà không cần thực hiện ở đây. Nhưng, khi lớp trừu tượng này sẽ được thừa hưởng bởi một số lớp cụ thể, chúng phải thực hiện tất cả các phương thức chưa được thực hiện đó trong lớp trừu tượng.

5

Tốt thôi. Để hiểu được điều trên, bạn phải hiểu bản chất của các lớp trừu tượng trước tiên. Chúng tương tự như giao diện trong khía cạnh đó. Đây là những gì Oracle nói về điều này here.

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation.

Vì vậy, bạn phải suy nghĩ về điều gì xảy ra khi giao diện mở rộng giao diện khác. Ví dụ:

//Filename: Sports.java 
public interface Sports 
{ 
    public void setHomeTeam(String name); 
    public void setVisitingTeam(String name); 
} 

//Filename: Football.java 
public interface Football extends Sports 
{ 
    public void homeTeamScored(int points); 
    public void visitingTeamScored(int points); 
    public void endOfQuarter(int quarter); 
} 

... như bạn có thể thấy, điều này cũng biên dịch hoàn toàn tốt đẹp. Đơn giản chỉ vì, giống như một lớp trừu tượng, một giao diện KHÔNG thể được khởi tạo. Vì vậy, nó không bắt buộc phải đề cập một cách rõ ràng các phương thức từ "cha mẹ" của nó. Tuy nhiên, TẤT CẢ các chữ ký của phương thức mẹ DO ngầm trở thành một phần của giao diện mở rộng hoặc thực hiện lớp trừu tượng. Vì vậy, một khi một lớp thích hợp (một trong đó có thể được khởi tạo) mở rộng ở trên, nó S be được yêu cầu để đảm bảo rằng mọi phương pháp trừu tượng duy nhất được thực hiện.

Hy vọng rằng sẽ giúp ... và Allahu 'alam!

+0

Đó là một quan điểm thú vị. Nó làm cho tôi nghĩ rằng "các lớp trừu tượng" thực sự là "các giao diện cụ thể", tức là các giao diện với một số phương thức cụ thể, thay vì các lớp với một số phương thức trừu tượng. –

+0

... một chút của cả hai thực sự. Nhưng có một điều chắc chắn, chúng không thể nhanh chóng được. – Grateful

2

When an Abstract Class Implements an Interface

In the section on Interfaces, it was noted that a class that implements an interface must implement all of the interface's methods. It is possible, however, to define a class that does not implement all of the interface's methods, provided that the class is declared to be abstract. For example,

abstract class X implements Y { 
    // implements all but one method of Y 
} 

class XX extends X { 
    // implements the remaining method in Y 
} 

In this case, class X must be abstract because it does not fully implement Y, but class XX does, in fact, implement Y.

tham khảo: http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

1

Với giao diện:

public interface IAnything { 
    int i; 
    void m1(); 
    void m2(); 
    void m3(); 
} 

Đây là ho w Java thực sự nhìn thấy nó:

public interface IAnything { 
    public static final int i; 
    public abstract void m1(); 
    public abstract void m2(); 
    public abstract void m3(); 
} 

Vì vậy, bạn có thể để lại một số (hoặc tất cả) các abstract phương pháp chưa thực hiện, cũng giống như bạn sẽ làm gì trong trường hợp abstract lớp mở rộng lớp khác abstract.

Khi bạn implement một interface, các quy tắc mà tất cả interface phương pháp phải được thực hiện trong nguồn gốc class, chỉ áp dụng cho bê tông class thực hiện (ví dụ, mà không phải là abstract chính nó).

Nếu bạn thực sự có kế hoạch tạo ra một abstract class ra khỏi nó, thì không có quy tắc nói rằng bạn đã để implement tất cả các phương pháp interface (lưu ý rằng trong trường hợp này nó là bắt buộc phải khai báo nguồn gốc class như abstract)

+0

Sử dụng 'javap IAnything.class' để tạo đoạn mã thứ hai. – sharhp

Các vấn đề liên quan