2012-01-21 7 views
11

は、instanceofが適切である主な例は以下のとおりです。Object.equals(Object)を実装instanceofの正しい決定はいつ使用していますか?私はいつもそれを理解してきたように

  1. 。したがって、私がListクラスを作成していて、何らかの理由でAbstractListを拡張しない場合は、最初にo instanceof Listをテストして要素を比較してequals(o)を実装します。
  2. ではなく、のセマンティクスが変更された特殊なケースの重要な(アルゴリズムによる)最適化ですが、パフォーマンスのみです。たとえば、Collections.binarySearchinstanceof RandomAccessテストを実行し、と非RandomAccessのリストに対してわずかに異なるバイナリ検索を使用します。

instanceofは、これらの2つのケースでコードの匂いを表しているとは思われません。しかし、instanceofを使用することが賢明な場合は他にもありますか?

答えて

6

レガシーコードまたはAPIが正当な使用である複合工場を書き込むことが、例えば可能 - instanceofの場合。 (それでもOOレイヤーを書きたいのですが、時にはそのような再設計が不可能になることがあります)。

特に、外部クラス階層に基づくファクトリが一般的なようです。

+0

Hmmmmm。念頭に置いた例私はこれまで使ってきたAPIでこの必要性に遭遇していません。 –

+0

@LouisWassermanたとえば、私たちは様々なFTPクラスが共通の基底クラスを拡張したり、インタフェースを実装したりしていないサードパーティのAPIを持っていたなど、OO以外の方法で記述されたものです。それらを「同じ」ものとして扱うために、私たちの迅速な回避策は、いくつかの簡単なインスタンスチェックを行いました。最終的にはレイヤーを上に置きます。世界には数多くの悪いAPIがあります。 –

+0

Ew。私はそれらの獣のいずれかに対処しなければならないことに感謝しなければならないと思います。 –

-1

あなたが言及したように、instanceofの「正しい」用途はかなり限定されています。私が知る限り、基本的に2つの主な用途を要約しています。

次のようにかかわらず、あなたは少しあなたの文を一般化することができますただし、次の必要なキャストの前に

  1. 型チェックを。
4

あなたの最初のケースは、私はinstanceof演算子を使用しますが、クラスが同じであるかどうかではないでしょう例である非常に特定のクラスのインスタンスに依存し、特殊なケースのシナリオの実装:

o != null && o.getClass() == this.getClass() 

これにより、A extends BBのインスタンスが等しく見なされることを避けることができます

その他のケース私はすぐに考えることができますが、私はかなり確信していますALID例では、例えば、パラメータとして、一般的なインタフェースを受けcanCreatecreate方法を持っている

  • 工場インスタンスご利用いただけます。各ファクトリはインターフェイスの特定の実装を処理できるため、instanceofが必要です。ファクトリ抽象クラス/インタフェースにのみインターフェイスを定義する
  • 複合実装(私の最初の例に示すように)コントロールの外側
+1

しかし、 'List'の場合、' B extends A'と 'C extends A'のインスタンスは等しいとみなされます。 –

+0

あなたの最初のポイントは時には非常に重要です。しかし、サブクラスのインスタンスを親クラスのインスタンスと等価にしたいアプリケーションがあります。その場合、 'instanceof'はクラスアイデンティティをチェックするよりも理にかなっています。また、 'instanceof'は最終的なクラスのためのあなたのクラスアイデンティティチェックと同等です。私は2つの方法をベンチマークしていませんが、 'instanceof'がその場合には少し速いと驚くことはありません。 –

+0

@LouisWassermanしかし、この場合、 'instanceof'は失敗します。' anA instanceof aB'は 'false'になります。 –

5

あなたの質問に答える1つの方法は、「固体Javaライブラリではいつinstanceofを使用するのですか?もし、適切に設計されたJavaライブラリの例がGuavaであるとすれば、instanceofのどこでそれを受け入れるかを決めることができます。

