2011-06-24 56 views
49

Tôi đang học Java gần đây và tôi đã xem khái niệm về các lớp học package-private, đây là mặc định nếu chúng tôi không chỉ định bất kỳ điều gì. Nhưng sau đó tôi nhận ra:Ưu điểm và nhược điểm của các gói riêng tư trong gói Java?

  1. Tôi hiếm khi thấy việc sử dụng lớp gói riêng tư. Có lý do nào cho điều này, ví dụ, nó có những hạn chế nghiêm trọng, nó là thừa, hoặc đơn giản là tôi không đọc đủ? Có đối số mạnh mẽ cho/chống lại việc sử dụng nó?

  2. Nếu nó thực sự không hữu ích trong hầu hết các trường hợp, tại sao nó sẽ là mặc định?

  3. Trong trường hợp nào chúng ta nên sử dụng gói riêng tư trong thế giới thực? Tức là, khi nào nó sẽ trở thành không thể thay thế?

Nói cách khác, ưu và nhược điểm chính của công cụ sửa đổi gói riêng tư mặc định là gì?

Trả lời

41

Câu trả lời ngắn gọn - đó là hình thức riêng tư rộng hơn một chút.

Tôi giả sử rằng bạn đã quen thuộc với sự khác biệt giữa publicprivate và lý do tại sao thực tiễn tốt là tạo phương pháp và biến private nếu chúng chỉ được sử dụng nội bộ cho lớp được đề cập.

Vâng, nếu bạn đang nghĩ đến việc tạo phần mềm theo cách mô-đun, bạn có thể nghĩ về giao diện công khai với mô-đun của mình. Trong bối cảnh này, nó có ý nghĩa hoàn hảo để tạo ra các phương thức public nếu chúng được gọi bởi người tiêu dùng; private nếu họ đang ở trong một lớp học; và package private nếu chúng được sử dụng để gọi giữa các lớp trong mô-đun này, tức là đó là chi tiết triển khai của mô-đun của bạn (được người gọi công khai nhìn thấy) nhưng mở rộng nhiều lớp.

Điều này hiếm khi được sử dụng trong thực tế, bởi vì hệ thống gói hóa ra không hữu ích cho loại điều này. Bạn sẽ phải đổ tất cả các lớp cho một mô-đun nhất định vào chính xác cùng một gói, mà đối với bất kỳ thứ gì không tầm thường sẽ có một chút khó sử dụng. Vì vậy, ý tưởng là tuyệt vời - làm cho một phương pháp có thể truy cập chỉ với một số ít các lớp "lân cận", rộng hơn một chút private - nhưng các hạn chế về cách bạn xác định tập hợp các lớp đó có nghĩa là nó hiếm khi được sử dụng/hữu ích.

+1

Tôi có thể thấy lý do tại sao một người nào đó có thể đã nói rằng - trình sửa đổi 'protected' giống như' gói riêng tư' ngoại trừ các lớp con cũng được mời tham gia vào nhóm. Nhưng nó sẽ là sai lầm để tạo ra một mối quan hệ lớp con (chỉ dành cho mục đích truy cập) nếu một người không tồn tại một cách tự nhiên. Nó thường sẽ không có ý nghĩa gì cho ví dụ lớp 'EmailSender' là lớp con của lớp' DomainObjectFilter' hoặc ngược lại. Trong tình huống này, phương pháp này thường được tạo thành 'công khai' (có lẽ với một bình luận nói rằng nó không * khái niệm * công khai ...). –

+0

"đổ tất cả các lớp cho một mô-đun nhất định vào chính xác cùng một gói - khó sử dụng" - Đúng, nhưng tôi đã sử dụng phương pháp này ngay cả trong các trường hợp không tầm thường, như 20-30 lớp trong gói. Bất cứ điều gì lớn hơn, tất nhiên, là cần tái cấu trúc. –

+0

