2013-08-28 29 views
22

Tôi đã thấy nhiều bài viết về sự khác biệt giữa các phần bổ trợ riêng tư được bảo vệ và gói. Một điều tôi nhận thấy mâu thuẫn giữa hai bài viết nàysự khác biệt giữa các bộ sửa đổi truy cập được bảo vệ và gói riêng tư trong Java?

  1. Isn't "package private" member access synonymous with the default (no-modifier) access?

    Trong câu trả lời chấp nhận nói rằng

    Các modifier bảo vệ xác định rằng các thành viên chỉ có thể được truy cập trong gói riêng của mình (như với gói-riêng) và, ngoài ra, bởi một lớp con của lớp của nó trong một gói khác.

  2. Why the protected modifier behave differently here in Java subclass?

    Trong câu trả lời chấp nhận nói rằng

    Để đáp ứng truy cập ở mức bảo vệ hai điều kiện phải được đáp ứng:

    • Các lớp phải nằm trong cùng một gói .
    • Phải có mối quan hệ kế thừa.

Chẳng phải họ trái ngược nhau? từ sự hiểu biết của tôi về các bài viết khác, bài đăng đầu tiên đưa ra câu trả lời chính xác được bảo vệ == gói-riêng + phân lớp trong gói khác.

Nếu tuyên bố này là đúng, thì tại sao mã này không thành công với thông báo lỗi sau trên lớp con mèo của tôi trên đường dây 17

The method testInstanceMethod() from the type Animal is not visible 

mã của tôi cho siêu và lớp dưới.

package inheritance; 

public class Animal { 

    public static void testClassMethod() { 
     System.out.println("The class" + " method in Animal."); 
    } 
    protected void testInstanceMethod() { 
     System.out.println("The instance " + " method in Animal."); 
    } 
} 

package testpackage; 

import inheritance.Animal; 

public class Cat extends Animal{ 
     public static void testClassMethod() { 
      System.out.println("The class method" + " in Cat."); 
     } 
     public void testInstanceMethod() { 
      System.out.println("The instance method" + " in Cat."); 
     } 

     public static void main(String[] args) { 
      Cat myCat = new Cat(); 
      Animal myAnimal = myCat; 
      myAnimal.testClassMethod(); 
      myAnimal.testInstanceMethod(); 
     } 
    } 

Hãy làm rõ lý do mã ở trên không thành công. Điều đó sẽ rất hữu ích. Cảm ơn

+1

Bạn phải là một Cat để sử dụng testInstanceMethod(). Casting to Animal hạn chế quyền truy cập vào phương thức đó đối với gói lavel và vì gói chính của bạn nằm trong gói khác nên mã không thành công. (Tôi nghĩ rằng nó thậm chí sẽ không biên dịch). Có phương pháp ở đó nhưng bạn không có quyền truy cập nó vì nó được khai báo trong Animal bằng cách bảo vệ. – PSIXO

+0

Tuyên bố thứ hai nên được xây dựng là: * "Để thỏa mãn mức độ truy cập được bảo vệ, ** một trong hai điều kiện phải được đáp ứng ..." * (Xem thêm bình luận tôi đã đưa ra bên dưới câu trả lời đó.) – aioobe

Trả lời

21

Câu trả lời đầu tiên về cơ bản là đúng - protected thành viên có thể được truy cập bởi

  • lớp từ cùng một gói
  • lớp con của lớp tuyên bố từ gói khác

Tuy nhiên, có một mẹo nhỏ:

6.6.2 Chi tiết về quyền truy cập được bảo vệ

Thành viên được bảo vệ hoặc người xây dựng của một đố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 đó.

Nó có nghĩa là lớp con từ gói khác không thể truy cập protected thành viên của trường tùy ý của superclasses của họ, họ chỉ có thể truy cập chúng trên trường hợp của loại riêng của họ (trong đó type là một kiểu thời gian biên dịch ngôn luận, vì nó là một kiểm tra thời gian biên dịch).

Ví dụ (giả định rằng mã này là trong Cat):

Dog dog = new Dog(); 
Animal cat = new Cat(); 

dog.testInstanceMethod(); // Not allowed, because Cat should not be able to access protected members of Dog 
cat.testInstanceMethod(); // Not allowed, because compiler doesn't know that runtime type of cat is Cat 

((Cat) cat).testInstanceMethod(); // Allowed 

