8

編集 2 : 完全にobject-oriented実装されたプログラムは高いパフォーマンスを発揮しますか? ほとんどは、frameworkそれの全力で書かれています。ただし、 forやreflectionのようにそれを達成するためにも頻繁に使用されます。の使用はパフォーマンスにある程度影響します。AOPdependency injectionreflection

それで、使用するのは良い習慣reflectionですか?プログラミング言語構造からのリフレクションに代わるものはありますか? どの程度までreflection使用する必要がありますか?

4

3 に答える 3

10

リフレクションは、それ自体、そして本質的に遅いものです。詳細については、この質問を参照してください。これにはいくつかの理由があります。ジョン・スキートはそれをうまく説明しています:

パラメーターなしのコンストラクターがあることを確認する パラメーターなしのコンストラクターのアクセス可能性を確認する 呼び出し元がリフレクションを使用するためのアクセス権を持っていることを確認する (実行時に) 割り当てられる必要があるスペースの量を計算する コンストラクター コードを呼び出す (それがわからないため)事前にコンストラクターが空であること)

基本的に、リフレクションは呼び出しの前に上記のすべてのステップを実行する必要がありますが、通常のメソッド呼び出しははるかに少ないことを行う必要があります。

B をインスタンス化するための JITted コードは非常に軽量です。基本的に、十分なメモリを割り当てる必要があります (GC が必要でない限り、ポインタをインクリメントするだけです)。それだけです。実際に呼び出すコンストラクタ コードはありません。JITがそれをスキップするかどうかはわかりませんが、どちらにしてもやることはあまりありません。

そうは言っても、Java が必要なことを行うのに十分なほど動的ではない場合が多くあり、リフレクションはシンプルでクリーンな代替手段を提供します。次のシナリオを検討してください。

  1. CarBoat、 など、さまざまなアイテムを表すクラスが多数ありますHouse
  2. どちらも同じクラスを拡張/実装します: LifeItem.
  3. ユーザーは、"Car"、"Boat"、または "House" の 3 つの文字列のいずれかを入力します。
  4. 目標は、パラメーターに基づいて LifeItem のメソッドにアクセスすることです。
  5. 頭に浮かぶ最初のアプローチは、if/else 構造を構築し、want を構築することLifeItemです。ただし、これはあまりスケーラブルではなく、数十のLifeItem実装があると非常に面倒になる可能性があります。

ここでリフレクションが役立ちます。LifeItem名前に基づいてオブジェクトを動的に構築するために使用できるため、「Car」入力がCarコンストラクターにディスパッチされます。突然、数百行の if/else コードだった可能性があるものが、単純な反射行に変わります。後者のシナリオは、文字列を使用した switch ステートメントが導入されているため、Java 7 以降のプラットフォームでは有効ではありませんが、それでも何百ものケースを含む switch は避けたいものです。ほとんどの場合、清潔さの違いは次のようになります。

反射なし:

public static void main(String[] args) {
   String input = args[0];
   if(input.equals("Car"))
      doSomething(new Car(args[1]));
   else if(input.equals("Boat"))
      doSomething(new Boat(args[1]));
   else if (input.equals("House"))
      doSomething(new House(args[1]));
   ... // Possibly dozens more if/else statements
}

一方、リフレクションを利用すると、次のようになります。

public static void main(String[] args) {    
   String input = args[0];
   try {
      doSomething((LifeItem)Class.forName(input).getConstructor(String.class).newInstance(args[1]));
   } catch (Exception ie) {
      System.err.println("Invalid input: " + input);
   }  
}

個人的には、後者の方が前者よりもすっきりしていて、簡潔で、保守しやすいと思います。最終的には個人的な好みですが、これはリフレクションが役立つ多くのケースの 1 つにすぎません。

さらに、リフレクションを使用する場合は、できるだけ多くの情報をキャッシュするようにしてください。言い換えれば、単純で論理的なことを採用get(Declared)Methodします。たとえば、できる限りどこでも呼び出すのではなく、変数に格納して、使用するたびに参照を再取得するオーバーヘッドがないようにします。

したがって、これらは反射の長所と短所の両極端です。要約すると、リフレクションによってコードの可読性が向上する場合 (提示されたシナリオのように)、ぜひ試してみてください。その場合は、リフレクション コールの数を減らすことget*を検討してください。リフレクション コールは最も簡単に削除できます。

于 2013-02-18T16:23:24.990 に答える
7

リフレクションは「従来のコード」よりも費用がかかりますが、時期尚早の最適化はすべての悪の根源です。10年にわたる経験的証拠から、リフレクションを介して呼び出されたメソッドは、重いループから呼び出されない限り、パフォーマンスにほとんど影響を与えないと思います。それでも、リフレクションでパフォーマンスが向上しています。

特定のリフレクティブ操作、特にField、Method.invoke()、Constructor.newInstance()、およびClass.newInstance()は、パフォーマンスを向上させるために書き直されました。リフレクティブ呼び出しとインスタンス化は、以前のリリースよりも数倍高速です 。J2SDK1.4の拡張機能-

メソッドルックアップ(つまり、Class.getMethod)は上記に記載されておらず、適切なメソッドオブジェクトを選択するには、通常、クラス階層をトラバースしながら、パブリックでない場合は「宣言されたメソッド」を要求するなどの追加の手順が必要です。可能な場合はいつでも、見つかったメソッドを適切なマップに保存する傾向があるため、次回のコストはMap.get()とMethod.invoke()のコストのみになります。うまく書かれたフレームワークならどれでもこれを正しく処理できると思います。

リフレクションが使用されている場合、特定の最適化が不可能であることも考慮する必要があります(メソッドのインライン化やエスケープ分析など。JavaHotSpot™仮想マシンのパフォーマンスの向上)。しかし、これは、反射を絶対に避けなければならないという意味ではありません。

ただし、リフレクションを使用するかどうかの決定は、コードの可読性、保守性、設計手法などの他の基準に基づく必要があると思います。独自のコードでリフレクションを使用する場合(内部でリフレクションを使用するフレームワークを使用するのではなく)、1つコンパイル時エラーをデバッグが難しい実行時エラーに変換するリスクがあります。場合によっては、リフレクティブ呼び出しをCommandやAbstractFactoryなどの従来のOOPパターンに置き換えることができます。

于 2013-02-18T06:39:36.473 に答える
2

一例を挙げることができます (ただし、申し訳ありませんが、数か月前のテスト結果をお見せすることはできません)。私は、いくつかの古い DOM パーサー コードをクラス + 注釈に置き換えた XML ライブラリ (カスタム プロジェクト指向) を作成しました。私のコードは元のサイズの半分でした。私はテストを行いましたが、リフレクションはよりコストがかかりましたが、それほど多くはありませんでした (実行の 14 ~ 15 秒のうち 0.3 秒程度 (損失は約 2%))。コードが頻繁に実行されない場所では、わずかなパフォーマンスの低下でリフレクションを使用できます。

さらに、パフォーマンスを向上させるためにコードを改善できると確信しています。

そこで、次のヒントをお勧めします。

  1. 美しくコンパクトで簡潔な方法で行うことができる場合は、リフレクションを使用してください。
  2. コードが何度も実行される場合は、リフレクションを使用しないでください。
  3. 大量の情報を別のソース (XML ファイルなど) から Java アプリケーションに投影する必要がある場合は、リフレクションを使用します。
  4. リフレクションと注釈の最適な使用法は、コードが 1 回だけ実行される場合 (プリローダー) です。
于 2013-02-18T10:26:22.523 に答える