Java 哈希映射性能

Java Hash Map Performance

protected static final Map<String, Integer> m = new HashMap();

我对使用上述内容的性能有疑问。我正在为一个简单的 RPG 游戏创建一个 2D Tile Engine。我使用上面的哈希映射来存储图块的名称及其相关的颜色代码(例如:0xff00ff21)。由于这是一个游戏,代码 m.get("name"); 被调用了很多次来检查一个图块是否更新。 (例如:我电脑的渲染方法每秒运行大约 850 次)。另请注意,我确保在任何循环之外声明 HashMap,并且它是通过 m.put("name", value) 输入所有信息的构造函数的方法调用(也是静态的)初始化的。

1) 以这种方式使用 HashMap 是个好主意吗?是否有另一种方法可以更有效地解决这个问题。

2) 使用 hashMap 的静态最终实现是好的做法吗?这些值永远不会改变,并且在超级 class 及其子 classes 中需要使用的值(因此 "protected")。我也可以将键和值变量设置为 final 吗?

3) 我知道 HashMap 不允许重复的键,但是通过修改 HashMap,通过输入两个相同的键,它只是用最新的键和值替换旧的键和值 .put("name", value);如果您尝试 .put("water", 0xff00ff21).put("water", 0xff221133) and/or .put("water",0xff00ff21)

是否有可能引发错误的方法

感谢您的宝贵时间。这个社区的新手,期待 helping/getting 帮助。

请注意,三个问题一并提出是不好的post。

1) 国际海事组织,是的。对于这种事情,我通常使用 HashMap。这可以更好地阐明事情并增强代码的可读性。想象一下,如果你只对这些东西使用十六进制颜色值,我想很多人会问你什么是 0xff221133 什么是 0xff00ff21。

2) 是的! static final 用于声明某种常量。但是,将散列映射声明为 static final 并不意味着它的内容不能更改。为了防止这种情况,将地图封装在一个class中,只提供get方法:

final class TileColorMap {
    private static final HashMap<String, Integer> tileColorMap = //blah blah blah
    static {
        //Add things to your map here
    }
    public static int get(String key) {
        return tileColorMap.get(key);
    }
}

3) 如果您查看文档,特别是 Hashmap<>.put,您会看到:

Returns: the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)

因此您可以添加一个方法,将 put 某些内容添加到映射中,如果键重复,将通过检查返回值是否为 null 来抛出异常。

private static void putStuffInMap (String key, int value) {
    Integer returnedValue = tileColorMap.put(key, value);
    if (returnedValue != null) {
        throw new RuntimeException("Duplicate Keys!");
    }
}

1) 我不确定我明白你在这里做什么,但是你在这里可以使用多少种不同的瓷砖?您最好只定义一个带有几个常量 Tile 的 Tile 对象,您可以通过引用 Tile.WATER 等来一次又一次地重复使用这些对象,而不是进行哈希表查找。如果水有多种颜色,只需将它们全部放入水 Tile 对象中并从中挑选。

public class Tile
{
    public static final Tile WATER = new Tile(...);
    public static final Tile ROCK = new Tile(...);
}

2) 使 hashmap 实例成为静态的和最终的并不能使它不可变。内容还是可以更新的。无论如何,没有性能优势。只读哈希图不会比可写哈希图快。如果你不想更新它,就不要更新它。这是您的代码,它不会在您不注意时写入哈希图。

3) 您可以将 hashmap 子类化并使其不接受重复的键,但同样,我不确定这样做的目的是什么 - 为什么您不确定您的图块在 [=18 时的颜色=] 时间?这让我觉得这是在编译之前就决定的事情。

  1. 使用HashMap应该足够有效了。有没有更有效的方法?当然总会有,但适不适合取决于你的设计。例如,如果瓦片是静态定义的,您可以使用 enum/integer 常量来表示瓦片(而不是使用 "name"),并且您的 tile-to-XXX 映射可以很容易地表示为 ArrayList 甚至数组。 (同样,它可能不适合您的设计)。

  2. 同样取决于设计。 class 是否包含要实例化多次但您真的希望每个实例共享相同映射的映射?你打算给 child class 设置映射的灵活性吗?如果第一个答案是 YES,第二个答案是 NO,那么让它成为 static 才有意义。

    为避免更改地图内容,您可以将其包装在不可修改的地图中:

    // Access your data through this, so you won't mistakenly modify it
    protected final Map<...> tileColorMap = Collections.unmodifiableMap(getTileColorMap());
    
    // your super class or sub-class is providing the actual map
    protected Map<...> getTileColorMap() {
        Map<...> tileColorMap = new HashMap<>();
        // do your setup
        return tileColorMap;
    }
    
  3. 如果您使用的是 Java 8+,最好使用 Map#merge() 方法,并让重新映射函数抛出您想要的异常。与其他答案给出的方法相比,使用 merge() 更安全,因为不会错误地替换原始值。如果新值与现有值不同,您也可以选择性地抛出异常。