有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java Hashmap实现中的字符串哈希问题

在做了一段时间的研究并查找了一些旧帖子之后,我意识到,当您在Java中使用以字符串为键的Hashmap或Hashtable时,第一轮哈希将应用于每个字符串对象hashCode(显然有第二个哈希函数应用于int hashCode()的结果),其中默认情况下int hashCode()与它的调用者在内存中的位置(从我读到的内容)有一些关系。话虽如此,如果我有一个带有开发人员定义的键类的映射,我读到我可以重写int hashCode(),并使用对象的一些不同字段为每个对象返回尽可能唯一的int。但是,请考虑下面的代码片段,其中包含基元类型的数组。

import java.util.HashMap;

public class test
{ 

    public static void main(String[] args) { 

        HashMap<char[], int[] > map = new HashMap<char[], int[]>();

        String s = "Hello, World";

        int x[] = { 1, 2, 3, 4, 5 };

        map.put( s.toCharArray(), x );

        x = map.get( s );

        for ( int i : x )
            System.out.print( i );
    } 
}

程序从NullPointerException崩溃当然是因为map.get( s );返回null。我怀疑发生这种情况是因为map.put()map.get()之间有两个不同的引用。我希望程序输出的是123445

我的问题是:如何让上面的代码片段通过键的值与键的引用来查找键?也就是说,如何让程序输出12345

编辑: 我使用hashmap作为查找表。我正在从文件中读取字符串,需要一种快速方法来确定我刚才读取的字符串是否在表中


共 (4) 个答案

  1. # 1 楼答案

    来自Oracle文档

    public V get(Object key)
    
    Returns the value to which the specified key is mapped, or null if this 
    map contains no mapping for the key.
    More formally, if this map contains a mapping from a key k to a value v 
    such that (key==null ? k==null : key.equals(k)), then this method returns v; 
    otherwise it returns null.
    

    显然s.equals(s.toCharArray())是错误的。他们甚至不是同一个阶级

    但是,您可以使用一个类作为键,该类重写equals(),在您的情况下返回true。 例如:

    class MyCharArray {
    
       private char[] data;
    
       @Override
       public boolean equals(Object o) {
           if (o instanceOf String) {
               return data.equals(o.toCharArray);
           else {
               return false;
           }
       }
    
       ...
    }
    
  2. # 2 楼答案

    只需使用字符串作为映射的键

    HashMap<String, int[] > map = new HashMap<String, int[]>();
    String key = "array1";
    int x[] = { 1, 2, 3, 4, 5 };
    map.put( key, x );
    

    字符串是不可变的,因此它是作为映射键的好选择

    添加另一个阵列:

    String key2 = "array2";
    int x2[] = { 6, 7, 8, 9, 10 };
    map.put( key2, x2 );
    

    输出值:

    x = map.get( key );
    for ( int i : x )
        System.out.print( i + " " );
    }
    

    给予

    1 2 3 4 5

    x = map.get( key2 );
    for ( int i : x )
        System.out.print( i + " " );
    }
    

    给予

    6 7 8 9 10

  3. # 3 楼答案

    1. “在某个地方读到有两轮散列”。不,如果你想知道字符串是如何散列的,去看看代码
    2. 散列映射的基本约定是,如果键具有相同的散列并且通过其equals函数相等,则它将检索项。为什么您认为char[]有一个被重写的equals,允许它正确地将自身与字符串进行比较?甚至在彼此之间?它不会覆盖equals,并且仅当它是同一实例时才会返回true
    3. 您正在对键使用数组。这是可能的,但大多数高级开发人员会为此向你大喊大叫。没有比较它们的好方法:对象。等于(默认情况下使用)意味着您无法复制数组-您必须使用完全相同的对象。使用数组。相等(或比较内容的类似方法)将意味着您有可变对象作为键-不好

    根据您的评论,我理解您希望能够编辑字符串。在你把它放到地图上之前没关系。但是当对象是映射中的键时,不要以可能更改哈希代码或相等值的方式更改对象。最好的方法是使用自定义对象。阵列不适用于此

    如果您真的想在映射中动态更改值,请使用BiMap(或者自己执行forcePut中的操作)

  4. # 4 楼答案

    有很多方法可以做到这一点。您可以做的最小更改之一是在调用put()之前只保存char[],并将相同的更改用作get()的参数:

    char[] charArray = s.toCharArray();
    map.put(charArray, x);
    x = map.get(charArray);
    

    这里重要的一点是,您需要使用与put()相同的对象来get()