2011-07-27 34 views
44

Tại sao Java xác định rằng trình chỉ định truy cập cho một phương thức ghi đè có thể cho phép nhiều hơn, nhưng không ít hơn, truy cập so với phương pháp ghi đè? Ví dụ, một phương thức cá thể được bảo vệ trong siêu lớp có thể được công khai, nhưng không phải là riêng tư, trong lớp con.Các công cụ sửa đổi truy cập java và các phương thức ghi đè

+6

Để sử dụng mô tả chung: 'B mở rộng A' nếu' B là A '. Vì vậy, nếu 'A' có thể thực hiện' action() ', và' B là a', thì 'B' cũng có thể thực hiện' action() '. – davin

+0

cảm ơn tất cả các bạn. Bây giờ tôi hiểu rằng việc khai báo mở rộng (A mở rộng B) cũng tạo ra một lược đồ kế thừa truy cập một chiều (mở rộng hơn). – yesilupper

Trả lời

47

Đó là một nguyên tắc cơ bản trong OOP: lớp trẻ là một trường hợp hoàn toàn chính thức của lớp cha mẹ, và phải do hiện ít nhất cùng một giao diện làm lớp cha. Làm cho những điều được bảo vệ/công khai ít hiển thị hơn sẽ vi phạm ý tưởng này; bạn có thể làm cho các lớp con không sử dụng được như các cá thể của lớp cha.

+1

Đồng ý với Patrick. Điều này cũng theo nguyên tắc thay thế Liskov – tapasvi

7

Bởi vì nó sẽ là kỳ lạ:

class A { 
    public void blah() {} 
} 

class B extends A { 
    private void blah() {} 
} 


B b = new B(); 
A a = b; 
b.blah(); // Can't do it! 
a.blah(); // Can do it, even though it's the same object! 
+0

Tôi nghĩ rằng trước khi bạn thay đổi nó là một ví dụ cụ thể hơn, mặc dù điều này hơi khó chịu hơn, vì bạn có thể định nghĩa một trường hợp như vậy để ném một ngoại lệ thời gian chạy khi truy cập một phương thức riêng tư (rõ ràng là một thuật ngữ được phát minh). Nhưng trong ví dụ trước của bạn người ta sẽ phải làm việc, và người kia phải thất bại. Có thể bao gồm cả hai? – davin

+0

@davin: Tôi chưa thay đổi! Tôi chỉ cải thiện nhận xét mã ... –

+0

Ồ, sau đó tôi tưởng tượng rằng bạn có 'A a = new A(); B b = new B(); 'hoặc' A b = new B(); ' – davin

26

Hãy tưởng tượng hai loại cổ phiếu này:

public class Animal { 
    public String getName() { return this.name; } 
} 

public class Lion extends Animal { 
    private String getName() { return this.name; } 
} 

tôi có thể viết mã này:

Animal lion = new Lion(); 
System.out.println(lion.getName()); 

Và nó sẽ phải có giá trị, kể từ ngày Động vật phương thức getName() là công khai, ngay cả khi nó được đặt ở chế độ riêng tư trên Lion. Vì vậy, không thể làm cho mọi thứ ít hiển thị hơn trên các lớp con như khi bạn có một tham chiếu siêu lớp, bạn sẽ có thể truy cập vào nội dung này.

+0

Bạn đang thiếu một 'mở rộng động vật' :) – Jeffrey

+0

có vẻ là một câu trả lời tốt hơn. – instinct

+0

Đây là nguyên tắc thay thế của Liskov. – RainDoctor

0

Vì một lớp con là một chuyên môn của lớp cha hoặc nói cách khác, đó là phần mở rộng của lớp cha.

Hãy tưởng tượng ví dụ phương pháp toString. Tất cả các đối tượng Java đều có nó vì Object của lớp có nó. Hãy tưởng tượng bạn có thể định nghĩa một lớp với phương thức toString là private. Sau đó bạn không còn đối xử với tất cả các đối tượng như nhau nữa. Ví dụ, bạn sẽ không còn có thể một cách an toàn này:

for (Object obj : collection) System.out.println(obj);

0

Vâng, về trường hợp cụ thể bạn đã đề cập, Java sẽ xử lý chính xác điều đó như thế nào? Nếu lớp con tạo một phương thức public/protected private, thì JVM nên làm gì khi phương thức đó được gọi trên một cá thể của lớp con? Tôn trọng riêng tư và gọi triển khai của lớp cha? Hơn nữa, bạn đang phá vỡ hợp đồng được chỉ định bởi các siêu lớp khi bạn đột nhiên nói "không ai có thể truy cập phương pháp này, mặc dù những gì hợp đồng ban đầu nói."

5

Lấy một ví dụ đưa ra dưới đây

class Person{ 
public void display(){ 
     //some operation 
    } 
} 

class Employee extends Person{ 
    private void display(){ 
     //some operation 
    } 
} 

trọng điển hình xảy ra trong trường hợp sau đây

Person p=new Employee(); 

Đây p là tài liệu tham khảo đối tượng với kiểu Person (siêu lớp) khi chúng ta đang kêu gọi p .display(). Khi sửa đổi lần truy cập là hạn chế hơn, các tài liệu tham khảo đối tượng p không thể truy cập đối tượng con của loại nhân viên

1

muộn để đảng nhưng tôi muốn thêm một người nữa mối quan tâm liên quan đến trọng: Phương pháp trọng phải cho phép ít (hoặc cùng một mức độ) ngoại lệ ném được so với phương pháp ghi đè; thậm chí không có gì ném được.

Liskov nguyên tắc thay thế có thể giải thích rằng quá:

interface Actionable { 
    void action() throws DislocationException; 
} 

public class Actor implements Actionable { 
    @Override 
    public void action() throws DislocationException { 
    //.... 
    } 
} 

public class Stuntman implements Actionable { 
    @Override // this will cause compiler error 
    public void action() throws DislocationException, DeathException { 
    //.... 
    } 
} 

// legacy code to use Actionable 
try { 
    Actionable actor = new Actor(); // this cannot be replaced by a Stuntman, 
            // or it may break the try/catch block 
    actor.action(); 
} catch (DislocationException exc) { 
    // Do something else 
} 

Ở trên, phương pháp ghi đè đưa ra cam kết rằng trong trường hợp xấu nhất nó sẽ ném DislocationException, không còn phải (một bác sĩ là cần thiết tại địa điểm quay phim) . Vì vậy, phương pháp ghi đè không được phá vỡ điều đó, bằng cách thêm nhiều DeathException (hoặc xe cứu thương là phải)

Tôi thường gọi quy tắc ghi đè "[có thể] thêm quyền truy cập [cấp độ], [nhưng] ít ngoại lệ"

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