Tại sao Java không sử dụng đóng gói với một số lớp?


25

Câu hỏi của tôi liên quan đến System.inSystem.outcác lớp học (có thể có những câu hỏi khác giống như trong thư viện Standard). Tại sao vậy? Đó không phải là một thực hành xấu trong OOP? Không nên sử dụng nó như: System.getIn()System.getOut()? Tôi đã luôn có câu hỏi này và tôi hy vọng tôi có thể tìm thấy một câu trả lời tốt ở đây.

Câu trả lời:


36

Định nghĩa cho inoutcác trường trong Systemlớp là:

public final static PrintStream out;
public final static InputStream in;

Đây là các hằng số. Chúng cũng là đối tượng, nhưng chúng là hằng số. Nó rất giống với lớp Toán:

public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;

Hoặc trong lớp Boolean:

public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);

Hoặc trong lớp Màu:

public final static Color white     = new Color(255, 255, 255);
public final static Color black     = new Color(0, 0, 0);
public final static Color red       = new Color(255, 0, 0);

Khi truy cập vào hằng số công cộng không thay đổi, sẽ không có lợi thế đáng kể để đóng gói nó - dựa trên khái niệm hoặc hiệu suất. Nó đây rồi. Nó sẽ không thay đổi.

Không có sự khác biệt thực sự giữa Color.whiteSystem.out.


Chà, tôi đã không nhìn thấy nó theo cách đó, chúng là những vật thể không đổi. Đó là một lời giải thích khá tốt.
Clawdidr

1
@Clawdidr trong Java ngày nay, người ta có thể cân nhắc sử dụng enumđể giữ chúng ... mặc dù enumlà mới với Java 1.5 (không phải là một tùy chọn trong 1.0 ngày).

Vì tò mò (bản thân không phải là nhà phát triển Java): có sự khác biệt giữa final staticstatic finalkhông? Nếu vậy, nó là cái gì?
Marjan Venema

1
@MarjanVenema không có sự khác biệt, chỉ là thứ tự ưu tiên của các sửa đổi. kiểm tra sửa đổi kiểu dáng kiểm tra cho thấy thứ tự ưu tiên. Rõ ràng, bất cứ ai đã viết hai tệp nguồn đó trong phiên bản jdk tôi đều không đồng ý với đơn đặt hàng. Nó chỉ đơn thuần là quy ước.

:) và cảm ơn Michael, vì đã dành thời gian trả lời và cho liên kết.
Marjan Venema

5

Lý do thực sự là đây là một vấn đề di sản. Các System.in,out,errhằng số là một phần của Java 1.0 ... và có lẽ còn nhiều hơn nữa. Vào thời điểm rõ ràng là thiết kế có vấn đề, đã quá muộn để khắc phục nó. Điều tốt nhất họ có thể làm là thêm các System.setIn,setOut,setErrphương thức trong Java 1.1 và sau đó xử lý các vấn đề đặc tả ngôn ngữ 1 .

Điều này tương tự như vấn đề tại sao có một System.arraycopyphương thức tĩnh có tên vi phạm các quy ước đặt tên Java.


Về việc đây có phải là "thiết kế xấu" hay không, tôi nghĩ là vậy. Có những tình huống xử lý không OO hiện tại là một vấn đề nghiêm trọng. (Hãy suy nghĩ ... làm thế nào bạn có thể chạy một chương trình Java bên khác khi họ "tiêu chuẩn IO" yêu cầu dòng xung đột. Nghĩ ... đơn vị kiểm tra mã mà đòi hỏi thay đổi dòng.)

Tuy nhiên, tôi cũng có thể liên quan đến lập luận rằng cách làm việc hiện tại thuận tiện hơn trong rất nhiều trường hợp.


1 - Thật thú vị khi lưu ý rằng các System.in,out,errbiến được đề cập đặc biệt trong JLS là có "ngữ nghĩa đặc biệt". JLS nói rằng nếu bạn thay đổi giá trị của một finaltrường, hành vi không được xác định ... ngoại trừ trong trường hợp của các trường này .


2

