如何在安卓中为字符串输入生成唯一的哈希码?

56

我想为输入的字符串在Android中生成唯一的哈希码。 是否有预定义的库可用或者我们需要手动生成?如果有人知道,请提供一个链接或者代码片段。

我想为在Android中输入的字符串生成唯一的哈希码,是否有预定义的库可用,或者我们需要手动生成?如果有人知道,请提供链接或代码示例。

1
字符串的内置hashCode怎么样? - Mikita Belahlazau
3
唯一哈希码?为什么?你怎么认为这可能是实现的呢? - amal
9
请详细说明。唯一哈希码是不可能的(除非它们可以具有无限长度),因为可能的字符串数是无限的。 - JB Nizet
@ingyhere - 请展示给我们如何... - Stephen C
3
你不知道OP的背景。完全不知道。假设他说“unique”时并不意味着这是一个巨大的挑战。无论如何,挑战依然存在:向我们展示如何做到。 - Stephen C
显示剩余2条评论
8个回答

65

这取决于你的意思:

  • 如先前提到的,String.hashCode() 返回一个32位的哈希码。

  • 如果您想要(比如)一个64位的哈希码,您可以轻松地自己实现它。

  • 如果您想要一个字符串的加密哈希值,Java密码库中包括MD5、SHA-1等实现。通常您需要将字符串转换为字节数组,然后将其提供给哈希生成器/摘要生成器。例如,请参见@Bryan Kemp的回答。

  • 如果您想要一个保证唯一的哈希码,则不会成功。 哈希和哈希码是非唯一的。

长度为N的Java字符串有65536 ^ N种可能的状态,并且需要一个具有16 * N位的整数来表示所有可能的值。 如果编写生成范围较小(例如小于16 * N位)整数的哈希函数,则最终会发现多个字符串散列到相同的整数上;即散列码不能唯一。 这称为鸽洞原理,并且有一个直接的数学证明。 (您不能与数学斗争并赢!)

但是,如果“可能唯一”并具有极小的非唯一性几率是可以接受的,则加密哈希值是一个好答案。 数学将告诉您哈希必须有多大(即需要多少位),才能达到给定(足够低的)非唯一性概率。


64位哈希码:如果需要完整性,可以使用sfussenegger在https://dev59.com/nXI-5IYBdhLWcg3w0MDx中提供的64位哈希码函数。 - Antoni
那么,一个32位的哈希值只能唯一地标识一个包含2个字符的字符串吗? - ADTC
基本上...是的。(假设character == 任意char值。如果character表示Unicode代码点......或(例如)ASCII代码点,则会变得更加复杂。) - Stephen C

38

这是我用来创建消息摘要哈希的类

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Sha1Hex {

    public String makeSHA1Hash(String input)
            throws NoSuchAlgorithmException, UnsupportedEncodingException
        {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            md.reset();
            byte[] buffer = input.getBytes("UTF-8");
            md.update(buffer);
            byte[] digest = md.digest();

            String hexStr = "";
            for (int i = 0; i < digest.length; i++) {
                hexStr +=  Integer.toString( ( digest[i] & 0xff ) + 0x100, 16).substring( 1 );
            }
            return hexStr;
        }
}

9
String input = "some input string";
int hashCode = input.hashCode();
System.out.println("input hash code = " + hashCode);

13
按照定义,没有一个哈希码被定义为唯一的!哈希码需要分布良好,唯一性的想法是提问者理解上的错误。 - bestsss
29
如果哈希码是唯一的,那将是一个极好的压缩算法。 - Jeffrey Blattman
9
尝试一下 "Z@S.ME" 和 "Z@RN.E",当使用 hashCode() 时它们具有相同的哈希值 ;) - Simon
@Simon,刚刚在.NET中运行了你的示例,因为我很好奇。它们肯定使用了不同的基本哈希算法,因为它们并不完全匹配。https://dotnetfiddle.net/6YJRpV - ps2goat
也许 OP 所说的 unique 是指:对于给定的输入字符串是唯一的(不应为相同的字符串生成两个哈希值)。 - Sanjay Verma
@Simon 哇哦,它们相撞了。 - TechWisdom

4

我使用这个作为我的 EhCacheManager 内存映射的键进行测试...

我认为这更加简洁

   /**
     * Return Hash256 of String value
     *
     * @param text
     * @return 
     */
    public static String getHash256(String text) {
        try {
            return org.apache.commons.codec.digest.DigestUtils.sha256Hex(text);
        } catch (Exception ex) {
            Logger.getLogger(HashUtil.class.getName()).log(Level.SEVERE, null, ex);
            return "";
        }
    }

我正在使用Maven,但这是JAR包 commons-codec-1.9.jar

3

对我来说,它起作用了。

   public static long getUniqueLongFromString (String value){
       return  UUID.nameUUIDFromBytes(value.getBytes()).getMostSignificantBits();
    }

3
你可以使用这段代码为给定的字符串生成哈希码。
int hash = 7;
for (int i = 0; i < strlen; i++) {
    hash = hash*31 + charAt(i);
}

3
你为什么选择从7点开始? - Braden Steffaniak

2
几行Java代码。
public static void main(String args[]) throws Exception{
       String str="test string";
       MessageDigest messageDigest=MessageDigest.getInstance("MD5");
       messageDigest.update(str.getBytes(),0,str.length());
       System.out.println("MD5: "+new BigInteger(1,messageDigest.digest()).toString(16));
}

0

让我们来看一下原始的hashCode()方法:

public int hashCode() {
    int h = hash;
    if (h == 0 && count > 0) {
        for (int i = 0; i < count; i++) {
            h = 31 * h + charAt(i);
        }
        hash = h;
    }
    return h;
}

上面的代码块来自java.lang.String类。正如您所看到的,它是一个32位的哈希码,如果您在小规模数据上使用它,那么还算可以。如果您正在寻找超过32位的哈希码,则可能需要查看此链接: http://www.javamex.com/tutorials/collections/strong_hash_code_implementation.shtml

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接