简单地说,我必须覆盖缓存选择正确密钥的方式,因为在检索密钥时不应考虑某些字段(例如,时间戳,消息ID等)。
我无法修改密钥对象的实际哈希函数,因为它已经用于在我的代码中识别。
是否可以使用番石榴缓存?有一个解决方法?
这是我的配置:
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()
// ...
}
}
答案 0 :(得分:14)
您只需将Request
个对象包装到CachedRequest
个对象中,其中CachedRequest
将根据所需字段实现hashCode()
和equals()
,并提供访问权限包裹Request
。
答案 1 :(得分: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)));
}
}
答案 2 :(得分:1)
我很确定,番石榴是不可能的。有一些使用自定义等价的合法案例,但他们说它们太少了,无法由CacheBuilder
和MapMaker
处理。 1 甚至{{1} },但它仅在内部使用(另请参阅here和here)。
您需要在要用于查找的字段中创建自己的密钥,或者将com.google.common.base.Equivalence
包装在另一个定义Request
和equals
的对象中。
1 使用与hashCode
/ equals
不同的内容的唯一情况是hashCode
(weakKeys
不再存在) ,然后它是softKeys
/ ==
组合。在任何情况下,您都不能自由选择等价。
答案 3 :(得分:0)
如果您使用的是 Lombok:
有一个 Lombok Annotation @EqualsAndHashCode
,它覆盖 hashCode
和 equals
以基于对象的非静态、非瞬态属性。因此,对于以下内容,如果您比较使用相同 name
、age
和 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