简体   繁体   English

我的Java Hashmap实现问题

[英]Problems with my implementation of a Java Hashmap

After doing research and looking up old posts for a while I realize that when you use a Hashmap or Hashtable in Java where Strings are the keys, the first "round" of hashing is applied to each String objects hashCode (apparently there is a second hash function that is applied to the result of int hashCode() ), where by default int hashCode() has some relationship with it's callers location in memory (from what I read). 经过研究并查找了一段时间后,我意识到当您在Java中使用Hashmap或Hashtable(其中Strings为键)时,哈希的第一个“回合”将应用于每个String对象hashCode(显然存在第二个hash应用于int hashCode()的结果的函数,默认情况下int hashCode()与它在内存中的调用者位置有一些关系(根据我的阅读)。 With that being said, if I had a map with a developer defined class for keys, I read that I can override int hashCode() and use some distinct field(s) of my object to return the most unique int possible for each object. 话虽如此,如果我有一个带有开发人员定义的键类的映射,我读到可以覆盖int hashCode()并使用对象的某些不同字段来为每个对象返回最唯一的int。 However, consider the code fragment below that contains arrays of primitive types. 但是,请考虑下面的代码片段,其中包含原始类型的数组。

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 );
    } 
}

The program crashes from a NullPointerException of course because map.get( s ); 当然,由于map.get( s );程序从NullPointerException崩溃map.get( s ); returns null. 返回null。 I suspect that has happened because there are two different references between map.put() and map.get() . 我怀疑发生了这种情况,因为map.put()map.get()之间有两个不同的引用。 What I want the program to output is 1 2 3 4 5. 我想要程序输出的是1 2 3 4 5。

My question: How can I get the above code fragment to look up the keys by the value of the key vs the reference of the key? 我的问题:如何获取上面的代码片段以通过键的值与键的引用来查找键? That is, how can I get the program to output 1 2 3 4 5? 也就是说,如何使程序输出1 2 3 4 5?

Edit: I am using the hashmap as a look up table. 编辑:我正在使用哈希表作为查找表。 I am reading strings from a file and need a fast way to determine if the string I just read in is in the table or not. 我正在从文件中读取字符串,并且需要一种快速的方法来确定我刚刚读入的字符串是否在表中。

Just use the String as the key for the map. 只需将String用作地图的键即可。

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

String is immutable so it is good choice as the key for a map. 字符串是不可变的,因此它是映射键的不错选择。

Adding another array: 添加另一个数组:

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

Outputting values: 输出值:

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

gives

1 2 3 4 5 1 2 3 4 5

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

gives

6 7 8 9 10 6 7 8 9 10

  1. "Read somewhere that there are 2 rounds of hashing". “在某处读取有2轮哈希值”。 No. If you want to see how Strings are hashed - go look at the code. 否。如果您想查看字符串的哈希方式-请查看代码。
  2. The basic contract of hash map is that it will retrieve items if the keys have the same hash and are equal by their equals function. 哈希映射的基本约定是,如果键具有相同的哈希并且由其equals函数相等,则它将检索项目。 Why do you think that char[] has an overridden equals that allows it to compare itself with Strings properly? 您为什么认为char[]有一个覆盖的equals ,可以使其与Strings正确比较? Or even between each other? 甚至彼此之间? It does not override equals, and will only return true if it's the same instance. 没有重载equals,如果它是同一个实例只会返回true。
  3. You are using arrays for keys. 您正在使用数组作为键。 That is possible but most senior devs will shout at you for that. 这是可能的,但是大多数高级开发人员会为此大喊大叫。 There is no good way to compare them: Object.equals (that they use by default) means you cannot reproduce an array - you have to use the exact same object . 没有比较它们的好方法:Object.equals(默认情况下使用)意味着您无法复制数组-您必须使用完全相同的object Using Arrays.equals (or similar means to compare contents) will mean you have mutable objects as keys - BAD . 使用Arrays.equals(或类似的方式比较内容)将意味着您具有可变对象作为键-BAD

As per your comment I understand that you want to be able to edit the string. 根据您的评论,我了解您希望能够编辑字符串。 That's fine before you put it into the map. 在您将其放入地图之前没关系。 But do not change objects when they are keys in a map in a way that might change the hash code or equals. 但是当对象是映射中的键时, 请勿以可能更改哈希码或等于值的方式更改对象。 Best way to do this is to use a custom object. 最好的方法是使用自定义对象。 Arrays are not suitable for this. 数组不适用于此。

If you really want to change the values on the fly while they're in a map - use a BiMap (or do what it does in forcePut yourself). 如果您真的想在地图中实时更改值,请使用BiMap (或BiMap执行forcePut )。

There are many ways to do this. 有很多方法可以做到这一点。 One of the smallest changes you can do is to simply save your char[] before calling put() , and use the same one as argument to get() : 您可以做的最小更改之一是在调用put()之前简单地保存char[] ,并将相同的参数用作get()参数:

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

The important thing here is that you need to use the same object to get() as you used to put() . 这里重要的是,您需要使用与put()相同的对象来get() put()

From Oracle Documentation 从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.

and obviously s.equals(s.toCharArray()) is false. 显然s.equals(s.toCharArray())是错误的。 They are not even the same Class. 他们甚至不是同一类。

However, you could use as key a Class that overrides equals() in a way that returns true for your case. 但是,您可以使用以返回true的方式重写equals()的Class作为键。 For example: 例如:

class MyCharArray {

   private char[] data;

   @Override
   public boolean equals(Object o) {
       if (o instanceOf String) {
           return data.equals(o.toCharArray);
       else {
           return false;
       }
   }

   ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM