我与使用3.4版的Apache Commons Lang HashCodeBuilder发生冲突。我正在哈希一个Route对象,其中包含两个Cell对象,即开始和结束。最后,我提供了一个发生冲突时的示例。这两个类都覆盖hashCode和equals方法。首先是Cell类:
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Cell {
private int east;
private int south;
public Cell(int east, int south) {
this.east = east;
this.south = south;
}
public int getEast() {
return east;
}
public void setEast(int east) {
this.east = east;
}
public int getSouth() {
return south;
}
public void setSouth(int south) {
this.south = south;
}
@Override
/**
* Compute hash code by using Apache Commons Lang HashCodeBuilder.
*/
public int hashCode() {
return new HashCodeBuilder(17, 31)
.append(this.south)
.append(this.east)
.toHashCode();
}
@Override
/**
* Compute equals by using Apache Commons Lang EqualsBuilder.
*/
public boolean equals(Object obj) {
if (!(obj instanceof Cell))
return false;
if (obj == this)
return true;
Cell cell = (Cell) obj;
return new EqualsBuilder()
.append(this.south, cell.south)
.append(this.east, cell.east)
.isEquals();
}
}
和Route类:
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.*;
public class Route {
private Cell startCell;
private Cell endCell;
public Route(Cell startCell, Cell endCell) {
this.startCell = startCell;
this.endCell = endCell;
}
public Cell getStartCell() {
return startCell;
}
public void setStartCell(Cell startCell) {
this.startCell = startCell;
}
public Cell getEndCell() {
return endCell;
}
public void setEndCell(Cell endCell) {
this.endCell = endCell;
}
@Override
public int hashCode() {
return new HashCodeBuilder(43, 59)
.append(this.startCell)
.append(this.endCell)
.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Route))
return false;
if (obj == this)
return true;
Route route = (Route) obj;
return new EqualsBuilder()
.append(this.startCell, route.startCell)
.append(this.endCell, route.endCell)
.isEquals();
}
}
碰撞示例:
public class Collision {
public static void main(String[] args) {
Route route1 = new Route(new Cell(154, 156), new Cell(154, 156));
Route route2 = new Route(new Cell(153, 156), new Cell(151, 158));
System.out.println(route1.hashCode() + " " + route2.hashCode());
}
}
输出为1429303 1429303。现在,如果将两个类的初始奇数和乘数奇数更改为相同,则此示例不会冲突。但是在HashCodeBuilder的文档中,它明确指定:
必须传递两个随机选择的奇数。理想情况下,每个类的奇数应该不同,但这并不是至关重要的。
理想情况下,如果可能的话,我希望为示例提供完美的哈希函数(内插函数)。
您可能能够通过在生成哈希代码时添加更多参数来更好地分配生成的哈希代码(这与Apache commons库无关)。通过此示例,您可以预先计算该类的一个或多个属性,Route
并在生成哈希码时使用此属性。例如,计算两个Cell
对象之间的直线的斜率:
double slope = (startCell.getEast() - endCell.getEast());
if ( slope == 0 ){//prevent division by 0
slope = startCell.getSouth() - endCell.getSouth();
}else{
slope = (startCell.getSouth() - endCell.getSouth()) / slope;
}
return new HashCodeBuilder(43, 59)
.append(this.startCell)
.append(this.endCell)
.append(slope)
.toHashCode();
用您的示例生成83091911 83088489。或者(或与之一起)使用两个Cell
对象之间的距离:
double length = Math.sqrt(Math.pow(startCell.getSouth() - endCell.getSouth(), 2) + Math.pow(startCell.getEast() - endCell.getEast(), 2));
return new HashCodeBuilder(43, 59)
.append(this.startCell)
.append(this.endCell)
.append(length)
.toHashCode();
与您的示例一起使用的结果为83091911和-486891382。
并测试这是否可以防止碰撞:
List<Cell> cells = new ArrayList<Cell>();
for ( int i = 0; i < 50; i++ ){
for ( int j = 0; j < 50; j++ ){
Cell c = new Cell(i,j);
cells.add(c);
}
}
System.out.println(cells.size() + " cells generated");
System.out.println("Testing " + (cells.size()*cells.size()) + " number of Routes");
Set<Integer> set = new HashSet<Integer>();
int collisions = 0;
for ( int i = 0; i < cells.size(); i++ ){
for ( int j = 0; j < cells.size(); j++ ){
Route r = new Route(cells.get(i), cells.get(j));
if ( set.contains(r.hashCode() ) ){
collisions++;
}
set.add(r.hashCode());
}
}
System.out.println(collisions);
在生成的6,250,000条路线中:
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句