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


25

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

回答:


36

クラス内の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.whiteとはSystem.out


まあ、私はそれをそのように見ていない、彼らは定数オブジェクトです。それはかなり良い説明です。
クローディドル

1
今日のJavaの@Clawdidrでは、を使用してそれらを保持することを検討するかもしれませんenum ... enumJava 1.5で新しくなりました(1.0日間のオプションではありません)。

好奇心から(Java開発者自身ではない):との間に違いはfinal staticありstatic finalますか?もしそうなら、それは何ですか?
マルジャンヴェネマ

1
@MarjanVenema違いはなく、修飾子の優先順序だけです。 checkstyle修飾子チェックは、優先順序を示します。どうやら、私がjdkバージョンでこれらの2つのソースファイルを書いた人は誰でも順序に同意しなかったようです。その単なる慣習です。

:)マイケル、リンクに時間を割いてくれてありがとう。
マルジャンヴェネマ

5

本当の理由は、これがレガシーな問題だからです。System.in,out,err定数は、Java 1.0の一部...と、おそらく多く、さらにバックでした。設計に問題があることが明らかになった時点で、修正するには遅すぎました。彼らができる最善のSystem.setIn,setOut,setErr方法は、Java 1.1にメソッドを追加し、言語仕様の問題に対処することでした1

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


これが「悪いデザイン」かどうかについては、そうだと思います。現在のオブジェクト指向以外の処理が深刻な問題である場合があります。(たとえば、「標準IO」ストリーム要件が競合する場合に、あるJavaプログラム別のJavaプログラム内で実行する方法を考えてみてください。

しかし、多くの場合、現在のやり方がより便利であるという議論にも関係します。


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


2

outオブジェクトは不変であり、パブリックの最終的な静的フィールドに保持するために何らかの形で安全になります(これは議論の余地があります)。

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


3
ステートメントをさらに強化し、パブリック最終変数(静的または非静的)はゲッターとまったく同じように「安全」であり、セッター/ゲッターペアに対して不変性を認めます。セッターは常に悪い考えです(Immutableは良いです-そして、「設定」するメソッドを不変にできない場合は、おそらく小さなビジネスロジックに値するでしょう)、ゲッターが必要な場合は、パブリックにすることもできますfinal、しかしどちらもしない方が望ましい-クラスにデータを要求するのではなく、クラスにそのデータに対して何かをするように要求する。
ビルK

@BillK:はい、デメテル法則としても知られています(ただし、法ではなく、ガイドラインです)。
sleske

2

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

使いやすさのために妥協が行われた場合もあると付け加えました。

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

String s = "Hello";

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

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

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

また、配列はオブジェクト指向以外の方法で初期化できます。

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

奇妙なことに、オブジェクトはクラスのインスタンスまたは配列のいずれかです。意味配列は、完全に分離されたタイプのクラスです。

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

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

6
あなたは異なるものです- new String("Hello")常に新しいStringオブジェクトを作成します。while String s = "Hello";は、インターンされたオブジェクトを使用します。比較:"Hello" == "Hello"trueの場合がありますが、new String("Hello") == new String("Hello")常にfalseです。で不可能な最初のコンパイル時最適化マジックがありますnew String("Hello")en.wikipedia.org/wiki/String_interning

@MichaelT完全を期すために、配列に余分な奇妙さを追加しました。
Tulainsコルドバ

2
@Tarik私は「文字列は非原始なので、このようにインスタンス化する必要がある」ことに反対していましたが、String s = new String("Hello");これは間違っています。短いオプションは(String s = "Hello";)である以上ので、文字列のインターンの正しいです。

2
ではString、「より正確な」オプションはありません。両方とも正しいです。ただし、MichaelTが言うように、文字列インターンのために短いほうが好まれます。
アンドレス

1
@AndresF。「少ないOO」を「あまり正しくない」に変更しました。
Tulainsコルドバ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.