web-dev-qa-db-ja.com

Javaが一部のクラスでカプセル化を利用しないのはなぜですか?

私の質問は、_System.in_および_System.out_クラスに関連しています(標準ライブラリにあるようなクラスが他にもある可能性があります)。何故ですか? OOPではそれは悪い習慣ではありませんか? System.getIn()およびSystem.getOut()のように使用しないでください。私はいつもこの質問をしてきたので、ここで良い答えを見つけられるといいのですが。

25
Clawdidr

inクラス内のoutおよびSystemフィールドの定義は次のとおりです。

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

これらは定数です。それらは偶然にもオブジェクトですが、定数です。これはMathクラスとほとんど同じです。

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

またはブールクラスで:

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

またはColorクラスで:

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);

変更されないパブリック定数にアクセスする場合、それをカプセル化することには大きな利点はありません-概念的またはパフォーマンスベース。それはそこにあります。変更されることはありません。

Color.whiteSystem.outには実際の違いはありません。

36
user40980

本当の理由は、これが古い問題であることです。 System.in,out,err定数はJava 1.0 ...の一部であり、おそらくかなり前に戻ってきました。設計に問題があることが明らかになったとき、それを修正するには遅すぎました。彼らができる最善のことは、Java 1.1にSystem.setIn,setOut,setErrメソッドを追加してから、言語仕様の問題に対処することでした。1

これは、名前がJava命名規則に違反する静的System.arraycopyメソッドがある理由の問題に似ています。


「悪いデザイン」なのか、そうでないのか。現在の非OO処理が深刻な問題である状況があります。 (考えてみてください。Java program inside別の1つを実行すると、「標準IO」ストリームの要件が競合する場合に実行できます。考えてください...変更を伴うユニットテストコードストリーム。)

ただし、多くの場合、現在の方法はより便利であるという主張にも関連しています。


1-System.in,out,err変数がJLSで「特別なセマンティクス」を持つと特別に言及されていることに注目するのは興味深いことです。 JLSによると、finalフィールドの値を変更した場合、動作は未定義です... theseフィールドの場合を除きます。

5
Stephen C

私は、出力オブジェクトは不変であると考えています。これにより、パブリックの最終的な静的フィールドに保持することは、ある程度安全になります(これは議論の余地があります)。

JDKのクラスの多くは、最良のオブジェクト指向設計原則を尊重していません。その理由の1つは、オブジェクト指向が主流のパラダイムとして浮上し始めたばかりで、多くのプログラマーが現在のようにそれらに慣れていない20年ほど前に書かれたという事実です。悪いAPI設計の非常に良い例は、日付と時刻のAPIで、変更に19年かかりました...

2
m3th0dman

この答え は素晴らしく真実です。

使いやすさのために妥協が行われた場合があることを付け加えておきます。

String型がプリミティブでない場合、String型のオブジェクトは新しいイベントなしでインスタンス化できます。

String s = "Hello";

文字列はプリミティブではないため、次のようにインスタンス化する必要があります。

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

ただし、StringはAPIで最も広く使用されているクラスであるため、コンパイラーはより短い、より少ないOOオプションを許可します。

また、配列はOO以外の方法で初期化することもできます。

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

奇妙なことに、オブジェクトはクラスまたは配列のインスタンスです。つまり、配列は完全に別のタイプのクラスです。

配列には定数ではないlengthパブリックフィールドがあります。また、インスタンスであるクラス配列に関するドキュメントもありません。 (ArraysクラスまたはJava.reflect.Arrayと混同しないでください)。

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