Bạn không thể tổ chức các tệp nguồn của bạn thành một hệ thống phân cấp thư mục, và sau đó trong quá trình xây dựng, đổ tất cả chúng vào cùng một thư mục/gói trước khi biên dịch? Điều đó sẽ cung cấp cho bạn cơ cấu tổ chức và lợi ích của quyền truy cập gói riêng tư, đúng không? – jrahhali

1

1 - Phụ thuộc vào kiến ​​trúc -Generally nếu bạn đang viết mã chỉ cho chính mình và trên các dự án nhỏ, bạn có thể sẽ không sử dụng nó. Trong các dự án lớn hơn nó có thể hữu ích để đảm bảo rằng bạn có thể kiểm soát nơi và làm thế nào một số phương pháp được gọi là.

2 - Mặc định (I.e. không công khai/được bảo vệ/riêng tư) không giống như tư nhân - trạng thái thứ tư của nó. Xem Java Access Control

3 - Nó có thể làm cho cuộc sống dễ dàng hơn khi bạn đang viết thư viện mà bạn không muốn bên thứ ba dựa vào cách bạn đang triển khai mã cơ bản.

+0

@BZ Không phải là gói mặc định riêng tư? –

+2

http://download.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html –

+1

@BZ Mà nói: Nếu một lớp không có công cụ sửa đổi (mặc định, còn được gọi là gói riêng tư). Cảm ơn câu trả lời, thuật ngữ là tầm thường :) –

2

Về câu hỏi "tại sao nó sẽ là mặc định", trong ngữ cảnh này, thuật ngữ "mặc định" chỉ có nghĩa là không có vòng loại khác. Tôi đoán họ có thể đã phát minh ra một từ khóa khác ("gói" đã được sử dụng), nhưng họ đã không.

Trong thế giới thực, tôi sử dụng quyền truy cập mặc định cho các lớp tiện ích và lớp trừu tượng mà tôi không muốn mọi người gọi hoặc sử dụng từ các gói khác. Giả sử bạn có một giao diện và hai triển khai cụ thể mở rộng từ một số lớp trừu tượng. Bạn khai báo hai lớp cụ thể của bạn là cuối cùng vì bạn không nhất thiết muốn mọi người phân lớp chúng (xem Java hiệu quả). Bạn cũng không muốn mọi người đi xung quanh với lớp trừu tượng của bạn vì lý do tương tự. Nếu bạn sử dụng truy cập mặc định cho lớp trừu tượng, thì mọi người chỉ nhìn thấy nó nếu họ đặt lớp của họ trong gói của bạn. Nó không phải là bằng chứng đạn, nhưng tôi nghĩ rằng đó là một sử dụng hợp lý/minh hoạ của truy cập mặc định. Điều đó nói rằng, thực tế là nó không ngăn chặn các chi tiết từ rò rỉ như tư nhân, nghĩa là không đảm bảo bất cứ điều gì, có nghĩa rằng nó không phải là một công ước đặc biệt hữu ích.

Một lý do khác khiến bạn không thấy nó được sử dụng thường xuyên hơn là mọi người có xu hướng loại trừ các lớp có quyền truy cập mặc định từ javadocs của họ.

+0

Anh ấy không hiểu nhầm cụm từ "mặc định", anh ta hỏi tại sao đó là cấp truy cập mặc định. Một lý do cho một mặc định là một cái gì đó thường được sử dụng nhất. Có nhiều lý do khác, và anh ấy yêu cầu họ. –

+1

Tôi không chắc chắn bạn đã đúng, nhưng tôi vui mừng cập nhật câu trả lời cho sự rõ ràng. – jtoberon

-1

"Gói riêng" được sử dụng khi bạn có nhiều gói và điều này có nghĩa là các lớp khác trong cùng một gói có thể truy cập thành viên lớp hoặc lớp đó là "công khai", các lớp trong các gói khác không thể truy cập. chúng. "

9

