Công cụ sửa đổi quyền truy cập 'được bảo vệ' của Java

1. Khái quát chung

Trong ngôn ngữ lập trình Java, các trường, hàm tạo, phương thức và lớp có thể được đánh dấu bằng các bổ trợ truy cập. Trong hướng dẫn này, chúng ta sẽ xem xét quyền truy cập được bảo vệ .

2. Từ khoá được bảo vệ

Trong khi các phần tử được khai báo là private chỉ có thể được truy cập bởi lớp mà chúng được khai báo, từ khóa protected cho phép truy cập từ các lớp con và thành viên của cùng một gói.

Bằng cách sử dụng từ khóa được bảo vệ , chúng tôi đưa ra quyết định về những phương thức và trường nào nên được coi là nội bộ của một gói hoặc cấu trúc phân cấp lớp và những phương thức và trường nào được hiển thị với mã bên ngoài.

3. Khai báo các trường, phương thức và hàm tạo được bảo vệ

Đầu tiên, hãy tạo mộtlớp có tên FirstClass chứa trường, phương thức và hàm tạo được bảo vệ :

public class FirstClass { protected String name; protected FirstClass(String name) { this.name = name; } protected String getName() { return name; } }

Với ví dụ này, bằng cách sử dụng từ khóa được bảo vệ , chúng tôi đã cấp quyền truy cập vào các trường này cho các lớp trong cùng gói với FirstClass và cho các lớp con của FirstClass .

4. Truy cập các Trường, Phương thức và Trình tạo được bảo vệ

4.1 Từ cùng một gói

Bây giờ, hãy xem cách chúng ta có thể truy cập các trường được bảo vệ bằng cách tạo một GenericClass mới được khai báo trong cùng một gói với FirstClass :

public class GenericClass { public static void main(String[] args) { FirstClass first = new FirstClass("random name"); System.out.println("FirstClass name is " + first.getName()); first.name = "new name"; } }

Vì lớp gọi này nằm trong cùng một gói với FirstClass, nó được phép xem và tương tác với tất cả các trường, phương thức và hàm tạo được bảo vệ .

4.2. Từ một gói khác

Bây giờ, hãy thử tương tác với các trường này từ một lớp được khai báo trong một gói khác với FirstClass :

public class SecondGenericClass { public static void main(String[] args) { FirstClass first = new FirstClass("random name"); System.out.println("FirstClass name is "+ first.getName()); first.name = "new name"; } }

Như chúng ta có thể thấy, chúng ta gặp lỗi biên dịch :

The constructor FirstClass(String) is not visible The method getName() from the type FirstClass is not visible The field FirstClass.name is not visible

Đó chính xác là những gì chúng tôi đã mong đợi bằng cách sử dụng từ khóa được bảo vệ . Điều này là do SecondGenericClass không nằm trong cùng một gói với FirstClass và không phân lớp nó.

4.3 Từ một lớp phụ

Bây giờ chúng ta hãy xem điều gì sẽ xảy ra khi chúng ta khai báo một lớp mở rộng FirstClass nhưng được khai báo trong một gói khác :

public class SecondClass extends FirstClass { public SecondClass(String name) { super(name); System.out.println("SecondClass name is " + this.getName()); this.name = "new name"; } }

Như mong đợi, chúng ta có thể truy cập tất cả các trường, phương thức và hàm tạo được bảo vệ. Điều này là do SecondClass là một lớp con của FirstClass .

5. Lớp bên trong được bảo vệ

Trong các ví dụ trước, chúng ta đã thấy các trường, phương thức và hàm tạo được bảo vệ đang hoạt động. Có một trường hợp cụ thể nữa - một lớp bên trong được bảo vệ .

Hãy tạo lớp bên trong trống này bên trong FirstClass của chúng ta :

package com.baeldung.core.modifiers; public class FirstClass { // ... protected static class InnerClass { } }

Như chúng ta có thể thấy, đây là một lớp bên trong tĩnh, và vì vậy có thể được xây dựng từ bên ngoài một thể hiện của FirstClass . Tuy nhiên, vì nó được bảo vệ , chúng tôi chỉ có thể khởi tạo nó từ mã trong cùng một gói với FirstClass .

5.1 Từ cùng một gói

Để kiểm tra điều này, hãy chỉnh sửa GenericClass của chúng tôi :

public class GenericClass { public static void main(String[] args) { // ... FirstClass.InnerClass innerClass = new FirstClass.InnerClass(); } }

Như chúng ta thấy, chúng ta có thể khởi tạo InnerClass mà không gặp bất kỳ vấn đề gì vì GenericClass nằm trong cùng một gói với FirstClass .

5.2. Từ một gói khác

Hãy thử khởi tạo một InnerClass từ SecondGenericClass , như chúng ta nhớ, nằm ngoài gói FirstClass :

public class SecondGenericClass { public static void main(String[] args) { // ... FirstClass.InnerClass innerClass = new FirstClass.InnerClass(); } }

As expected, we get a compilation error:

The type FirstClass.InnerClass is not visible

5.3. From a Sub-Class

Let's try to do the same from our SecondClass:

public class SecondClass extends FirstClass { public SecondClass(String name) { // ... FirstClass.InnerClass innerClass = new FirstClass.InnerClass(); } }

We were expecting to instantiate our InnerClass with ease. However, we are getting a compilation error here too:

The constructor FirstClass.InnerClass() is not visible

Let's take a look at our InnerClass declaration:

protected static class InnerClass { }

The main reason we are getting this error is that the default constructor of a protected class is implicitly protected. In addition, SecondClassis a sub-class of FirstClass but is not a sub-class of InnerClass. Finally, we also declaredSecondClass outside FirstClass' package.

For all these reasons, SecondClass can't access the protectedInnerClass constructor.

Nếu chúng tôi muốn giải quyết vấn đề này và cho phép SecondClass của chúng tôi khởi tạo một đối tượng InnerClass , chúng tôi có thể khai báo một cách rõ ràng một hàm tạo công khai :

protected static class InnerClass { public InnerClass() { } }

Bằng cách làm này, chúng tôi không còn gặp lỗi biên dịch nữa và bây giờ chúng tôi có thể khởi tạo InnerClass từ SecondClass .

6. Kết luận

Trong hướng dẫn nhanh này, chúng tôi đã thảo luận về công cụ sửa đổi quyền truy cập được bảo vệ trong Java. Với nó, chúng tôi có thể đảm bảo chỉ hiển thị dữ liệu và phương thức cần thiết cho các lớp con và lớp trong cùng một gói.

Như mọi khi, mã ví dụ có sẵn trên GitHub.