Java 理想的哈希代码实现
我的课程如下Java 理想的哈希代码实现,java,eclipse,equals,hashcode,Java,Eclipse,Equals,Hashcode,我的课程如下 public class Hash { int age; int id; String name; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((name == nul
public class Hash {
int age;
int id;
String name;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.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;
Hash other = (Hash) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
在本文中,我只使用了两个属性name和id来生成.equals方法,但现在我的问题是。实现.hashCode()方法的好方法是什么
两者的优点和缺点是什么?不用想太多,我会使用:apache的 要使用此类,请按如下方式编写代码:
public class Person {
String name;
int age;
boolean smoker;
...
public int hashCode() {
// you pick a hard-coded, randomly chosen, non-zero, odd number
// ideally different for each class
return new HashCodeBuilder(17, 37).
append(name).
append(age).
append(smoker).
toHashCode();
}
}
带答案:是否只有名称
和id
唯一地标识类的每个对象,并且与相等()
进行比较时一致?如果是,那么为什么我应该使用三个属性而不是两个属性
,有点旧,但细节不错。计算hashcode的一条重要规则是,您必须只使用与
equals()
实现相关的信息
由于在equals
方法中没有使用age
,因此在hashCode
中使用它是错误的!道理很简单:
- 想象两个对象o1和o2的属性为“id=1,age=2,name=foo”和“id=1,age=3,name=foo”
- 调用
将返回equals()
true
- 但是,调用
(在使用hashCode()
的实现上)将返回两个不同的值李>age
public int hashCode() {
return 0;
}
这是正确的,但效率极低(因为每个对象都会散列到相同的值,很明显!)。我认为如果id是唯一的,那么应该只使用id字段来生成哈希代码。通过这种方式,您将能够通过仅使用id创建对象来从集合中搜索对象
另外,如果您的id是唯一的,那么我们将为不同的对象使用不同的哈希代码,因此它将是有效的。哈希代码方法的实现取决于您希望如何进行bucketing-
关键是,这实际上取决于对象在范围内的分布方式(如果对象被正确地划分为桶,您将获得更好的性能)以及您希望如何进行扣合。不要使用
getClass()!=obj.getClass()
。使用instanceof
。否则,当您有子类时,它就会中断。如果不希望子类,则将类设置为final。但即便如此,也没有理由使用除instanceof
之外的其他东西。没有什么比“理想的哈希代码实现”更合适的了。但是你的代码看起来足够了。您的hashCode
实现必须与equals
一致。既然两者都不使用age
,这是正确的。@霍尔格:在子类的情况下,它将如何中断?。很少考虑两个不同子类的实例相等。我想说你永远不应该这样做that@DevBlanked:如果您永远不想要子类,那么将类设置为final。否则,您必须考虑子类的等于的契约。查看equals
实现的AbstractList
作为示例。可能有很多不同的子类被认为是相同的。@Holger AbstractList场景有点特殊,因为它实现了一个接口。因此,检查instanceof非常有意义。但在这种情况下,比较类是正确的做法。如果您有HashA子类,HashB扩展Hash类。您永远不希望HashA的实例被视为等同于hashb的实例这里有n种自动生成hashcode的方法,但我想了解它背后的逻辑热情,即实现是错误的(即使使用HashCodeBuilder
本身也不错):如果equals
不关心age
,则hashCode
不得使用它!我在最后一段加了一个问题来回答他的问题。该代码只是我从链接页面中选择的一个示例,它不是用来回答他的问题的。@Sage+1对于您现在的编辑,它是有意义的,但我不是downvoter@ankit对不起,我回复了约阿希姆。虽然我应该使用@
符号。事实上,当你和他评论的时候,我正在编辑。我还想链接一些文章。这意味着我们只能使用.equals中使用的信息或其中的一个子集,但我们不应该使用任何额外的信息information@ankit:没错。您甚至可以使用空子集(即使这通常是一个坏主意)。好的,最后一个问题是这样做是强制性的,使用一些额外的信息有什么害处吗?这将使我们的哈希代码更强大only@ankit:如果“额外信息”的意思是“在equals中使用的额外信息”那么,我能想到的唯一可能的缺点是,您的哈希代码可能需要更长的时间来计算。这取决于您如何准确地使用可能相关或不相关的对象(很抱歉,答案含糊不清,但这确实取决于:如果您很少或曾经在HashSet
或HashMap
中使用您的对象,那么整个hashCode
辩论就没有多大关系了)。
@Override
public int hashCode() {
return this.id % 2 == 0 ? 1 : 2;
}
@Override
public int hashCode() {
return this.age / 10 ;
}