Tôi tin rằng đối tượng bên ngoài là bất biến, điều này làm cho nó an toàn bằng cách nào đó (điều này gây tranh cãi) vì được giữ trong trường tĩnh cuối cùng công khai.

Nhiều lớp trong JDK không tôn trọng các nguyên tắc thiết kế hướng đối tượng tốt nhất. Một lý do cho điều này là thực tế là chúng đã được viết cách đây gần 20 năm, khi Định hướng đối tượng chỉ mới nổi lên như một mô hình chính thống và nhiều lập trình viên đơn giản là không quen thuộc với chúng như bây giờ. Một ví dụ rất hay về thiết kế API xấu là API Ngày & Giờ, họ đã mất 19 năm để thay đổi ...


3
Tôi sẽ làm cho tuyên bố mạnh mẽ hơn nữa, một biến cuối cùng công khai (tĩnh hoặc không) chính xác là "An toàn" như một getter và tôi cảm nhận được tính bất biến đối với cặp setter / getter. Setters luôn luôn là một ý tưởng tồi (Bất biến là tốt - và nếu nó không thể thay đổi được phương pháp "Đặt" thì có lẽ nó cũng xứng đáng với một logic kinh doanh nhỏ), Nếu bạn cần một getter, bạn cũng có thể công khai nó cuối cùng, nhưng không làm gì là tốt hơn - đừng yêu cầu một lớp cho dữ liệu của nó, hãy yêu cầu một lớp làm điều gì đó với dữ liệu của nó.
Bill K

@BillK: Vâng, còn được gọi là Luật Demeter (mặc dù đó không phải là luật, thay vào đó là hướng dẫn).
sleske

2

Câu trả lời này là tuyệt vời và đúng.

Tôi muốn thêm rằng trong một số trường hợp, sự thỏa hiệp được thực hiện vì mục đích sử dụng.

Các đối tượng kiểu String có thể được khởi tạo mà không có sự kiện mới, khi String không phải là nguyên thủy:

String s = "Hello";

Chuỗi không phải là nguyên thủy, nên được khởi tạo như thế này:

String s = new String("Hello");          // this also works 

Nhưng trình biên dịch cho phép tùy chọn OO ngắn hơn, ít hơn, bởi vì String là lớp được sử dụng rộng rãi nhất trong API.

Ngoài ra các mảng có thể được khởi tạo theo cách không OO:

int i[] = {1,2,3};

Thật kỳ lạ, một đối tượng là một thể hiện của một lớp hoặc một mảng . Mảng ý nghĩa là một loại lớp hoàn toàn riêng biệt.

Mảng có một lengthlĩnh vực công cộng không phải là một hằng số. Ngoài ra không có tài liệu về mảng lớp là một ví dụ. (không nhầm lẫn với lớp Arrays hoặc java.reflect.Array).

int a = myArray.length;    // not length()

6
Các bạn là những thứ khác nhau - new String("Hello")sẽ luôn tạo một đối tượng String mới. Trong khi String s = "Hello";sẽ sử dụng các đối tượng thực tập. So sánh: "Hello" == "Hello"có thể đúng, trong khi new String("Hello") == new String("Hello")luôn luôn sai. Có phép thuật tối ưu hóa thời gian biên dịch xảy ra trong lần đầu tiên không thể thực hiện được new String("Hello"). Xem en.wikipedia.org/wiki/String_i

@MichaelT Tôi đã thêm một số wierdiness thêm vào mảng, chỉ vì sự hoàn chỉnh.
Tulains Córdova

2
@Tarik Tôi đã phản đối "Chuỗi không phải là nguyên thủy, nên được đặt tên như thế này: String s = new String("Hello");" không chính xác. Tùy chọn ngắn hơn ( String s = "Hello";) là chính xác hơn vì thực tập chuỗi.

2
Với String, không có tùy chọn "chính xác hơn". Cả hai đều đúng. Mặc dù, như MichaelT nói, cái ngắn hơn được ưa thích vì thực tập String.
Andres F.

1
@AresresF. Tôi đã thay đổi "ít đúng" hơn cho "ít OO".
Tulains Córdova
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.