Guavaのソースコードjarを抽出してgrepしたら、 instanceofは122個のファイル間、439回言及されています

$ pwd 
/tmp/guava-13.0.1-sources 
$ grep -R 'instanceof' | wc -l 
439 
$ grep -Rl 'instanceof' | wc -l 
122 

そして、我々はいくつかのパターンが現れる見ることができ、これらの例いくつかを見て:平等を確認するには

  • これは最も一般的な使用法です。これは実装固有のものですが、拡張/実装するクラス/インタフェースに基づいて等価性を実際に測定したい場合は、instanceofを使用して、使用するオブジェクトを確実に確認してください。しかし、子クラスがequals()をオーバーライドし、親クラスと同じものを尊重しない場合、これは奇妙な問題を引き起こす可能性があります。例はどこにでもありますが、簡単なものはLists.equalsImpl()で、これはImmutableListで使用されています。短絡不要なオブジェクトの構築に

  • それはすでに希望のインスタンスの場合は、安全に使用または返却することができ、引数で渡された場合、たとえば、さらにそれを変換せずにチェックするためにinstanceofを使用することができます

    私たちが知っていれば、それは不変です。しかし、特に、静的なユーティリティクラスでは、など

  • これは全てのGuava内の場所で見ることができます異なる振る舞い

    をさらすことなく、実装の詳細にアクセスするには、ImmutableList.copyOf()Suppliers.memoize()CharMatcher.forPredicate()の例を参照してください。 com.google.common.collectパッケージ(例えば、Iterables.size())であり、可能であればCollection.size()が呼び出され、それ以外の場合はイテレータの項目数がO(n)時間にカウントされます。

  • 私はこのメリットは、以上の非常に少数精鋭のケースで行われている懐疑的だけど、あなたは正しいことをやっている確信していると仮定すると、あなたは不回避することができますtoString()

    を呼び出さないようにするにCharSequenceオブジェクトをStringsにinstanceofと変換すると、Joiner.toString(Object)で行われます。

  • を扱う複雑な例外を行うには明らかに行うには「正しい」ものは(実際に、それはすでにinstanceofチェックをやっているが)try/catchブロックを使用しているが、時にはあなたはそのメリットより複雑な処理ロジックを持っています条件付きブロックを使用するか、別のメソッドに処理を渡すことができます(たとえば、原因を取り除くか、実装固有の処理を行うなど)。例はSimpleTimeLimiter.throwCause()にあります。この動作を見て際立って

一つは、ほぼすべてのそれらの問題に対処しているされて私はを解決すべきではありません。ライブラリコードで便利です(例: Iterablesにありますが、もし私がこの振る舞いを実装しているなら、私のためにこれを解決するライブラリやユーティリティがないかどうか、私はおそらく自分自身に尋ねるべきです。

すべての場合、instanceofのチェックは、実装の詳細として内部でのみ使用する必要があります。つまり、instanceofチェックに依存するすべてのメソッドの呼び出し元は、(簡単に)それを伝えることができません。あなたがしたこと。たとえば、ImmutableList.copyOf()は常にImmutableListを返します。実装の詳細としては、新しいImmutableListを構築することを避けるためにinstanceofを使用しますが、これは予想される動作を受け入れられるようにする必要はありません。

私はグアバのソースコードを掘り下げていたので、あなたの名前にルイスが来て面白かったです。私は分かりませんでした!

+0

大きな、尊重されたコードベース(Guava)の良い分析。 – kevinarpe

+0

ユーティリティー・ライブラリーは、Java言語の使用法の良いサンプルを提供していません。たとえば、いくつのGoFデザインパターンを使用していますか? –

+0

Guavaは、*良い*コードベースの例として使用しましたが、必ずしも代表的なものではありません。私が逃した 'instanceof'を使用する他の*良い*理由があるなら、私は質問を更新します。現在、私は気づいていない。 – dimo414

関連する問題