Java 插入密钥时自定义等于/哈希(番石榴缓存)

Java 插入密钥时自定义等于/哈希(番石榴缓存),java,hash,equals,guava,Java,Hash,Equals,Guava,简单地说,我必须重写缓存选择正确键的方式,因为在检索键时不应考虑某些字段(例如,时间戳、消息id等)。 我无法修改key对象的实际哈希函数,因为它已用于在代码中识别 有番石榴贮藏库吗?还有解决办法? 这是我的配置: CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).recordStats(). expireAfterWrite(DEFAULT_AGE, TimeUnit.DAYS).build( new CacheLoader&

简单地说,我必须重写缓存选择正确键的方式,因为在检索键时不应考虑某些字段(例如,时间戳、消息id等)。 我无法修改key对象的实际哈希函数,因为它已用于在代码中识别
有番石榴贮藏库吗?还有解决办法?

这是我的配置:

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();
        }
    });

您可以简单地将
请求
对象包装到
缓存请求
对象中,其中
缓存请求
将基于所需字段实现
hashCode()
equals()
,如果无法修改哈希函数,则提供对包装的
请求
的访问权(我仍然不明白为什么),那么您需要为缓存使用“包装器”密钥,例如:

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)));
  }
}

我很确定,使用番石榴是不可能的。有一些使用自定义等价物的合法案例,但他们说它们太少,无法由
CacheBuilder
MapMaker
处理。1甚至有
com.google.common.base.Equivalence
,但它只在内部使用(另请参见和)

您需要在要用于查找的字段中设置自己的密钥,或者将
请求
包装到另一个对象中,以您想要的方式定义
equals
hashCode


1当使用与默认的
equals
/
hashCode
不同的东西时,唯一的情况是使用
weakKeys
软键
),然后是
==
/
系统。identityHashCode
组合。在任何情况下,您都不能自由选择等效项。

如果使用Lombok:

有一个Lombok注释
@EqualsAndHashCode
,它覆盖
hashCode
equals
,以对象的非静态、非瞬态属性为基础。因此,对于以下内容,如果您比较两个使用相同的
姓名
年龄
工资
创建的员工,他们的评估结果将为de>比较时为真

@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注释文档:


示例来自:

如果它使用自己的哈希实现,我无法想象它会是一个非常有用的实用程序。另外,您能否进一步解释“我不能修改我的哈希()函数,因为它已经用于识别“真实”等于对象”的意思?事实上,我并不是要求添加此功能,但如果有人知道如何处理此情况,您可以通过在密钥(即您的请求)上适当地实现hashCode()和equals()来处理此情况。仅从
hashCode
中删除字段,而将其保留在
equals
中。1.可能对性能有害,2.肯定正确,3.毫无意义。虽然@Hamal000没有提到他的equals,但我认为其中也包含了字段。我无法修改哈希,因为它是遗留代码,并且哈希已在某个位置使用还有。@Hamal000-我理解。但是,从hashcode中删除字段不应该降低它在其他地方的有用性(除非您一直将这些hashcode存储在例如数据库中)嗯,删除一个字段意味着缩小散列函数映射对象的空间,但这不是问题所在……不幸的是,在我的例子中,散列被用作客户端某处的id(使用此函数)。
等价性是公共的:@fry:的确是,但只有一个公共用途(在
Maps.difference
中)。
@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;
}