Tại sao một lớp không thể được định nghĩa là được bảo vệ?


89

Tại sao chúng ta không thể định nghĩa một lớp là protected?

Tôi biết rằng chúng ta không thể, nhưng tại sao? Cần phải có một số lý do cụ thể.


3
Nó sẽ làm gì nếu bạn khai báo một lớp được bảo vệ?

1
Tôi nghĩ rằng đây là những gì bạn đang tìm kiếm: stackoverflow.com/questions/2534733/java-protected-classes : D
dewijones92

2
Hãy nói lý do tại sao lớp ngoài không thể được bảo vệ? Các lớp bên trong có thể được bảo vệ.
Số 945

Câu trả lời:


101

Bởi vì nó không có ý nghĩa.

Thành viên lớp được bảo vệ (phương thức hoặc biến) cũng giống như gói-riêng (khả năng hiển thị mặc định), ngoại trừ việc nó cũng có thể được truy cập từ các lớp con.
Vì không có khái niệm như 'gói con' hay 'gói-kế thừa' trong Java, việc khai báo lớp được bảo vệ hoặc gói-riêng sẽ giống nhau.

Tuy nhiên, bạn có thể khai báo các lớp lồng nhau và lớp bên trong là lớp bảo vệ hoặc lớp riêng tư.


> Vì không có khái niệm như 'gói con' hoặc 'gói-kế thừa' trong Java, việc khai báo lớp được bảo vệ hoặc gói-riêng sẽ giống nhau. Tại sao lớp được bảo vệ sẽ có khả năng hiển thị giống như gói-riêng? Nó không giống với công khai? Cảm ơn.
yaromir

@Nikita Ryback Bạn có thể giải thích SubPackage hay gói-kế thừa là gì không? Tôi vẫn chưa rõ lý do tại sao protected lại được sử dụng trong lớp cấp cao nhất. Nếu bạn giải thích bằng ví dụ thì sẽ rất tuyệt.
App Kart

Khi bạn khai báo thành viên lớp là được bảo vệ, khả năng hiển thị của nó là các lớp ở cùng một gói (được gọi là quyền truy cập gói) và Lớp con . Nếu bạn cố gắng truy cập từ một lớp bên ngoài trong gói khác, thành viên phương thức được bảo vệ này sẽ không hiển thị.
kelgwiin

@kelgwiin Tôi tin rằng bạn không nên kết hợp các công cụ sửa đổi quyền truy cập của các lớp và của các thành viên. Bởi vì hai cái khác nhau. Trong khi các lớp cho phép tự sửa đổi dưới dạng công khai hoặc mặc định, các thành viên có thể được sửa đổi thành công khai, riêng tư, bảo vệ và mặc định.
sharhp

2
“Bởi vì nó chẳng có ý nghĩa gì” - đó là một câu nói khá táo bạo. Nó không được định nghĩa trong Java, nhưng những thứ tương tự vẫn tồn tại; ví dụ opentrong Kotlin cho phép phân lớp bên ngoài gói hiện tại (người ta có thể tưởng tượng protectedtrong Java ngăn chặn điều đó, với mặc định ngược lại).
Raphael

41

Như bạn đã biết, mặc định dành cho truy cập mức gói và được bảo vệ dành cho mức gói cộng với các lớp không phải gói nhưng mở rộng lớp này (Điểm cần lưu ý ở đây là bạn chỉ có thể mở rộng lớp nếu nó hiển thị!). Hãy đặt nó theo cách này:

  • lớp cấp cao nhất được bảo vệ sẽ được hiển thị cho các lớp trong gói của nó.
  • bây giờ làm cho nó hiển thị bên ngoài gói (các lớp con) là một chút khó hiểu và phức tạp. Những lớp nào nên được phép kế thừa lớp được bảo vệ của chúng ta?
  • Nếu tất cả các lớp được phép phân lớp thì nó sẽ tương tự như bộ chỉ định truy cập công khai.
  • Nếu không có thì nó tương tự như mặc định.

Vì không có cách nào để hạn chế lớp này chỉ được phân lớp bởi một vài lớp (chúng tôi không thể hạn chế lớp được kế thừa bởi chỉ một vài lớp trong số tất cả các lớp có sẵn trong một gói / bên ngoài một gói), nên không sử dụng các chỉ định truy cập được bảo vệ cho các lớp cấp cao nhất. Do đó nó không được phép.