Một điều tốt đẹp về gói riêng tư là bạn có thể sử dụng nó để cung cấp quyền truy cập vào các phương pháp bạn sẽ xem xét riêng tư đối với các lớp kiểm tra đơn vị. Nhược điểm của khóa học là các lớp khác trong gói có thể gọi nó khi họ thực sự không nên.

0

Xin lưu ý rằng khi bạn đang nói về lớp bạn chỉ có hai lựa chọn:

  1. lớp nào
  2. gói lớp tin

Khái niệm "lớp riêng" là vô nghĩa. (Tại sao tạo một lớp không được sử dụng ở bất kỳ đâu ?!)

Vì vậy, nếu bạn có một lớp cho các hoạt động trung gian không cần phải tiếp xúc với người dùng API, bạn phải khai báo là "gói riêng"

Ngoài ra khi bạn xác định nhiều lớp trong cùng một tệp nguồn, chỉ một lớp được phép công khai (tên của nó khớp với tên tệp .java). Nếu bất kỳ lớp nào khác được định nghĩa trong cùng một tệp, nó phải là "gói riêng tư".

2

Ngoài việc đóng gói, một trong những ưu điểm chính của việc sử dụng các lớp riêng tư là chúng không xuất hiện trong javadoc của dự án của bạn. Vì vậy, nếu bạn sử dụng một số lớp trợ giúp không sử dụng khác nhưng để giúp các lớp công khai của bạn làm điều gì đó mà khách hàng cần, thì có nghĩa là làm cho chúng gói riêng tư khi bạn muốn giữ mọi thứ càng đơn giản càng tốt cho người dùng thư viện.

Ví dụ: bạn có thể xem thư viện mà tôi đã phát triển. Các javadoc chỉ chứa 5 giao diện và 12 lớp mặc dù các source code có nhiều hơn nữa. Nhưng những gì được ẩn chủ yếu là các lớp bên trong cung cấp không có giá trị gia tăng cho một khách hàng (thường là tất cả các lớp cơ sở trừu tượng được ẩn).

Cũng có nhiều ví dụ trong JDK.

0

Mức truy cập gói riêng tư hạn chế hơn protected: các thuộc tính và phương pháp được bảo vệ vẫn có thể được truy cập bằng cách chỉ phân lớp con một lớp. Được bảo vệ thành viên (hoặc có thể) dành cho kế thừa trong khi các thành viên riêng tư của gói thì không.

Thành viên riêng tư gói thường được sử dụng để các lớp đa cấp bên trong một gói có thể truy cập các thuộc tính hoặc phương thức (tiện ích) cụ thể triển khai.

ví dụ tốt cho điều này là những nhà xây dựng gói-tin của String và mảng StringBuilder.value char:

/* 
* Package private constructor which shares value array for speed. 
* this constructor is always expected to be called with share==true. 
* a separate constructor is needed because we already have a public 
* String(char[]) constructor that makes a copy of the given char[]. 
*/ 
String(char[] value, boolean share) { 
    // assert share : "unshared not supported"; 
    this.value = value; 
} 

Vì vậy, lớp bên trong gói java.lang hiệu quả có thể tạo mới Strings nếu nội dung đã có mặt trong một char[] không xâm phạm an ninh. Bạn không thể làm điều này từ ứng dụng của bạn bởi vì nếu bạn có thể, bạn sẽ có quyền truy cập (tham chiếu) vào mảng char nội bộ của một String không thay đổi (phản ánh không được tính!).

Trong StringBuilder (hay đúng hơn là AbstractStringBuilder nơi thực hiện xuất phát từ) mảng char giữ giá trị hiện tại char[] value và một phương pháp accessor để char[] getValue() này cũng gói tin phương pháp hữu ích để hình String như contentEquals(StringBuffer sb)contentEquals(CharSequence cs) có thể sử dụng điều này cho hiệu quả và so sánh nhanh hơn mà không để lộ mảng char bên trong với "thế giới".

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