简体   繁体   English

Java哈希图性能

[英]Java Hash Map Performance

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

I have a question in regards to performance of using the above. 我对使用以上内容的性能有疑问。 I am creating a 2D Tile Engine for a simple RPG game. 我正在为一个简单的RPG游戏创建2D Tile Engine。 I am using the hash map above to store the name of a tile along with its respected color code (Ex: 0xff00ff21). 我正在使用上面的哈希图来存储图块的名称及其受尊重的颜色代码(例如:0xff00ff21)。 Since this is a game, the code m.get("name"); 由于这是一个游戏,因此代码m.get("name"); is called an enormous amount of times to check if a tile is updated or not. 被称为检查瓦片是否被更新的大量时间。 (Ex: The render method with my computer runs at about 850 times per second). (例如:我的计算机上的render方法每秒运行约850次)。 Please also note, I made sure to declare the HashMap outside of any loops and that it is initialized via a method call(also static) through the constructor that m.put("name", value) inputs all the information. 还请注意,我确保在任何循环之外声明HashMap,并通过m.put("name", value)输入所有信息的构造函数通过方法调用(也是静态的)对其进行初始化。

1) Is using a HashMap in this way a good idea? 1)以这种方式使用HashMap是个好主意吗? Is there perhaps another way to go about this more efficiently. 是否有另一种方法可以更有效地进行此操作。

2) Is using a static final implementation of a hashMap good practice? 2)使用hashMap的静态最终实现是一种好习惯吗? The values will never change and the values used will be needed within the super class and its sub classes (Hence the "protected"). 这些值永远不会改变,并且在超类及其子类中将需要使用这些值(因此称为“受保护”)。 Can I set the key and value variables to final as well? 是否可以将键和值变量设置为final?

3) I understand that HashMap doesn't allow for duplicate keys, but from tinkering around with the HashMap, by inputting two of the same keys it simply replaces the older key and value with the newest .put("name", value); 3)我知道HashMap不允许重复的键,但是通过修改HashMap,通过输入两个相同的键,它只是用最新的.put("name", value);替换了旧的键和值.put("name", value); Is there to a way to throw an error perhaps if you try to .put("water", 0xff00ff21) and .put("water", 0xff221133) and/or .put("water",0xff00ff21) 如果您尝试输入.put("water", 0xff00ff21).put("water", 0xff221133)和/或.put("water",0xff00ff21)有没有办法抛出错误?

Thank you for your time. 感谢您的时间。 New to this community and looking forward to helping/getting helped. 这个社区的新成员,期待获得帮助。

Please note that it is bad to ask three questions in one post. 请注意,一次发三个问题很不好。

1) IMO, yes. 1)海事组织,是的。 I usually use a HashMap for this kind of things. 我通常将HashMap用于此类事情。 This can clarify things a lot better and enhance the readability of your code. 这样可以更好地阐明事物,并增强代码的可读性。 Just imagine if you you only use hex color values for these kinda things, I think a lot of people would ask you what is 0xff221133 and what is 0xff00ff21. 试想一下,如果您仅将十六进制颜色值用于这些用途,我想很多人会问您什么是0xff221133和什么是0xff00ff21。

2) Yes it is! 2)是的! static final is used when you want to declare some kind of constant. 当您要声明某种常量时,使用static final However, declaring a hash map as static final doesn't mean that its content cannot be changed. 但是,将哈希映射声明为static final并不意味着不能更改其内容。 To prevent this, encapsulate the map in a class and only provide get methods: 为避免这种情况,请将地图封装在一个类中,仅提供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) If you look at the docs, specifically, Hashmap<>.put , you will see that: 3)如果查看文档,特别是Hashmap<>.put ,您将看到:

Returns: the previous value associated with key, or null if there was no mapping for key. 返回:与键关联的先前值;如果没有键的映射关系,则返回null。 (A null return can also indicate that the map previously associated null with key.) (返回null可能还表明该映射先前将null与key关联。)

