2013-04-03 41 views
12

Tôi biết rằng điều này đã được hỏi trước trong diễn đàn này nhưng tôi sẽ hỏi lại vì tôi không thấy bất kỳ câu trả lời hay nào (cho đến nay).Java: Hạn chế truy cập được bảo vệ cho lớp con trên đối tượng siêu lớp

Ở đây nó đi:

package a; 
public class A{ 
    protected int a; 
} 

package b; 
public class B extends A{ 
} 

package c; 
public class C extends B{ 
    public void accessField(){ 
     A ancient = new A(); 
     ancient.a = 2; //A - That wouldn't work. 

     a = 2; //B - That works. 
    } 

} 

Tại sao khoản A) sẽ không làm việc? Lý do đằng sau hạn chế này đối với quyền truy cập cổ đại đối tượng siêu lớp trong phân lớp C là gì?
Cảm ơn.

+1

Tôi đoán một bước kế thừa ở đây là không cần thiết để minh họa trường hợp. – Vitaly

+2

@HovercraftFullOfEels Tôi đoán câu hỏi lý thuyết hơn là thực tế nhưng không thú vị. – assylias

Trả lời

6

Thành viên được bảo vệ chỉ có thể truy cập được bên ngoài cùng một gói nếu đó là thông qua thừa kế - tức là trong hệ thống phân cấp.

Vì vậy, khi bạn tạo một phiên bản A khác từ một gói khác, đó không phải là một mối quan hệ thừa kế và do đó không thành công.

Như mọi khi, điều này được bao phủ trong JLS, 6.6.2:

Một thành viên bảo vệ hoặc constructor của một đối tượng có thể được truy cập từ bên ngoài gói trong đó nó được tuyên bố chỉ cho phép code đó là trách nhiệm để thực hiện đối tượng đó.

+0

Tôi đang bối rối. Phần tương tự cũng cho biết "* Truy cập chỉ được phép trong phần thân của lớp con S của C. *" - nó không nói * trực tiếp * phân lớp, chỉ lớp con ... – assylias

+0

@assylias Điểm công bằng - đó không phải là ý của tôi trực tiếp trong trường hợp này, nhưng tôi thấy nó có thể mơ hồ như thế nào nên tôi đã thay đổi từ ngữ một chút! – berry120

+1

@ berry120 Cảm ơn! – yapkm01

1

Trích dẫn từ sách Ngôn ngữ lập trình Java 3 ed. bởi Gosling và tất cả - trang 81 giây 3.5

"Những gì được bảo vệ thực sự có nghĩa là" - .. ngoài khả năng truy cập trong lớp và mã trong cùng một gói, một thành viên được bảo vệ cũng có thể được truy cập từ một lớp học các tham chiếu đối tượng là ít nhất cùng loại với lớp - đó là tham chiếu đến loại của lớp hoặc một trong các lớp con của nó

5

Thực tế bạn không cần hai mức kế thừa và mã bên dưới sẽ dẫn đến cùng một hành vi :

public class B extends A{ 
    public void accessField() { 
     A ancient = new A(); 
     ancient.a = 2; //A - That wouldn't work. 

     a = 2; //B - That works. 
    } 
} 

Lý do tại sao a = 2 hoạt động là JLS 6.2.2.1:

Cho C là lớp trong đó thành viên được bảo vệ được khai báo. Chỉ được phép truy cập trong nội dung của một phân lớp S của C.

Lưu ý rằng nó không nói trực tiếp phân lớp, nhưng chỉ phân lớp con. Vì vậy, a = 2 hoạt động trong lớp B hoặc lớp C.

Mặt khác, ancient.a = 2; được bao phủ bởi các điểm viên đạn tiếp theo trong cùng một phần:

Nếu truy cập là bởi một tên có trình độ Q.Id, trong đó Q là một ExpressionName, sau đó truy cập là cho phép nếu và chỉ nếu kiểu của biểu thức Q là S hoặc một lớp con của S.

trong trường hợp của bạn, Q.Idancient.a => nó sẽ chỉ có thể truy cập nếu loại ancientB hoặc một lớp con của B.Vì vậy, ví dụ, điều này sẽ biên dịch:

public class B extends A{ 
    public void accessField() { 
     C ancient = new C(); 
     ancient.a = 2; //A - That wouldn't work. 
    } 
} 
0

Trích dẫn từ JLS 6.6.2

Một thành viên bảo vệ hoặc constructor của một đối tượng có thể được truy cập từ bên ngoài gói trong đó nó được tuyên bố chỉ cho phép code đó là trách nhiệm việc thực hiện đối tượng đó.

Khi bạn nói,

A ancient = new A(); 
ancient.a = 2; 

bạn không kế thừa bất cứ điều gì từ cổ xưa (Một đối tượng) và do đó không chịu trách nhiệm thi hành. Bằng cách làm cho C mở rộng A, bạn đã thừa kế 'a' từ một đối tượng A khác nhau, do đó câu lệnh bên dưới hoạt động.

a = 2; 

Nếu,

ancient.a = 2; 

công trình, sau đó không có sự khác biệt giữa một cộng đồng và một specifier truy cập tin.

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