我有一个应用程序,它显示行中的对象集合,一个对象=一行.对象存储在HashMap中.行的顺序不会影响应用程序的功能(这就是使用HashMap而不是可排序集合的原因).
但是我注意到,当使用两个不同版本的Java虚拟机运行时,相同的应用程序运行方式不同.应用程序使用JDK 5编译,可以使用Java 5或Java 6运行时运行,没有任何功能差异.
有问题的对象覆盖java.lang.Object#hashCode()并且显然需要遵循Java API中指定的契约.这可以通过以下事实得到证明:它们在应用程序的每次运行中始终以相同的顺序出现(在同一Java运行时中).
出于好奇,为什么Java运行时的选择会影响订单?
对于其字段仅为原始的类,例如:
class Foo
{
int a;
String b;
boolean c;
long d;
boolean equals(Object o)
{
if (this == o) return true;
if (!(o instanceof Foo)) return false;
Foo other = (Foo) o;
return a == other.a && b.equals(other.b) && c == other.c && d = other.d;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个合理的"足够好"的写作方式hashCode()吗?
boolean hashCode()
{
return (b + a + c + d).hashCode();
}
Run Code Online (Sandbox Code Playgroud)
也就是说,我构建了一个使用String相同的字段,equals()然后使用String#hashCode().
编辑: 我已更新我的问题以包括一个long字段.应如何long处理hashCode()?只是让它溢出int …
public class Test {
public static void main(String args[]) {
String s1 = "abc";
//Here is invoking of overriding String hashCode method.
System.out.println("hashCode value "+s1.hashCode()); }
}
Run Code Online (Sandbox Code Playgroud)
而不是它,我想得到非重写的Object hashCode方法.我怎么得到它?
我有一个不可变的类TokenList,它由Token对象列表组成,它们也是不可变的:
@Immutable
public final class TokenList {
private final List<Token> tokens;
public TokenList(List<Token> tokens) {
this.tokens = Collections.unmodifiableList(new ArrayList(tokens));
}
public List<Token> getTokens() {
return tokens;
}
}
Run Code Online (Sandbox Code Playgroud)
我对这些TokenLists执行了几个操作,这些操作将多个TokenLists作为输入并返回单个TokenList作为输出.可以有任意多个TokenLists进入,每个TokenLists可以有任意多个Tokens.
这些操作很昂贵,并且很有可能多次执行相同的操作(即相同的输入),所以我想缓存输出.但是,性能至关重要,我担心在这些可能包含任意多个元素的对象上执行hashCode()和equals()的费用(因为它们是不可变的,然后hashCode可以被缓存,但是equals仍然很昂贵).
这让我想知道是否可以通过对TokenList进行以下更新来简单而廉价地使用UUID来提供equals()和hashCode():
@Immutable
public final class TokenList {
private final List<Token> tokens;
private final UUID uuid;
public TokenList(List<Token> tokens) {
this.tokens = Collections.unmodifiableList(new ArrayList(tokens));
this.uuid = UUID.randomUUID();
}
public List<Token> getTokens() {
return tokens;
}
public UUID getUuid() {
return uuid;
}
}
Run Code Online (Sandbox Code Playgroud)
这样的东西充当缓存键:
@Immutable
public final class TopicListCacheKey {
private …Run Code Online (Sandbox Code Playgroud) 在一次传递中基于这些字符串的值计算哈希码的最佳方法是什么?
好的我的意思是它需要:
1 - fast:我需要获取大字符串(10 ^ 3..10 ^ 8项)的短字符串的哈希码.
2 - 识别整个数据列表这么多列表可能只有几个不同的字符串必须有不同的哈希码
怎么用Java做?
也许有一种方法可以使用现有的字符串哈希码,但如何合并为单独的字符串计算的许多哈希码?
谢谢.
我有以下来自Joshua Bloch的有效Java代码(第9章,第3章,第49页)
如果类是不可变的并且计算哈希代码的成本很高,您可以考虑在对象中缓存哈希代码,而不是每次请求时重新计算它.如果您认为此类型的大多数对象将用作哈希键,则应在创建实例时计算哈希码.否则,您可能会在第一次调用hashCode时选择懒惰地初始化它(Item 71).目前尚不清楚我们的PhoneNumber类是否值得这样做,只是为了向您展示它是如何完成的:
// Lazily initialized, cached hashCode
private volatile int hashCode; // (See Item 71)
@Override public int hashCode() {
int result = hashCode;
if (result == 0) {
result = 17;
result = 31 * result + areaCode;
result = 31 * result + prefix;
result = 31 * result + lineNumber;
hashCode = result;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是如何缓存(记住hashCode)在这里工作.第一次hashCode()调用方法,没有hashCode将其分配给结果.这个缓存如何工作的简要解释将是伟大的.谢谢
请考虑以下代码:
private static void TestHashCode<T>()
{
dynamic initialValue = 10;
Console.WriteLine("{0}: {1}", typeof(T).Name, ((T)initialValue).GetHashCode());
}
TestHashCode<int>();
TestHashCode<uint>();
TestHashCode<long>();
TestHashCode<ulong>();
TestHashCode<short>();
TestHashCode<ushort>();
Run Code Online (Sandbox Code Playgroud)
输出:
Int32: 10
UInt32: 10
Int64: 10
UInt64: 10
Int16: 655370
UInt16: 10
Run Code Online (Sandbox Code Playgroud)
见之间的差异short和ushort?实际上,这些类的源代码是不同的:
// ushort
public override int GetHashCode()
{
return (int) this;
}
// short
public override int GetHashCode()
{
return (int) (ushort) this | (int) this << 16;
}
Run Code Online (Sandbox Code Playgroud)
但与此同时,GetHashCode()签名/未签名版本的实现int和long相同:
// int and uint
public override …Run Code Online (Sandbox Code Playgroud) 嗨,我想知道如果你有你正在寻找的对象的Hashcode,是否可以直接访问HashSet的内容,有点像使用HashCode作为HashMap中的键.
我想它可能会像这样:
MyObject object1 = new MyObject(1);
Set<MyObject> MyHashSet = new HashSet<MyObject>();
MyHashSet.add(object1)
int hash = object1.getHashCode
MyObject object2 = MyHashSet[hash]???
Run Code Online (Sandbox Code Playgroud)
谢谢!
编辑:谢谢你的回答.好吧,我知道我可能会推动HashSet的合同,但是对于这个特定的项目,相等性完全由哈希码决定,我确信每个哈希码/ hashbucket只有一个对象.我非常不愿意使用HashMap的原因是因为我需要将我正在映射的原始int转换为Integer对象,因为HashMap只接受对象作为键,我也担心这可能会影响性能.我还能做些什么来实现类似的东西吗?
根据这篇博客文章,HashMap 在已经检索到的哈希码上重新调用它自己的hashCode()(被调用的hash())实现.
如果key不为null,那么它将调用key对象的hashfunction,参见上面方法中的第4行,即key.hashCode(),所以在key.hashCode()返回hashValue之后,第4行看起来像
int hash = hash(hashValue)
现在,它将返回的hashValue应用到自己的散列函数中.
我们可能想知道为什么我们使用hash(hashValue)再次计算hashvalue.答案是,它防御质量差的哈希>函数.
HashMap能否准确地重新分配哈希码?HashMap可以存储对象,但是它无权访问将hashCode分配给其对象的逻辑.例如,hash()无法集成以下hashCode()实现背后的逻辑:
public class Employee {
protected long employeeId;
protected String firstName;
protected String lastName;
public int hashCode(){
return (int) employeeId;
}
}
Run Code Online (Sandbox Code Playgroud) 鉴于这样一个类:
class MyObject {
private String id1;
private String id2;
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof MyObject)) {
return false;
}
MyObject other = (MyObject) o;
return id1.equals(other.id1) || id2.equals(other.id2);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,相等不依赖于两个字段匹配,两个字段都有效.什么是hashCode这个类的合适实现?