3

クラスがあります

class A {
    private int x;
    public void setX(...){...}
    public int getX(){return x;}
}

class B {
    int y;
    public void setY() {
        //Accessing x of A, assume I already have object of A
        if(a.getX() < 0) {
             y = a.getX();
        }
    }
}

class C {
    int y;
    public void setY() {
        //Accessing x of A, assume I already have object of A
        int tmpX = a.getX();
        if(tmpX < 0) {
             y = tmpX;
        }
    }
}

どちらがより良いコーディング方法ですか? x of Aクラス B またはクラス C でアクセスした方法は?

4

11 に答える 11

2

どちらがより良いコーディング方法ですか?

読みやすさに関しては議論の余地がありますが、ほとんど違いはありません。

堅牢性に関してCは、より優れています。以下 (最後) を参照してください。ただし、多くの場合、これらのシナリオを除外できます。

パフォーマンス (これはあなたが実際に求めていることです) に関しては、答えはプラットフォームに依存するということです。による:

  • コードをコンパイルしているか解釈しているかに関係なく、
  • そのコードが実際にコンパイルされるかどうかにかかわらず、JIT コンパイルしている場合、および
  • コンパイラ/オプティマイザの品質、および効果的に最適化する能力。

確認する唯一の方法は、有効なマイクロ ベンチマークを作成し、関心のある特定のプラットフォームを使用して実際にパフォーマンスをテストすることです。

(またgetX()、仮想呼び出しが必要かどうか、つまりgetX()メソッドをオーバーライドする X のサブクラスであるかどうかにも依存します。)

ただし、次のように予測します。

  • JIT コンパイルが有効になっている Java Hotspot システムでは、JIT は getX() 呼び出しをインライン化します (仮想呼び出しの問題をモジュロします)。
  • 初期の Davlik VM では、JIT コンパイラは呼び出しをインライン化しません。
  • 最近の Davlik VM では、JIT コンパイラが呼び出しをインライン化します。

(最後の予測は、Davlik コンパイラ担当者の 1 人からのこの回答に基づいています ... )


コードを事前にマイクロ最適化することは、一般的には悪い考えです。

  • ほとんどの場合、マイクロ最適化は時間の無駄になります。このコードが頻繁に実行されない限り、パフォーマンスの違いはほとんど目立たないでしょう。
  • 残りの時間の一部では、マイクロ最適化は効果がありません...または実際に事態を悪化させます1
  • マイクロ最適化がプラットフォームの 1 つの世代で機能したとしても、それ以降のバージョンでの JIT コンパイラの変更により、マイクロ最適化が無効になるか、さらに悪化する可能性があります。

1 - Sun のコンパイラ担当者から、「巧妙なマイクロ最適化」によってオプティマイザが有用な最適化が可能であることを実際に検出できなくなる可能性があるというアドバイスを見たことがあります。これはおそらくこの例には当てはまりませんが...


最後に、 とが同等のコードBではない状況があることに注意してください。C頭に浮かぶ状況の 1 つは、誰かがメソッドに隠れた副作用があるサブクラスを作成した場合AですgetX。たとえば、呼び出しgetXによってイベントが発行される場合や、呼び出しカウンターがインクリメントされる場合などです。

于 2013-06-29T06:12:22.777 に答える
1

通常は一時変数を使用する必要があります。つまり、通常は次の方法が適しています。

 int tmpX = a.getX();
 if(tmpX < 0) {
       y = tmpX;
 }

これにはいくつかの理由があります。

  • 少なくとも同じかそれ以上速くなります。一時的なローカルint変数の使用は非常に安価で (ほとんどの場合、CPU レジスタに格納されます)、追加のメソッド呼び出しと追加のフィールド ルックアップのコストよりも優れています。が良ければ、JIT は 2 つを同等のネイティブ コードにコンパイルするかもしれませんが、それは実装に依存します。
  • 同時実行のほうが安全です。フィールドは、2 つの呼び出しxの間に別のスレッドによって変更される可能性があります。getX()通常、値を 1 回だけ読み取り、その値を操作するのではなく、2 つの潜在的に異なる値を処理して結果を混乱させるという問題が発生するのではなく....
  • 将来誰かが行って呼び出しをより複雑にすると、間違いなくより効率的getX()になります (たとえば、ログを追加したり、フィールドを使用するのではなく x の値を計算したりします)。長期的な保守性を考えてください。
  • 適切な名前の一時変数に割り当てることで、より適切な名前を使用できます。tmpXあまり意味のあるものではありませんが、そのようなものであればplayerOneScore、コードがより明確になります。適切な名前は、コードをより読みやすく、保守しやすくします。
  • 余分なメソッド呼び出しを最小限に抑えることは、一般的に良い習慣です。この特定のケースでは問題にならない場合でも、これを行う習慣を身につけて、重要な状況 (たとえば、メソッド呼び出しが高価なデータベース ルックアップを引き起こす場合) で自動的に行うようにすることをお勧めします。
于 2013-06-28T12:18:45.400 に答える
0

自分で確認したい場合は、 a を使用しSystem.currentTimeMillis()てコードを数百万回実行し (作成された変数を別のものに設定してリセットされることを確認するたびに)、System.currentTimeMillis()もう一度使用して減算して、それぞれの合計時間の繰り返しを取得します。どちらが速いかを確認します。ちなみに、実際に何百万回も実行しない限り、大きな違いが生じるとは思えません。

于 2013-06-28T11:59:56.997 に答える