Nó có ý nghĩa, bởi vì việc tiếp cận của protected thành viên của Dog bởi Cat có thể phá vỡ bất biến của Dog, trong khi Cat có thể truy cập protected thành viên riêng của mình một cách an toàn, bởi vì nó biết cách bảo đảm những bất biến của chính nó.

quy tắc chi tiết:

6.6.2.1 Truy cập vào một thành viên bảo vệ

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, thì quyền truy cập chỉ được phép nếu và chỉ khi loại biểu thức Q là S hoặc một lớp con của S.
  • Nếu truy cập bằng biểu thức truy cập trường E.Id, trong đó E là biểu thức Chính hoặc bằng biểu thức gọi hàm E.Id (...), trong đó E là biểu thức Chính, thì quyền truy cập được cho phép nếu và chỉ khi loại E là S hoặc một lớp con của S.

6.6.2.2 Đủ điều kiện Truy cập vào một Constructor được bảo vệ

Cho C là lớp trong đó một hàm tạo được bảo vệ được khai báo và để S là lớp trong cùng trong khai báo sử dụng hàm tạo được bảo vệ. Sau đó:

  • Nếu truy cập bằng cách gọi hàm tạo siêu lớp con siêu (...) Hoặc bằng trình tạo hàm bậc cha đủ điều kiện của biểu mẫu E.super (...), Trong đó E là biểu thức Chính, sau đó truy cập được cho phép.
  • Nếu truy cập là do biểu thức tạo thể hiện lớp ẩn danh của biểu mẫu mới C (...) {...} hoặc bởi biểu thức tạo thể hiện lớp đủ điều kiện của biểu mẫu E.new C (...) { ...}, trong đó E là biểu thức Chính, thì quyền truy cập được cho phép.
  • Nếu không, nếu truy nhập là bởi biểu thức tạo thể hiện lớp đơn giản của biểu mẫu C mới (...) Hoặc bằng biểu thức tạo thể hiện lớp có trình độ của biểu mẫu E.new C (...), Trong đó E là biểu thức Chính, khi đó quyền truy cập không được phép. Một constructor được bảo vệ có thể được truy cập bởi một biểu thức tạo cá thể lớp (không khai báo một lớp ẩn danh) chỉ từ bên trong gói mà nó được định nghĩa.

Xem thêm:

+0

Tôi nghĩ tôi hiểu, nhưng vẫn cần thời gian để tiêu hóa và vượt qua. Có vẻ như, nếu một superclass có 'protected void get() {}' và một subclass ghi đè nó không thể có 'void get() {}' , tức là truy cập mặc định. nhưng nó có thể có 'public void get() {}' hoặc 'protected void get() {}' – eagertoLearn

+2

@eagertoLearn - Ý tưởng đằng sau đó là một lớp con luôn có thể làm cho các phương thức dễ tiếp cận hơn nhưng không thể truy cập được; theo cách đó, lớp con vẫn tuân theo hợp đồng siêu hạng. Nói theo cách khác, việc truyền tới lớp học siêu hạng sẽ không bao giờ cho phép bạn truy cập vào nhiều phương thức hơn. –

0

Bạn đã tạo một thể hiện Cát và đúc nó vào siêu kiểu lớp ví dụ: loại động vật của nó. Theo kiểu Animal, testInstanceMethod của nó có thể nhìn thấy trong cùng một gói hoặc bất kỳ kiểu con nào. Nếu bạn không truyền đến Animal, mã sẽ biên dịch.

Hy vọng rằng sẽ giúp

./Arun

1

Trong truy cập được bảo vệ các thành viên được truy cập trong cùng một gói và thừa hưởng thành viên lớp trong gói khác cũng có thể được truy cập.

Trong gói truy cập, các thành viên của các lớp trong cùng một gói có thể được truy cập. Các thành viên lớp trong các gói khác không thể được truy cập trong gói truy cập.

+2

Câu hỏi này đã hơn ba tuổi với câu trả lời được chấp nhận. Câu trả lời của bạn cũng không thêm bất cứ điều gì đáng giá cho câu trả lời đã được chấp nhận, vì vậy tôi không thực sự nhìn thấy một điểm trong câu trả lời của bạn đang ở đây (không có hành vi phạm tội). – rayryeng

+1

Đọc "câu trả lời được chấp nhận" khiến mắt tôi chảy máu ... Tôi không phải là luật sư cú pháp ngôn ngữ (và không chơi trên TV) vì vậy tôi thực sự đánh giá cao câu trả lời "ngắn gọn hơn" này. – geowar

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