web-dev-qa-db-ja.com

なぜJava.lang.Objectは抽象的ではないのですか?

可能性のある複製:
Java:抽象として宣言されていないObjectクラスの根拠

なぜ抽象ではなくJavaの基本クラスであるObjectクラスなのですか?

私は本当に長い間この質問をしてきましたが、ここでは純粋に好奇心から質問されています、それがすべてです。それは抽象的ではないので、私のコードや誰かのコードには何も壊れていませんが、なぜ彼らはそれを具体的にしたのだろうと思っていましたか?

なぜ誰もがこのオブジェクトクラスの「インスタンス」(およびその存在としての参照ではない)が必要なのでしょうか? 1つのケースは、ロックにObjectのインスタンスを使用する貧弱な同期コードです(少なくとも一度はこの方法で使用しました。

Objectクラスの「インスタンス」の実用的な使用はありますか?そして、そのインスタンス化はOOPにどのように適合しますか?彼らがそれを抽象とマークした場合はどうなりますか(もちろん、そのメソッドに実装を提供した後)?

128
Elister

_Java.lang.Object_の設計者が私たちに言わずに、私たちは意見に基づいて答えを出さなければなりません。解決できるいくつかの質問があります。

Objectのメソッドのいずれかが抽象的であることの恩恵を受けますか?

いくつかの方法がこれから恩恵を受けると主張することができます。 hashCode()equals()を例にとると、これら2つが両方とも抽象化されていれば、これら2つの複雑さについてのフラストレーションははるかに少ないでしょう。そのため、開発者は実装方法を把握する必要があり、一貫性があることがより明確になります(効果的なJavaを参照)。ただし、hashCode()equals()、およびclone()は、個別のオプトイン抽象化(つまり、インターフェース)に属しているという意見が多くあります。他のメソッドwait()notify()finalize()などは十分に複雑であるか、ネイティブであるため、既に実装されていることが最善です。抽象化の恩恵を受けません。

だから答えはノーだと思います、Objectのメソッドはどれも抽象的であることの恩恵を受けません。

Objectクラスを抽象としてマークすることは有益ですか?

すべてのメソッドが実装されていると仮定すると、Object abstractをマークする唯一の効果は、そのメソッドを構築できないことです(つまり、new Object()はコンパイルエラーです)。これには利点がありますか?私は、「オブジェクト」という用語自体が抽象的である(完全に「オブジェクト」と説明できるものを見つけることができますか?)ので、オブジェクト指向のパラダイムに適合すると考えています。ただし、purist側です。空のサブクラスであっても、開発者に任意の具体的なサブクラスの名前を選択させることは、意図をよりよく表現するコードになると主張できます。私は、パラダイムに関して完全に正しいであると思います、オブジェクトはabstractとマークされるべきですが、本当の利点はありません。デザインの好みの問題です(プラグマティズムと純度)。

同期にプレーンオブジェクトを使用する習慣は、それが具体的になるのに十分な理由ですか?

他の回答の多くは、synchronized()操作で使用するプレーンオブジェクトの構築について説明しています。これは一般的で受け入れられた慣習であったかもしれませんが、デザイナーが望んでいた場合、Objectが抽象的であることを防ぐのに十分な理由ではないと思います。他の回答では、特定のオブジェクトで同期したいときにObjectの単一の空のサブクラスを宣言する方法について言及していますが、これは立ち上がりません-空のサブクラスがSDKで提供されている可能性があります(_Java.lang.Lock_または何でも)、これは同期したいときにいつでも構築できます。これを行うと、より強力な意図のステートメントを作成するという追加の利点があります。

Objectを抽象化することで悪影響を受ける可能性のある他の要因はありますか?

純粋な設計の観点とは別に、選択に影響を与えた可能性のあるいくつかの領域があります。残念なことに、私はそれらについて十分に知りません。ただし、これらのいずれかが決定に影響を与えたとしても、私は驚かないでしょう。

  • 性能
  • セキュリティ
  • JVMの実装の単純さ

他の理由がありますか?

反射に関連している可能性があると言われています。ただし、オブジェクトの設計後にリフレクションが導入されました。したがって、反射に影響するかどうかは重要ではありません-それは理由ではありません。ジェネリックについても同じです。

Java.lang.Objectは人間によって設計されたという忘れられないポイントもあります。彼らは間違いを犯したかもしれず、質問を考慮しなかったかもしれません。欠陥のない言語は存在せず、これはの1つかもしれませんが、もしそうなら、それはほとんど大きなものではありません。そして、私は野心に欠けることなく、このような広く使用されている技術、特に15年続き、まだ強くなっている技術の重要な部分の設計に関与することはほとんどないと思います。批判と見なされるべきではありません。

それを言って、私はそれを抽象にしただろう;-p

概要
基本的には、私が見る限り、「Java.lang.Objectが具体的な理由」という両方の質問に対する答えです。または(もしそうなら)「Java.lang.Object abstractはなぜですか?」・・・「どうして?」.

65
Grundlefleck

Java.lang.Objectのプレーンインスタンスは、通常、ロック/同期のシナリオで使用され、それが受け入れられています。

また、それが抽象的である理由は何でしょうか?インスタンスとしてそれ自体では完全に機能していないためですか?いくつかの抽象的なメンバーで本当にできますか?そうは思わないでください。したがって、そもそも抽象化するという議論は存在しません。そうではありません。

抽象クラスAnimalがある古典的な動物の階層を考えてください。Animalクラスを抽象化する理由は、Animalのインスタンスが事実上「無効」であるためです。より良いWord-animal(すべてのメソッドが基本実装を提供していても)。 Objectを使用すると、そうではありません。そもそもそれを抽象化するという圧倒的なケースはありません。

24

私が読んだすべてのものから、Objectは具体的である必要はないようです、そして実際にはshouldは抽象的でした。

具体的である必要がないだけでなく、いくつかの後で 詳細な読みObjectnot抽象的であることは、基本的な継承モデルと矛盾しています-サブクラスはadd機能のみを許可するため、具象クラスの抽象サブクラスを許可するべきではありません。
明らかにObjectの抽象サブクラスがあるJavaの場合はそうではありません。

Objectのインスタンスが役立ついくつかのケースを考えることができます。

  • あなたや他のコメント者が述べているように、ロックと同期。おそらくコードのにおいですが、Objectインスタンスが常にこのように使用されるのを見てきました。
  • Null Objects のように、equalsはインスタンス自体を除いて常にfalseを返すため。
  • テストコード、特にコレクションクラスをテストする場合。コレクションまたは配列をnullsではなくダミーオブジェクトで埋めるのが最も簡単な場合があります。
  • 匿名クラスのベースインスタンスとして。例えば:
    Object o = new Object() {...code here...}
11
Brett Daniel

おそらく抽象と宣言すべきだったと思いますが、いったん終了してリリースすると、大きな痛みを伴うことなく元に戻すのは非常に困難です-Java Language Spec 13.4.1を参照:

「抽象ではないクラスが抽象として宣言されるように変更された場合、そのクラスの新しいインスタンスを作成しようとする既存のバイナリは、リンク時にInstantiationErrorをスローするか、(リフレクションメソッドが使用される場合)実行時にInstantiationExceptionをスローします;したがって、このような変更は、広く分散したクラスには推奨されません。」

7
ishmeister

私は、ほとんどの人が完全に機能するクラスを作成し、そのメソッドのすべてを完全な方法で抽象的に実装することが良い考えだと思う理由を理解していません。
なぜそれを抽象化するのかを尋ねたいのですが?すべきでないことをしますか?必要な機能が不足していますか?これらの質問はどちらもいいえで答えることができます。それはそれ自体で完全に機能するクラスであり、抽象化すると、空のクラスを実装する人々につながります。

public class UseableObject extends AbstractObject{}

UseableObjectは抽象オブジェクトから継承し、驚くべきことに実装できます。機能を追加せず、存在する唯一の理由はオブジェクトによって公開されたメソッドへのアクセスを許可することです。
また、「貧弱な」同期での使用に同意する必要があります。プライベートオブジェクトを使用したアクセスの同期は、synchronize(this)を使用するよりも安全で、Java util Concurrent。のLockクラスよりも安全で使いやすいです。

5
josefx

時々、独自の状態を持たないプレーンなオブジェクトが必要です。そのようなオブジェクトは一見役に立たないように見えますが、それぞれに異なるidentityがあるため、依然として有用です。 Tnisは、ロックが最も重要ないくつかのシナリオで役立ちます。2つのスレッドを調整する必要があります。 Javaでは、ロックとして使用されるオブジェクトを使用してこれを行います。オブジェクトは、ロックになるために存在するだけで十分な状態を持っている必要はありません。

_class MyThread extends Thread {
   private Object lock;
   public MyThread(Object l) { lock = l; }

   public void run() { 

      doSomething();
      synchronized(lock) {
          doSomethingElse();
      } 
   }
}

Object lock = new Object();
new MyThread(lock).start();
new MyThread(lock).start();
_

この例では、ロックを使用して、2つのスレッドがdoSomethingElse()を同時に実行しないようにしました。

Objectが抽象的でロックが必要な場合、ロックをインスタンス化できるようにするために、メソッドやフィールドを追加せずにサブクラス化する必要があります。

それについて考えてみると、ここにあなたに対する二重の質問があります:オブジェクトが抽象的であると仮定して、抽象メソッドを定義しますか?答えはNoだと思います。そのような状況では、クラスを抽象として定義することにはあまり価値がありません。

5
Itay Maman

ここには実用性の簡単な質問があるようです。クラスを抽象化すると、何かを行う、つまりインスタンス化するプログラマーの能力が失われます。具象クラスではできない抽象クラスでできることは何もありません。 (まあ、その中に抽象関数を宣言することができますが、この場合、抽象関数を持つ必要はありません。)それを具体的にすることで、より柔軟にします。

もちろん、それを具体的にすることによって行われた積極的な害があれば、その「柔軟性」は欠点になります。しかし、Objectをインスタンス化可能にすることによって引き起こされる積極的な害は考えられません。 (「インスタンス化可能」という言葉は何ですか?)誰かが生のObjectインスタンスに対して行った使用が良いアイデアであるかどうかを議論することができます。しかし、未加工のObjectインスタンスについてこれまでに見たすべての使用が悪い考えであると確信できたとしても、そこには良い使用がないかもしれないことを証明しません。だから、それが何も傷つけず、それが助けになるかもしれない、それが実際に現時点で役立つだろう方法を考えることができなくても、なぜそれを禁止するのか?

2
Jay

これまでのところ、すべての答えは、Java 1.0でどのようなものであったかを忘れています。Java 1.0では、匿名クラスを作成できませんでした。何らかの目的(同期またはnullプレースホルダー)のオブジェクトが必要な場合は、その目的のクラスを宣言する必要があり、コード全体にこの目的のためにこれらの追加のクラスがあります。オブジェクトのインスタンス化。

もちろん、あなたがJavaを設計していたら、今日は誰もがすべきだと言うかもしれません:

 Object NULL_OBJECT = new Object(){};

しかし、それは1.0ではオプションではありませんでした。

1
Yishai

私はデザイナーが将来どのようにオブジェクトを使用するかを知らなかったので、ミューテックス、キーなどの必要のない場所に追加のクラスを作成するように強制することでプログラマーを制限したくなかったと思います。等.

1
Pool

また、配列でインスタンス化できることも意味します。 1.5日前では、これにより一般的なデータ構造を持つことができました。これは、一部のプラットフォームではまだ当てはまる可能性があります(J2MEを考えていますが、よくわかりません)

0
malaverdiere