事实上,键总是被排序的。如果您将地图输出几次,您会发现结果保持不变。
首先,我将再次八卦散列:
原因是散列。每个对象都有hashCode()
方法。散列空间就像一个大数组,其中包含所有可能的散列值作为索引。当一个新元素插入 aHashSet
或一个新元素对放入 aHashMap
时,根据其哈希码将其放入哈希空间。如果两个元素具有相同的哈希码,则将它们与equals()
方法进行比较,如果不相等,则将新元素放在它旁边。
然后,如果您知道那里发生了什么,您可以实现如下代码:
import java.util.*;
class MyString {
private String str;
public MyString (String str) {
this.str = str;
}
public String toString () {
return str;
}
public boolean equals (Object obj) {
if (obj.getClass().equals(MyString.class)) {
return obj.toString().equals(str);
}
return false;
}
public int hashCode () {
if (str.equalsIgnoreCase("Not Categorized")) {
return Integer.MAX_VALUE;
} else if (str.hashCode() == Integer.MAX_VALUE) {
return 0;
}
return str.hashCode();
}
}
public class Test {
public static void main (String args[]) {
Map<MyString, String> m = new HashMap<MyString, String>();
m.put(new MyString("a"), "a");
m.put(new MyString("c"), "c");
m.put(new MyString("Not Categorized"), "NC");
m.put(new MyString("b"), "b");
Set<MyString> keys = m.keySet();
for (MyString k : keys) {
System.out.println(m.get(k));
}
}
}
结果是“未分类”总是最后出现。原因很简单:它的哈希值总是整数的最大值。
我创建一个 String 包装类的原因是 String 类是最终的,它不能被扩展。所以通过这种方式,你的类结构会有一点改变,但不会太大。
可以使用 TreeMap,但效率会降低:
public static void main (String args[]) {
Map<String, String> m = new TreeMap<String, String>(new Comparator<String>() {
public int compare (String s1, String s2) {
if (s1.equals(s2)) {
return 0;
}
if (s1.equalsIgnoreCase("Not Categorized")) {
return 1;
}
if (s2.equalsIgnoreCase("Not Categorized")) {
return -1;
}
if (s1.hashCode() > s2.hashCode()) {
return 1;
} else if (s1.hashCode() < s2.hashCode()) {
return -1
} else {
return 0;
}
}
public boolean equals (Object obj) {
return false;
}
});
m.put("a", "a");
m.put("c", "c");
m.put("Not Categorized", "NC");
m.put("b", "b");
Set<String> keys = m.keySet();
for (String k : keys) {
System.out.println(m.get(k));
}
}
结果是一样的。它会对所有元素进行排序,但不会改变其他字符串的散列顺序,它只会确保“未分类”始终是最大的。