3
"Bây giờ việc tạo một lớp được bảo vệ có thể nhìn thấy bên ngoài gói (các lớp con) là một chút khó hiểu và phức tạp. Những lớp nào nên được phép kế thừa lớp được bảo vệ của chúng ta? Và nếu tất cả các lớp được phép trở thành lớp con thì nó sẽ tương tự như bộ định nghĩa truy cập công khai." thực sự giúp tôi hiểu được vấn đề là tại sao lớp bảo vệ không có ý nghĩa :)
user1338998


3

@Nikita Rybak câu trả lời có điểm tốt nhưng thiếu chi tiết, tôi không thể chỉ đơn giản là có được ý tưởng mà không tự mình suy nghĩ sâu sắc, sau đây là những gì tôi nghĩ và bây giờ tôi nên hoàn toàn hiểu lý do.

Bốn công cụ sửa đổi quyền truy cập, giả sử cấp 1 là công khai và cấp 4 là riêng tư (dựa trên bảng này theo trình tự). Điều đầu tiên chúng ta nên biết là tại sao lớp không thể được định nghĩa là private ở cấp cao nhất.

Vậy nếu "private class foo" (Một thành viên riêng được định nghĩa, tức là bản thân lớp là một thành viên) cho phép, thì bên ngoài (chứa thành viên) là gì? Phạm vi tệp? Không, tệp bên ngoài là vô nghĩa vì thậm chí nhiều lớp trong tệp đơn sẽ được biên dịch thành tệp lớp riêng biệt. Vì vậy, bên ngoài là gói . Nhưng công cụ sửa đổi quyền truy cập mặc định cấp 3 đã có nghĩa là "gói-riêng tư ". Vì vậy, công cụ sửa đổi quyền truy cập riêng tư cấp 4 sẽ không được sử dụng / cho phép.

Nhưng lớp riêng lồng nhau được phép vì bên ngoài trực tiếp là lớp, không phải gói, ví dụ :

class PrivateNestedMain {
    private static class Inner {
        public static void main(String[] args) {
            System.out.println("Hello from Inner!");
        }
    }
}

Bây giờ điều gì sẽ xảy ra nếu "lớp bảo vệ foo" cho phép? Đặc điểm chính được bảo vệ là lớp con, vì vậy (gói) bên ngoài NÊN (do phạm vi tối đa, nhưng vẫn là tùy chọn) cung cấp kiểu của lớp con , tức là gói con, hoặc package A extends package Bnhưng chúng ta không biết điều đó. Vì vậy, protected không thể sử dụng hết tiềm năng (phạm vi chính là toàn lớp con) ở cấp cao nhất mà bên ngoài là gói (nghĩa là không có gói phụ như vậy), nhưng được bảo vệ có thể sử dụng đầy đủ tiềm năng trong lớp lồng nhau mà bên ngoài là lớp ( tức là có thể là lớp con) :

class ProtectedNestedMain {
    protected static class Inner {
        public static void main(String[] args) {
            System.out.println("Hello from Inner!");
        }
    }
}

Lưu ý rằng phần trên đã nói "không thể sử dụng hết tiềm năng" do nó không thể tiếp cận toàn lớp con chỉ vì không có lớp con bên ngoài, điều đó có nghĩa là thực sự được bảo vệ có thể được cho phép , đó chỉ là vấn đề lựa chọn để tránh trùng lặp công việc của gói. -private nếu bên ngoài không phân lớp được , xem bên dưới.

Sự khó hiểu của tôi chủ yếu là do bảng nổi tiếng tại https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html :

nhập mô tả hình ảnh ở đây

Nếu cấp độ 1 (công khai) và cấp độ 3 (gói-riêng tư) được cho phép, thì làm sao mà ở giữa cấp độ 2 (được bảo vệ) lại không được phép?

hỗ trợ công khai lớp con nên dễ gây hiểu nhầm. Cách chính xác để đọc bảng này là

hỗ trợ công khai lớp con nếu bên ngoài có tính năng lớp con.

Điều gây hiểu lầm tương tự áp dụng cho package-private, package-private không hỗ trợ lớp con ( N trong ô) không có nghĩa là khái niệm lớp con áp dụng ở bên ngoài.

