10

単純に、キーを取得するときに一部のフィールド(タイムスタンプ、メッセージIDなど)を考慮すべきではないため、キャッシュが正しいキーを選択する方法をオーバーライドする必要があります。 キーオブジェクトの実際のハッシュ関数は、コードでの認識にすでに使用されているため、変更できません。
Guavaキャッシュで可能ですか?そして回避策はありますか?

これは私の構成です:

CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).recordStats().
    expireAfterWrite(DEFAULT_AGE, TimeUnit.DAYS).build(
    new CacheLoader<Request, Response>() {
        @Override
        public Response load(Request request) { 
            return request.getResponse();
        }
    });

そしてこれは私のハッシュ関数です(私のコードのどこかで使用されています):

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + code;
    result = prime * result + messageID; // <= **this one shouldn't evaluated**
    result = prime * result + Arrays.hashCode(payload);
    result = prime * result + (int) (timestamp ^ timestamp >>> 32); // <= **this one shouldn't evaluated**
    result = prime * result + (type == null ? 0 : type.hashCode());
    result = prime * result + version;
    return result;
}

ところで、この種のキャッシュは、独自のハッシュ関数の実装を使用していますか(たとえば、イントロスペクションによる)、それともデフォルトのキャッシュを使用していますか?

**編集: **
応答で指摘されているように、この結果を達成するための最良の方法はラッパークラスです。
私の解決策

/**
 * Nested class to store a request as a key in the cache. It is needed to
 * normalize the variable fields of the normal requests.
 */
private static final class CachedRequest extends Request {

    private static CachedRequest fromRequest(Request request) {
        // set only the fields that cannot change between two same requests
        // ...
    }

    @Override
    public int hashCode() {
        HashFunction hashFunction = Hashing.md5();
        HashCode hashCode;
        // ...
        return hashCode.asInt();
    }

    @Override
    public boolean equals(Object obj) {
            // coherent with hashCode()
            // ...
    }
}
4

4 に答える 4

16

RequestオブジェクトをCachedRequestオブジェクトにラップするだけで、目的のフィールドをCachedRequest実装hashCode()してequals()基づいて、ラップされたへのアクセスを提供できますRequest

于 2012-09-05T15:21:29.557 に答える
2

私はかなり確信しています、それはグアバでは不可能です。カスタム同等性を使用する正当なケースがいくつかありますが、それらは、CacheBuilderおよびで処理するにはまれすぎると言われていますMapMaker1もありますがcom.google.common.base.Equivalence、内部でのみ使用されます(ここここも参照してください)。

ルックアップに使用するフィールドから独自のキーを作成するかRequest、別のオブジェクトを定義equalshashCodeて希望の方法でラップする必要があります。

1equalsデフォルトの/とは異なるものhashCodeが使用される唯一のケースはwith weakKeyssoftKeysもう存在しない)であり、それは==/System.identityHashCodeコンボです。いかなる場合でも、同等性を自由に選択することはできません。

于 2012-09-05T15:24:26.127 に答える
1

ハッシュ関数を変更できない場合(理由はまだわかりません)、キャッシュに「ラッパー」キーを使用する必要があります。例:

public class RequestKey {
  private final Request _req;

  public int hashCode() {
    // use appropriate Request fields here
  }

  public boolean equals(Object o) {
    return ((this == o) || ((o != null) && (getClass() == o.getClass()) && _req.equals(((RequestKey)o)._req)));
  }
}
于 2012-09-05T15:21:44.440 に答える
0

Lombokを使用している場合:

@EqualsAndHashCodeオブジェクトの非静的、非一時的なプロパティをオーバーライドhashCodeし、それequalsに基づくLombokアノテーションがあります。したがって、以下の場合、同じ、、、およびで作成された2人の従業員を比較するとnameage比較時salaryに評価されtrueます。

@EqualsAndHashCode
public class Employee {

    private String name;
    private int age;
    private int salary;
}

含めたくないプロパティがある場合は、それらにマークを付けることができます@EqualsAndHashCode.Exclude

@EqualsAndHashCode
public class Employee {

    private String name;
    @EqualsAndHashCode.Exclude
    private int age;
    @EqualsAndHashCode.Exclude
    private int salary;
}

次のフィールドを具体的に含めることもできます。

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Employee {

    @EqualsAndHashCode.Include
    private String name;
    @EqualsAndHashCode.Include
    private int age;
    private int salary;
}

Lombokアノテーションドキュメント:https ://projectlombok.org/features/EqualsAndHashCode

例は次のとおりです:http ://www.javabyexamples.com/delombok-equalsandhashcode

于 2021-03-02T00:33:16.547 に答える