Java 处理映射、equals()和hashCodes()。这有多高效?
我正在写的东西每秒会收到相当多的交易。对于传入的每个事务,都会引用一个映射,其中键值是id,bean将帮助处理该特定事务。基本上,每个事务都带有一个id,将对映射进行查找,以检索相应的bean进行处理。棘手的是,每个事务的id并不意味着与映射中的id精确匹配。更多的问题是从操作开始的。为此,我没有使用字符串作为id,而是创建了一个名为MyId的简单pojo。代码如下:Java 处理映射、equals()和hashCodes()。这有多高效?,java,hashmap,Java,Hashmap,我正在写的东西每秒会收到相当多的交易。对于传入的每个事务,都会引用一个映射,其中键值是id,bean将帮助处理该特定事务。基本上,每个事务都带有一个id,将对映射进行查找,以检索相应的bean进行处理。棘手的是,每个事务的id并不意味着与映射中的id精确匹配。更多的问题是从操作开始的。为此,我没有使用字符串作为id,而是创建了一个名为MyId的简单pojo。代码如下: public class MyId { private static final int HASHCODE_CONST
public class MyId
{
private static final int HASHCODE_CONSTANT = 1;
private String value;
public MyId(String value)
{
this.value = value;
}
@Override
public int hashCode()
{
//Returns the same hashcode value for all instances of this pojo
return HASHCODE_CONSTANT;
}
@Override
public boolean equals(Object obj)
{
//Checks for object type, forcibly casts and then compares the starts with
if(obj instanceof MyId)
{
if(!(obj == null || "".equals(obj)))
{
return this.value.startsWith(((MyId)obj).getValue());
}
}
return false;
}
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
//Test
public static void main(String[] args)
{
Map map = new HashMap();
map.put(new MyId("123456"), "");
System.out.println("Result: " + map.containsKey(new MyId("12345677")));
System.out.println("Result: " + map.containsKey(new MyId("11234567")));
}
}
第一个测试返回true,第二个测试返回false,就像它应该返回的一样。似乎在调用equals()之前,map.containsKey()方法首先调用并比较对象的hashcode方法。如果你的散列值不匹配,它甚至不需要比较。虽然这是可行的,但必须以这种方式实现hashcode方法来欺骗映射,这感觉有点狡猾
我想知道是否有更有效的方法来做到这一点。我们每秒处理相当多的事务,因此需要在地图上查找相当多的内容
PS:我把这个盲编码了,所以我肯定有语法错误。请忽略这些。只是想表达一下大意。如果您的hashCode()
方法返回一个常量值,那么您的所有键都将散列到HashMap
中的同一个bucket中,从而有效地将HashMap
减少为一个链表,访问时间为O(n)(而不是近似为O(1))
一种可能的解决方案(不节省空间):对于每个字符串,存储与可能的字符串前缀相对应的多个键,但所有键都引用相同的值。例如,对于单词“Hello”,您将存储键“H”、“He”、“Hel”、“Hell”、“Hello”。这显然会占用更多的空间,但查找时间会非常快,您不需要修改类的equals()
方法来执行“模糊”比较。您可以通过编写自定义类来提高空间效率;e、 g
/**
* Class representing String prefix.
* Storage overhead == original string + two ints.
*/
public class Prefix {
private final String str;
private final int len;
private final int hc;
public Prefix(String str, int len) {
this.str = str;
this.len = len;
this.hc = toString().hashCode(); // Precompute and store hash code.
}
public String toString() {
return str.substring(0, len);
}
public int hashCode() {
return hc;
}
public boolean equals(Object o) {
boolean ret;
if (this == o) {
ret = true;
} else if (o instanceof Prefix) {
ret = toString().equals(((Prefix)o).toString());
} else {
ret = false;
}
return ret;
}
}
如果您的hashCode()
方法返回一个常量值,则所有键都将散列到HashMap
中的同一个存储桶中,从而有效地将HashMap
减少为一个链表,访问时间为O(n)(而不是近似为O(1))
一种可能的解决方案(不节省空间):对于每个字符串,存储与可能的字符串前缀相对应的多个键,但所有键都引用相同的值。例如,对于单词“Hello”,您将存储键“H”、“He”、“Hel”、“Hell”、“Hello”。这显然会占用更多的空间,但查找时间会非常快,您不需要修改类的equals()
方法来执行“模糊”比较。您可以通过编写自定义类来提高空间效率;e、 g
/**
* Class representing String prefix.
* Storage overhead == original string + two ints.
*/
public class Prefix {
private final String str;
private final int len;
private final int hc;
public Prefix(String str, int len) {
this.str = str;
this.len = len;
this.hc = toString().hashCode(); // Precompute and store hash code.
}
public String toString() {
return str.substring(0, len);
}
public int hashCode() {
return hc;
}
public boolean equals(Object o) {
boolean ret;
if (this == o) {
ret = true;
} else if (o instanceof Prefix) {
ret = toString().equals(((Prefix)o).toString());
} else {
ret = false;
}
return ret;
}
}
我认为您正在强制两个不同的对象使用相同的数据结构,这使得您的地图没有那么高效 为了提供更好的解决方案,我可能需要更多信息,例如:地图中的id是否总是6位数 好的,然后你可以创建两个像这样的类
public class MyIdMap {
private String value;
public MyIdMap(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyIdMap other = (MyIdMap) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}
public class MyId {
private String value;
public MyId(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public MyIdMap getMyIDMap() {
return new MyIdMap(value.substring(0, 6));
}
}
将MyIdMap放在一个映射中,然后当您查找它时,只需使用Map.get(myId.getMyIdMap())我认为您是在强制两个不同的对象使用相同的数据结构,这使得您的映射效率不高 为了提供更好的解决方案,我可能需要更多信息,例如:地图中的id是否总是6位数 好的,然后你可以创建两个像这样的类
public class MyIdMap {
private String value;
public MyIdMap(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyIdMap other = (MyIdMap) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}
public class MyId {
private String value;
public MyId(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public MyIdMap getMyIDMap() {
return new MyIdMap(value.substring(0, 6));
}
}
将MyIdMap放在一个映射中,然后当您查找它时,只需使用Map.get(myId.getMyIdMap())为什么要以如此低效的方式使用HashMap。同样,使用TreeMap可以更快地完成同样的事情——它完全可以完成您想要的。
此外,哈希代码中的const将显示O(n)性能,而TreeMap将显示ln(n)。为什么以如此低效的方式使用HashMap。同样,使用TreeMap可以更快地完成同样的事情——它完全可以完成您想要的。
此外,哈希代码中的常量将显示O(n)性能,而TreeMap为您提供ln(n)。此对象甚至不遵循:
- 如果根据equals(Object)方法两个对象相等,那么对两个对象中的每一个调用hashCode方法必须产生相同的整数结果
- 根据equals(java.lang.Object)方法,如果两个对象不相等,则对这两个对象中的每一个调用hashCode方法都必须产生不同的整数结果,这不是必需的
您可能需要测试您的实现(一个始终返回常量的存根)和一个“普通”的
对象,比如字符串。请测试,测试,测试,思考,测试,测试,…这个目标甚至没有遵循:
- 如果根据equals(Object)方法两个对象相等,那么对两个对象中的每一个调用hashCode方法必须产生相同的整数结果
- 根据equals(java.lang.Object)方法,如果两个对象不相等,则对这两个对象中的每一个调用hashCode方法都必须产生不同的整数结果,这不是必需的
但是,程序员应该知道,为不相等的对象生成不同的整数结果可能会提高哈希表的性能
您可能需要测试您的实现(一个始终返回常量的存根)和一个“普通”的对象,比如字符串。请测试,测试,测试<