Điều đó có nghĩa là chúng ta nên bỏ qua cột Lớp con nếu tính năng lớp con không khả dụng ở bên ngoài:

nhập mô tả hình ảnh ở đây

Như chúng ta có thể thấy bây giờ, cả gói bảo vệ và gói riêng tư hiện đang ở cùng một cấp độ ( YYN ), không còn nhầm lẫn về lý do tại sao ở giữa cấp độ không được phép. Nhìn chung, Java chỉ chọn gói-riêng tư hơn được bảo vệ để tránh gây nhầm lẫn ( đây chỉ là vấn đề lựa chọn , nhưng đặc tính chính được bảo vệ là lớp con, vì vậy gói-riêng là ưu việt hơn) và kết quả là chỉ cho phép 2 công cụ sửa đổi truy cập ở cấp cao nhất:

Ở cấp cao nhất — công khai hoặc gói-riêng tư (không có công cụ sửa đổi rõ ràng).


3

Việc xác định trường được bảo vệ làm cho trường đó có thể truy cập bên trong gói cũng như bên ngoài gói chỉ thông qua kế thừa (Chỉ bên trong lớp con).

Vì vậy, nếu chúng ta được phép tạo một lớp được bảo vệ thì chúng ta có thể truy cập nó bên trong gói rất dễ dàng nhưng để truy cập lớp đó bên ngoài gói, trước tiên chúng ta cần mở rộng thực thể đó trong đó lớp này được định nghĩa là gói của nó.

Và vì một gói không thể được mở rộng (có thể được nhập vào), việc xác định một lớp được bảo vệ một lần nữa sẽ khiến nó trở thành gói riêng tư, tương tự như việc xác định nó là mặc định mà chúng ta có thể làm. Do đó, không có lợi ích gì khi xác định một lớp private, nó sẽ chỉ làm cho mọi thứ trở nên mơ hồ.

Để biết thêm thông tin, hãy đọc Tại sao một lớp Java bên ngoài không thể là riêng tư hoặc được bảo vệ


3
Vui lòng tiết lộ bất kỳ chi nhánh nào và không sử dụng trang web như một cách để quảng bá trang web của bạn thông qua đăng bài. Xem Làm thế nào để tôi viết một câu trả lời tốt? .

1

Được bảo vệ không tương tự như công khai. Protected có cả quyền truy cập cấp độ gói cộng với chỉ có thể được truy cập bên ngoài các gói bằng kế thừa..Nếu một lớp nói A bên ngoài một gói INHERITS một lớp từ gói khác (với phương thức được bảo vệ bằng cách sử dụng INHERITANCE) thì nó có thể truy cập các phương thức của lớp B này. có các phương thức được bảo vệ nhưng các lớp con bắt nguồn từ lớp này, tức là, A không thể truy cập các phương thức được bảo vệ .. điều ngược lại xảy ra với công khai ..

Thí dụ:

package 2;
class B
{
protected void method1()
{
}
}
package 1;
import 2.B;
class A extends B
{
//can access protected method
}
class C extends A
{
//can't access the protected method
}

0

hành vi “bảo vệ” = hành vi “mặc định” + “sử dụng nó trong bất kỳ lớp con nào trong bất kỳ gói nào”.

Dù sao chúng ta cũng có công cụ sửa đổi truy cập mặc định cho lớp, lợi thế duy nhất chúng ta có thể nhận được từ công cụ sửa đổi truy cập được bảo vệ là: - bằng cách sử dụng nó trong bất kỳ gói nào thông qua phân lớp. Nhưng đối với lớp con, khả năng hiển thị của lớp cha mẹ "được bảo vệ" sẽ là riêng tư. Vì vậy, nó không thể được truy cập. Về cơ bản, nếu bạn có một lớp cấp cao nhất được bảo vệ, thì không một lớp bên ngoài nào có thể có được quyền truy cập bằng cách phân lớp nó. Vì vậy, bảo vệ cho một lớp cấp cao nhất là vô nghĩa.


0

Được bảo vệ : CHỈ CÓ THỂ ở cấp độ gói *.

lớp được định nghĩabảo vệ ---> nó không thể được mở rộng từ bên ngoài gói (không hiển thị).

Và nếu nó không thể được mở rộng thì việc giữ nó như được bảo vệ là vô nghĩa , vì khi đó nó sẽ trở thành quyền truy cập mặc định được phép.