So you can add a method that put something into the map and will throw an exception if the key is a duplicate by checking whether the returned value is null. 因此,可以通过检查返回的值是否为null来添加一种方法,该方法put某些内容放入映射中,如果键重复,则将引发异常。

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

1) I'm not sure I understand what you're doing here, but how many different kinds of tiles could you be using here? 1)我不确定自己在这里做什么,但您在这里可以使用多少种瓷砖? You might be better off just defining a Tile object with a few constant Tiles that you can just reuse again and again by referring to Tile.WATER, etc instead of doing a hashtable lookup. 您最好定义一个带有一些恒定Tiles的Tile对象,您可以通过引用Tile.WATER等来一次又一次地重用它们,而不用进行哈希表查找。 If water has multiple colors just put them all in the water Tile object and pick from amongst them. 如果水有多种颜色,只需将它们全部放入水瓷砖对象中,然后从其中选择即可。

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

2) Making a hashmap instance static and final doesn't make it immutable. 2)将hashmap实例设为静态和final不会使其不变。 The contents can still be updated. 内容仍然可以更新。 There's no performance benefit anyway. 无论如何都没有性能上的好处。 A read only hashmap wouldn't be any faster than a writable one. 只读哈希图不会比可写哈希图快。 If you don't want it updated, just don't update it. 如果您不希望对其进行更新,请不要对其进行更新。 It's your code, it's not like it's going to write to the hashmap when you aren't looking. 这是您的代码,而不是在不查找时将其写入哈希映射。

3) You could subclass hashmap and make it not accept duplicate keys, but again, I'm not sure what the purpose of this is- why aren't you sure what colors your tiles will be at run time? 3)您可以将hashmap子类化,使其不接受重复的键,但是同样,我不确定这样做的目的是什么-为什么不确定瓦片在运行时将是什么颜色? This strikes me as the kind of thing decided before compile time. 这让我印象深刻,因为在编译之前就已经决定了这种事情。

  1. Using HashMap should be efficient enough. 使用HashMap应该足够有效。 Is there more efficient way? 有没有更有效的方法? Of course there will always be but whether it is appropriate depends on your design. 当然总会有,但是是否合适取决于您的设计。 For example, if tiles are statically defined, you may use enum/integer constants to represent a tile (instead of using "name"), and your tile-to-XXX mapping can be easily expressed as ArrayList or even array. 例如,如果图块是静态定义的,则可以使用枚举/整数常量来表示图块(而不是使用“名称”),并且您的图块到XXX的映射可以轻松地表示为ArrayList或什至数组。 (Again, it may not be appropriate to your design). (同样,它可能不适合您的设计)。

  2. Again it depends on the design. 再次取决于设计。 Are the class containing the map something that is going to instantiate multiple times but you really want each instance to share same mapping? 包含映射的类是否要实例化多次,但您确实希望每个实例共享相同的映射吗? Are you going to give flexibility to the child class to set up the mapping? 您是否要灵活地给子类设置映射? It is only meaningful to make it static if first answer is YES and second is NO. 仅当第一个答案为是,第二个答案为否时,将其设置为static才有意义。

    To avoid change of content for the map, you can wrap it in a unmodifiable map: 为避免更改地图内容,可以将其包装在不可修改的地图中:

     // 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. If you are using Java 8+, it may be better to use Map#merge() method, and have the remapping function throw an exception you desire. 如果您使用的是Java 8+,则最好使用Map#merge()方法,并让重映射函数抛出您想要的异常。 Compared with the approach given by other answers, using merge() is safer as original value won't be mistakenly replaced. 与其他答案给出的方法相比,使用merge()更安全,因为不会错误地替换原始值。 You may also selectively throw the exception if the new value is different from existing value. 如果新值与现有值不同,您也可以有选择地引发异常。

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

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