根据许多值创建唯一的hashCode

时间:2019-01-07 12:08:58

标签: java algorithm math hash hashcode

我正在尝试基于六个不同的值来实现唯一的hashCode。我的班级具有以下属性:

private int id_place;
private String algorithm;
private Date mission_date;
private int mission_hour;
private int x;
private int y;

我正在按以下方式计算hashCode:

id_place * (7 * algorithm.hashCode()) + (31 * mission_date.hashCode()) + (23 * mission_hour + 89089) + (x * 19 + 67067) + (y * 11 + 97097);

如何将其转换为唯一的hashCode?我不确定这是独一无二的...

5 个答案:

答案 0 :(得分:3)

它不必唯一,也可以唯一。 if (callType == OUTGOING_CALL_END || callType == INCOMING_CALL_END) { Cursor cursorCallLogs = getRecentCallLogs(context.getContentResolver()); if (cursorCallLogs != null) { cursorCallLogs.moveToLast(); do { try { String callNumber = cursorCallLogs.getString(cursorCallLogs.getColumnIndex("number")); callNumber = utilS.getPhoneNumber(callNumber); utilS.log("Phone NUmber", callNumber); duration = (cursorCallLogs.getInt(cursorCallLogs.getColumnIndex("duration")) * 1000); utilS.log("durationCall", "" + duration); } catch (Exception e) { e.printStackTrace(); } } while (cursorCallLogs.moveToPrevious()); } } public static Cursor getRecentCallLogs(ContentResolver cr) { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) { return null; } else { return cr.query(CallLog.Calls.CONTENT_URI, null, null, null, android.provider.CallLog.Calls.DATE + " DESC limit 1"); } } 返回一个hashCode()(32位),这意味着如果您只有一个int属性,而没有其他属性,则它可能是唯一的。

int类可以(并且确实)具有唯一的Integer,但是很少有其他类。

由于您具有多个属性,其中一些是hashCode(),所以作为这些属性的函数的int不能是唯一的。

您应该争取一个hashCode()函数,该函数可以为您的属性的不同组合提供各种不同的值,但是它不能唯一。

答案 1 :(得分:1)

两个不同对象的HashCode不必唯一。根据{{​​3}}-

  1. 在Java应用程序执行期间,只要在同一对象上多次调用 ,hashCode()必须始终返回相同的值 ,前提是不使用任何信息在equals上比较对象。从一个应用程序的执行到同一应用程序的另一次执行,该值不必保持一致
  2. 如果根据equals(Object)方法两个对象相等,则在两个对象中的每个对象上调用hashCode()方法必须产生相同的值。
  3. 如果根据equals(java.lang.Object)方法,如果两个对象不相等,则不需要在两个对象中的每个对象上调用hashCode方法必须产生不同的整数结果 。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

因此,您不必创建每次都返回不同哈希码的hashCode()函数。

答案 2 :(得分:1)

Unique is not a hard requirement, but the more unique the hash code is, the better.

Note first that the hash code in general is used for a HashMap, as index into a 'bucket.' Hence optimally it should be unique modulo the bucket size, the number of slots in the bucket. However this may vary, when the map grows.

But okay, towards an optimal hash code:

  • Ranges are important; if x and y where in 0..255, then they could be packed uniquely in two bytes, or when 0..999 then y*1000+x. For LocalDateTime, if one could take the long in seconds (i.o. ms or ns), and since 2012-01-01 so you might assume a range from 0 upto say two years in the future.
  • You can explore existing or generate plausible test data. One then can mathematically optimize your hash code function by their coincidental coefficients (7, 13, 23). This is linear optimisation, but one can also do it by simple trial-and-error: counting the clashes for varying (A, B, C).

    //int[] coeffients = ...;
    int[][] coefficientsCandidates = new int[NUM_OF_CANDIDATES][NUM_OF_COEFFS];
    ...
    int[] collisionCounts = new int[NUM_OF_CANDIDATES];
    for (Data data : allTestData) {
        ... update collisionCounts for every candidate
    }
    ... take the candidate with smallest collision count
    ... or sort by collisionCounts and pick other candidates to try out
    

In general such evaluation code is not needed for a working hash code, but especially it might detect bad hash codes, were there is some pseudo-randomness going wrong. For instance if a factor is way too large for the range (weekday * 1000), so value holes appear.

But also one has to say in all honesty, that all this effort probably really is not needed.

答案 3 :(得分:0)

在Eclipse中,有一个函数可以为您生成方法public int hashCode()。我使用了您提供的类属性,结果如下:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((algorithm == null) ? 0 : algorithm.hashCode());
    result = prime * result + id_place;
    result = prime * result + ((mission_date == null) ? 0 : mission_date.hashCode());
    result = prime * result + mission_hour;
    result = prime * result + x;
    result = prime * result + y;
    return result;
}

它看起来很像您的计算。但是,正如安迪·特纳(Andy Turner)在对问题的评论中指出的,而伊兰在回答中指出的那样,如果对象的每个实例的数量超过了可能的不同哈希码的最大数量,则无法简单地为其创建唯一的哈希码。

答案 4 :(得分:0)

由于您有多个字段,请使用:

public int hashCode() {
    return Objects.hash(id_place, algorithm, mission_date, mission_hour, x, y);
}

如果objA.equals(objB)为true,则objA和objB必须返回相同的哈希码。 如果objA.equals(objB)为false,则objA和objB可能返回相同的哈希码,如果在这种情况下您的哈希算法碰巧返回了不同的hashCode,则出于性能方面的考虑。

 public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    ClassA classA = (ClassA) o;
    return id_place == classA.id_place &&
            mission_hour == classA.mission_hour &&
            x == classA.x &&
            y == classA.y &&
            Objects.equals(algorithm, classA.algorithm) &&
            Objects.equals(mission_date, classA.mission_date);
}