10

简单地说,我必须重写缓存选择正确键的方式,因为在检索键时不应该考虑某些字段(例如,时间戳、消息 ID 等)。 我无法修改密钥对象的实际散列函数,因为它已用于在我的代码中进行识别。
Guava Caches 可以吗?并有解决方法?

这是我的配置:

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

我很确定,使用番石榴是不可能的。有一些使用自定义 Equivalence 的合法案例,但他们说它们太少了,无法由CacheBuilderand处理MapMaker1有 even com.google.common.base.Equivalence,但仅在内部使用(另请参见此处此处)。

您需要从要用于查找的字段中创建自己的密钥,或者将您的密钥包装Request在另一个对象定义equalshashCode您想要的方式中。

1equals与默认/不同的唯一情况hashCode是使用weakKeys(softKeys不再存在),然后是==/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 Annotation@EqualsAndHashCode覆盖hashCodeequals基于对象的非静态、非瞬态属性。因此,对于下面的情况,如果您比较使用相同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 回答