2010-08-22 13 views
13

Tôi muốn hiểu những gì đang xảy ra trong ví dụ bên dưới (nơi một thành viên được bảo vệ đang được truy cập từ bên ngoài gói thông qua một lớp con).Java: truy cập được bảo vệ qua các gói

Tôi biết đối với các lớp bên ngoài gói, lớp con chỉ có thể xem thành viên được bảo vệ thông qua kế thừa.

Có hai gói: package1package2.

  1. package1: ProtectedClass.java

    package org.test.package1; 
    
    public class ProtectedClass { 
    
        protected void foo() { 
         System.out.println("foo"); 
        } 
    } 
    
  2. package2: ExtendsprotectedClass.java

    package org.test.package2; 
    
    import org.test.package1.ProtectedClass; 
    
    public class ExtendsprotectedClass extends ProtectedClass { 
    
        public void boo() { 
         foo(); // This works, 
           // since protected method is visible through inheritance 
        } 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // Why is this working? 
            // Since it is accessed through a reference, 
            // foo() should not be visible, right? 
        } 
    } 
    
  3. package2: UsesExtendedClass.java

    package org.test.package2; 
    
    public class UsesExtendedClass { 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // CompilationError: 
            // The method foo() from the type ProtectedClass 
            // is not visible 
        } 
    } 
    

Điều này được hiểu rằng boo() phương pháp trong ExtendsprotectedClass có thể truy cập foo(), kể từ khi các thành viên bảo vệ có thể được truy cập thông qua thừa kế duy nhất.

Câu hỏi của tôi là, tại sao phương pháp foo() làm việc tốt khi truy cập thông qua một tài liệu tham khảo trong phương pháp main() của ExtendsprotectedClass nhưng sẽ không làm việc khi truy cập thông qua epc tham chiếu trong UsesExtendedClass?

Trả lời

12

Mã trong lớp ExtendsprotectedClass được phép truy cập các thành viên được bảo vệ của ProtectedClass thông qua tham chiếu loại ExtendsprotectedClass. Từ số JLS section 6.6.2:

Thành viên được bảo vệ hoặc người xây dựng của đối tượng có thể được truy cập chỉ bằng mã chịu trách nhiệm thực hiện đối tượng đó.

Hãy C là lớp trong đó một thành viên m bảo vệ được công bố. Truy cập chỉ được phép trong phần thân của lớp con S của C. Ngoài ra, nếu Id biểu thị một trường cá thể hoặc phương pháp mẫu, thì:

  • Nếu truy cập bằng tên đủ điều kiện Q.Id, trong đó Q là một ExpressionName, sau đó truy cập được phép khi và chỉ khi kiểu của biểu thức Q là S hoặc một lớp con của S. [...]

UsesExtendedClass không chịu trách nhiệm nội thi hành ExtendsprotectedClass, do đó cuộc gọi cuối cùng thất bại.

EDIT: Lý do đằng sau điều này là truy cập protected được thiết kế để giúp các lớp con thực hiện chức năng mà chúng cần, cho phép truy cập nhiều hơn vào bên trong lớp cha hơn bình thường.Nếu đã có sẵn cho tất cả mã, nó sẽ khá gần với việc đặt phương thức công khai. Về cơ bản, các lớp con được tin cậy không để phá vỡ đóng gói; chúng được cung cấp nhiều khả năng hơn trong các đối tượng thuộc kiểu riêng của chúng. API công khai không được hiển thị các chi tiết đó, nhưng API được bảo vệ chỉ có thể cho các mục đích mang lại cho các lớp con nhiều cơ hội hơn.

+0

@Jon Cảm ơn. Tôi hiểu rằng các thành viên lớp của phân lớp có thể truy cập các thành viên được bảo vệ (như được chỉ rõ trong phương thức 'boo()'). Nhưng đã tò mò muốn biết tại sao nó được phép truy cập vào thành viên được bảo vệ thông qua một tham chiếu của lớp con, ** CHỈ ** trong các phương thức lớp con? bất kỳ lý do nào đằng sau nó? – JWhiz

+0

@JWhiz: Chỉnh sửa ... –

+1

2) Hoạt động vì phương pháp được bảo vệ được truy cập bởi một con trỏ của lớp riêng của nó. Điều này sẽ không thành công:
void tĩnh công khai ExtendsprotectedClass.main (String [] args) { ProtectedClass epc = new ExtendsprotectedClass(); // upcast
epc.foo(); // nên là lỗi biên dịch?
} –

1

Tôi tin rằng bạn đã trả lời câu hỏi của riêng mình; UsesExtendedClass không kế thừa từ ProtectedClass, và - theo định nghĩa - các thành viên "được bảo vệ" chỉ có thể truy cập trong lớp mà chúng được khai báo/định nghĩa hoặc trong một lớp kế thừa từ lớp mà chúng được khai báo hoặc xác định.

+2

'theo định nghĩa - thành viên" được bảo vệ "chỉ có thể truy cập trong lớp mà chúng được khai báo/xác định'. Tôi không hoàn toàn đồng ý với điều đó vì các thành viên được bảo vệ có thể truy cập được từ các lớp khác trong cùng một gói mà không cần thừa kế. – JWhiz

2

Nó đang làm việc trong trường hợp đầu tiên bởi vì nó đang được gọi từ cùng một lớp ngay cả khi phương pháp đang được truy cập thông qua một tham chiếu. Bạn thậm chí có thể gọi phương thức private của ExtendsprotectedClass thông qua một tham chiếu trong cùng một phương thức chính.

+1

Cảm ơn. Bây giờ tôi thấy lý do tại sao nó có thể truy cập nó thông qua tham chiếu. '+ 1' cho nó. Tuy nhiên, nó không được phép gọi các phương thức 'private' thông qua một tham chiếu Object? Điều này không vi phạm mục đích của việc biến nó thành 'riêng tư'? Bất kỳ lý do cụ thể nào cho phép làm như vậy? – JWhiz

+1

@JWhiz các công cụ sửa đổi truy cập java làm việc ở lớp và không ở cấp độ cá thể. Do đó, một phương thức riêng tư là riêng tư cho lớp và không phải là một cá thể. Nếu cá nhân làm việc trên các cá thể, bạn sẽ phải tạo ra nhiều biến và phương thức công khai hơn nếu hai cá thể phải tương tác. Điều này sẽ phá vỡ đóng gói bằng cách làm cho việc triển khai hiển thị bên ngoài lớp. – josefx