我正在HashMap
中保存库存对象,其中键是代码符号String
(例如Apple,Inc。的"AAPL"
)。不幸的是,这是不可行的,因为Ally Financial Inc(GM1)和Global Partners LP(GLP)有冲突的哈希码,并且会相互覆盖。例如:"GM1".hashCode() == "GLP".hashCode()
==主要问题。
股票代码字符串是否有hashCode
可以保证不会发生冲突?
public Class StockTicker {
public String symbol;
public StockTicker(String symbol) { this.symbol = symbol; }
@Override
public int hashCode() {
// What goes here?
}
}
成功的答案可能会利用自动收报机字符串不超过5个字符的事实,并且将是大写字母数字,但“。”除外。如“BRK.B”。
答案 0 :(得分:4)
我认为关键字符串的hashCode对地图本身没有任何影响(我假设您使用密钥的实际股票代码字符串,而不是哈希代码;如果您插入地图使用哈希码,然后是,这将导致问题)。我跑了一个快速测试,运行正常。
private Map<String, String> stockMap = new HashMap<String, String>();
@Test
public void mapTest() {
stockMap.put("GM1", "gm1stock");
stockMap.put("GLP", "glpstock");
assertEquals(2, stockMap.size());
}
就像Mshnik所说,Java会为你处理碰撞,所以你不需要担心。你能详细说明具体导致你问题的代码吗?
答案 1 :(得分:2)
正如其他答案和评论所指出的那样,A)Java将正确处理冲突,假设您以一种令人愉快的方式编写了equals和hashcode,并且B)即使获得完美的哈希码函数并不能保证您不会得到碰撞。
据说,可以为您的规范编写完美的哈希码函数。您需要担心的是37个字符(26个字母,10个数字和.
),小于64.因此我们可以使用6位来表示每个字符。您最多有5
个字符,这意味着您的哈希码最多需要30位,这符合int。
这是一个创建完美哈希码的实现:
public static class Stock{
// The possible characters of a stock - note length is < 64
private final static String alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.";
//Will be 6 for given valid chars, but coding it like this prevents bugs later
private final static int shiftAmnt = (int)(Math.log(alphaNumeric.length()) / Math.log(2)) + 1;
private String stock;
public Stock(String s) {
stock = s;
}
@Override
public boolean equals(Object o) {
return o instanceof Stock && stock.equals( ((Stock)o).stock);
}
@Override
public int hashCode() {
int code = 0;
for (char c : stock.toCharArray()) {
code = code << shiftAmnt;
code += alphaNumeric.indexOf(c);
}
return code;
}
}