我知道HashMap 不保证订单。请考虑以下代码:
import java.util.HashMap;
import java.util.Map;
public class SandBox {
protected static class Book {
String name;
public Book(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
protected static class MyThread extends Thread {
@Override
public void run() {
super.run();
final int n = 10;
Book[] books = new Book[n];
for (int i=0; i<n; i++)
books[i] = new Book("b" + i);
for (Book b : books)
System.out.print(b + ", ");
System.out.println();
HashMap<Book, Object> hm = new HashMap<>();
for (Book b : books)
hm.put(b, null);
for (Map.Entry<Book, Object> entry : hm.entrySet())
System.out.print(entry.getKey() + ", ");
System.out.println();
}
}
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
t.join();
}
}
在每次运行中,HashMap的顺序都不同(如预期的那样)。例如:
输出#1:
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9,
b3, b4, b7, b9, b0, b8, b1, b2, b6, b5,
输出#2:
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9,
b9, b4, b3, b7, b8, b0, b1, b5, b6, b2,
但奇怪的是,如果我更换线
t.start();
t.join();
与
t.run();
(不使用多线程)输出始终相同:
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9,
b0, b3, b7, b4, b2, b6, b9, b1, b5, b8,
我不了解HashMap的顺序与Thread之间的关系。有人可以向我解释为什么会发生这种情况吗?
答案 0 :(得分:14)
这是因为内部的MATRIX(@rows, @cols, @valued) = MMULT(TRANSPOSE(SPLIT(REPT(@valued &"|",@rows),"|")),SPLIT(REPT("1|",@cols),"|"))
顺序将取决于哈希码的实现。
您的HashMap
课程未实施Book
因此会使用the default one
尽可能合理实用,由hashCode方法定义 class Object确实为不同的对象返回不同的整数。 (这个 通常通过转换内部地址来实现 将对象转换为整数,但这种实现技术不是 JavaTM编程语言所要求的。)
这意味着它将使用内存地址。
在您的情况下,对于单个线程,重新运行时分配的内存地址是相同的,而在线程版本中则不是这样。
但这只是'偶然'而且即使在单线程中你也不能依赖它(别人会运行它并获得不同的结果, 或者甚至在以后运行它时,您可以获得不同的结果,因为对象将具有不同的内存地址)
在hashCode
中使用对象时,请务必覆盖hashCode
(&amp; equals
}。
答案 1 :(得分:-1)
不是一个答案,而是作为补充:这里是用于插入(put)的代码,在HashMap代码中,TreeNode代码:
/**
* Tie-breaking utility for ordering insertions when equal
* hashCodes and non-comparable. We don't require a total
* order, just a consistent insertion rule to maintain
* equivalence across rebalancings. Tie-breaking further than
* necessary simplifies testing a bit.
*/
static int tieBreakOrder(Object a, Object b) {
int d;
if (a == null || b == null ||
(d = a.getClass().getName().
compareTo(b.getClass().getName())) == 0)
d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
-1 : 1);
return d;
}
正如您所看到的,它依赖于本地的System.identityHashCode
。
在系统中:
/**
* Returns the same hash code for the given object as
* would be returned by the default method hashCode(),
* whether or not the given object's class overrides
* hashCode().
* The hash code for the null reference is zero.
*
* @param x object for which the hashCode is to be calculated
* @return the hashCode
* @since JDK1.1
*/
public static native int identityHashCode(Object x);
另请参阅此答案:How does the JVM ensure that System.identityHashCode() will never change?