java - List上hashCode()的JVM优化

标签 java list optimization hash jvm

想象一个简单的例子:

class B{
    public final String text;
    public B(String text){
        this.text = text;
    }
}

class A {
    private List<B> bs = new ArrayList<B>;

    public B getB(String text){
        for(B b :bs){
           if(b.text.equals(text)){
               return b;
           }
        }
        return null;
    }

    [getter/setter]
}

假设对于 A 的每个实例,List<B>,我们需要调用getB(String) 经常。但是,假设列表也有可能发生变化(添加/删除元素,甚至重新分配)。

在这个阶段,getB(String) 的平均复杂度是 O(n)。为了改进这一点,我想知道我们是否可以使用一些巧妙的缓存。

假设我们缓存 List<B>Map<String, B>关键是 B.text .这会提高性能,但如果列表发生更改(新元素或删除元素)或重新分配(A.bs 指向新引用),它将不起作用。

为了解决我认为的问题,以及 Map<String, B> ,我们可以存储列表的散列 bs .当我们调用 getB(String)方法,我们计算列表的散列 bs .如果哈希没有改变,我们从 map 中获取结果,如果改变了,我们重新加载 map 。

问题是计算 java.util.List 的哈希值遍历列表的所有元素并计算它们的哈希值,这至少是 O(n)。

问题

我想知道的是,JVM 计算 List 的哈希值是否会比我在 getB(String) 中的循环更快方法。可能这取决于 B 的哈希实现.如果是这样,什么样的事情可以工作?简而言之,我想知道这是否愚蠢或可以带来一些性能改进。

最佳答案

没有实际解释原因,您似乎出于某种原因相信保持列表结构也很重要。这样做的唯一合理原因是您需要集合的顺序保持一致。如果切换到“普通” map ,值的顺序将不再恒定,例如按照您将项目添加到 map 的顺序保存。

如果您需要保持顺序(列表行为)使用键访问单个项目,您可以使用 LinkedHashMap,它本质上加入了一个行为LinkedList 和一个 HashMap。即使 LinkedHashMap.values() 返回一个集合而不是一个列表,列表的行为在集合中也得到保证。

您的问题的另一个问题是,您不能使用列表的哈希码来安全地确定更改。如果散列码发生了变化,您确实可以确定列表也发生了变化。如果两个哈希码相同,您仍然不能确定列表实际上是否相同。例如。如果哈希码实现基于字符串,则“1a”和“2B”的哈希码相同。

关于java - List上hashCode()的JVM优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16191731/

相关文章:

C++ 模板优化

java - @Async 在 REST 类中不起作用

Java Swing - 禁用 JCheckbox 时出现问题

java - 如何使用selenium/java切换到新的弹出窗口

ruby-on-rails-3 - Rails 列出过去 24 小时内创建/更新的记录

swift 数组 'contains' 功能就地优化

java - 保存到字符串/从字符串加载时如何处理空列表?

python - 如何根据另一个变量的值调用列表中的元素?

html - 列表样式 - 使用计数器时的第二行缩进

java - 是Java -XX :+UseParNewGC garbage collection option still buggy?