Áp dụng tương tự cho các lớp được xác định riêng .

Lưu ý: Các lớp lồng nhau hoặc bên trong có thể được định nghĩa là bảo vệ hoặc riêng tư .

* : Khám phá từ khóa được bảo vệ , cho câu trả lời này, tôi đã làm cho nó ngắn gọn.


0

Câu trả lời từ @ Akash5288 không có ý nghĩa gì đối với tôi:

Nếu tất cả các lớp được phép phân lớp thì nó sẽ tương tự như bộ chỉ định truy cập công khai.

Vì không có cách nào để hạn chế lớp này chỉ được phân lớp bởi một vài lớp (chúng tôi không thể hạn chế lớp được kế thừa bởi chỉ một vài lớp trong số tất cả các lớp có sẵn trong một gói / bên ngoài một gói), nên không sử dụng các chỉ định truy cập được bảo vệ cho các lớp cấp cao nhất. Do đó nó không được phép.

Sau đó, bạn có thể áp dụng logic tương tự cho các phương thức và biến được bảo vệ, sau đó chúng cũng "tương tự như công khai". Tất cả các lớp bên ngoài một gói có thể mở rộng lớp công khai của chúng ta và sử dụng các phương thức được bảo vệ của nó. Tại sao hạn chế các phương thức và biến đối với các lớp mở rộng là ok, nhưng hạn chế toàn bộ lớp thì không ổn? "Tương tự với công khai" không phải là "giống như công khai". Giải thích của tôi là hoàn toàn ổn nếu cho phép một lớp được bảo vệ, cũng như cho phép các phương thức được bảo vệ.

Câu trả lời "bạn không thể mở rộng một lớp mà bạn không thể truy cập / xem" hợp lý hơn.


0

Điều có ý nghĩa đối với câu hỏi này là JVM được viết bằng C (Sun JVM) và C ++ (oracle JVM), vì vậy trong quá trình biên dịch, chúng tôi sẽ tạo các tệp .class từ tệp java của chúng tôi và nếu chúng tôi khai báo một lớp với từ khóa Protected thì nó sẽ không được truy cập bởi JVM.

Câu trả lời tại sao lớp được bảo vệ sẽ không được truy cập bởi JVM là vì các trường được bảo vệ có thể truy cập trong cùng một gói hoặc đối với gói khác chỉ thông qua kế thừa và JVM không được viết theo cách để nó sẽ kế thừa lớp đó. Hy vọng điều này thỏa mãn câu hỏi này :)

Tương tự, một lớp cấp cao nhất không thể là riêng tư. Giải thích như sau:

Vì vậy, điều gì sẽ xảy ra nếu chúng ta định nghĩa một lớp private, lớp đó sẽ chỉ có thể truy cập được trong thực thể mà nó được định nghĩa mà trong trường hợp của chúng ta là gói của nó?

Vì vậy, việc xác định quyền truy cập private vào lớp sẽ làm cho nó có thể truy cập bên trong cùng một gói mà từ khóa mặc định đã làm cho chúng ta, Do đó, không có lợi ích gì khi xác định một lớp private nó sẽ chỉ làm cho mọi thứ trở nên mơ hồ.


0

được bảo vệ có nghĩa là thành viên có thể được truy cập bởi bất kỳ lớp nào trong cùng một gói và bởi các lớp con ngay cả khi chúng nằm trong các gói khác.

Thí dụ:

package a;
class parent{
 protected void p();
}
package b;
import a.p;
class child extends parent{
  //you can access method which is protected in the parent in the child 
}
class another extends child {
 //here you can not access the protected method 
}

0

nếu một lớp bên ngoài được khai báo bởi protected, tôi nghĩ bạn muốn lớp chỉ có thể được truy cập từ cùng một gói và lớp con của nó nhưng các gói khác nhau. Tuy nhiên, không thể tạo các lớp con cho một lớp được bảo vệ, bởi vì khi bạn viết "lớp Chó mở rộng Động vật", vì "Động vật" được bảo vệ chỉ có thể được truy cập bởi lớp con của nó, rõ ràng, "Chó" không phải là lớp con "Động vật" .

Vì vậy, lớp ngoài được bảo vệ giống với lớp ngoài (mặc định)!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.