2

と呼ばれるクラスがあり、オブジェクトNumberの等価比較をたくさん行うつもりだとしましょう。ジェネリックメソッドNumberの「オーバーヘッド」(クラス比較など)が気になります。この場合、?の代わりにNumber::equals(Object o)などの方法を提供することは有用ですか?これは一般的なパターンですか?または、JVMは現在、これを行う利点がないほど十分に最適化されていますか?Number::isEqualTo(Number other)Number::equals(Object o)

コード例は次のとおりです。

public class Number {
    int _value;

    Number(int value) {
        _value = value;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != getClass()) return false;
        return isEqualTo((Number)o);
    }

    public boolean isEqualTo(final Number other) {
        return _value == other._value;
    }

    public static void main(String[] args) {
        Number one = new Number(1);
        Number two = new Number(2);
        if (!one.isEqualTo(two)) {
            System.out.println("fast comparison?");
        }
        if (!one.equals(two)) {
            System.out.println("slow comparison?");
        }
    }
}
4

5 に答える 5

5

2つの方法のセマンティクスは異なります。

  • equalsObject::equals契約によってセマンティクスが決定されますが、
  • isEqualToNumberオブジェクトにのみ適用されるセマンティクスがあります

比較はリンゴ同士ではないので、equalsより多くのCPUサイクルが必要になるのは当然です。ただし、違いに気付く可能性はほとんどありません。

あなたのようなクラスがを実装することははるかに一般的ですComparable<T>。そこでのセマンティクスでは、等価性チェックだけでなく、順序チェックが必要ですが、不明なクラスのオブジェクトを取得する必要がないため、CPUサイクルを節約できます。

平等に代わるものを提供する正当な理由があるはずです(たとえば、equals(Object)ボトルネックとして指摘するプロファイラーの実行、変更による読みやすさの認識された改善、またはより多くのことを行うインターフェイスの採用によるより豊かなセマンティクスの達成)。数CPUサイクルを削減するためにこれを行うと、最適化が時期尚早になります。

于 2012-11-20T18:38:04.823 に答える
3

最も不利なシナリオ ( equalsalways calls isEqualTo) を使用した簡単なマイクロベンチマークは、次のことを示しています (ミリ秒):

等しい: 1014
isEqualTo: 1010

結論: プログラムが他に何もしない限り、これはパフォーマンスのボトルネックにはならず、最適化の第 1 原則に固執する必要があります。最初にプロファイルを作成し、次に最適化する必要があるものを最適化します。

テストコード:

public class TestPerf {

    private static int NUM_RUN;
    private static List<Number> list = new ArrayList<>();

    public static void main(String[] args) {
        NUM_RUN = 100_000;

        for (int i = 0; i < 10000; i++) {
            list.add(new Number(i));
        }

        long sum = 0;
        System.out.println("Warmup");

        for (int i = 0; i < NUM_RUN; i++) {
            sum += method1(17);
            sum += method2(17);
        }

        System.gc();

        System.out.println("Starting");

        sum = 0;
        long start = System.nanoTime();
        for (int i = 0; i < NUM_RUN; i++) {
            sum += method1(17);
        }
        long end = System.nanoTime();
        System.out.println("equals: " + (end - start) / 1000000);

        System.gc();

        start = System.nanoTime();
        for (int i = 0; i < NUM_RUN; i++) {
            sum += method2(17);
        }
        end = System.nanoTime();
        System.out.println("isEqualTo: " + (end - start) / 1000000);

        System.out.println(sum);
    }

    private static int method1(int target) {
        int sum = 0;
        Number comparison = new Number(target);
        for (Number n : list) {
            if (n.equals(comparison)) sum++;
        }
        return sum;
    }

    private static int method2(int target) {
        int sum = 0;
        Number comparison = new Number(target);
        for (Number n : list) {
            if (n.isEqualTo(comparison)) sum++;
        }
        return sum;
    }

    public static class Number {

        int _value;

        Number(int value) {
            _value = value;
        }

        @Override
        public boolean equals(final Object o) {
            if (o == this) return true;
            if (o == null) return false;
            if (o.getClass() != getClass()) return false;
            return isEqualTo((Number) o);
        }

        public boolean isEqualTo(final Number other) {
            return _value == other._value;
        }
    }
}
于 2012-11-20T18:37:28.750 に答える
1

これは、比較メソッドを使用する場所によって異なります。

たぶん、コンパレータインターフェイスのさまざまな実装を使用できますか?

これらは、例えばに使用することができます。リストを並べ替えます。

于 2012-11-20T18:30:57.923 に答える
1

それ自体のオーバーロードを提供することさえできequalsます: equals(Number). 非常に慎重に実装すると(動作的に と区別できないようにequals(Object)するため)、特定の場合にチェック ダウンキャストを回避することで、わずかな速度向上を実現できます。a.getClass() == b.getClass()違いが無視できるほど小さいので、まだチェックする必要があることに注意してください。

于 2012-11-20T18:32:27.327 に答える
0

xx.isEqualTo.yy「オブジェクト」レベルでの比較です。この 2 つのオブジェクトが同じオブジェクトを参照しているかどうかを確認するだけです。

特定のクラスに対して「方程式メソッド」を記述する方が常に優れています。たとえば、この場合、最適な比較は単純==です。

于 2012-11-20T18:33:58.643 に答える