Java 字符串或对象比较的哈希集

Java hashset of strings or objects comparision

我开发了一个 Java 模块,用于检查 JFrame 表单上的任何组件是否已更改其值(文本)并将该组件放入 JFrame 的 HashSet 中。

目前,我在value/text更改时将组件名称(String类型)放入HashSet。

我又想到,如果我将 Object(具有更改值的组件)放入 HashSet 中,认为与使用组件名称(String)相比可能会节省时间。

这里,我的问题是faster/efficent在

之间

总之,也许,哪个更便宜?字符串比较还是对象比较?

谢谢,

JB

插入的便宜不应该是开发阶段的首要问题。 equals 对象的方法通常执行起来并不昂贵。你应该从任何能给你带来最少代码复杂性的东西开始,只有当性能成为一个问题时才开始以效率为目标。此外,除非插入到集合中的项目在 hashcode 上发生冲突,否则甚至不会进行比较。

Martin 的回答是正确的,不要再担心性能了,除非你确定你有一个严重的性能问题,这对你的产品有实际的负面影响。

但要回答问题:

如果您使用 HashSet,那么性能将取决于组件是否实现了 hashCode(),如果实现了,它们的 hashCode() 计算成本是多少。大多数机会是他们甚至没有实现 hashCode(),因此他们的哈希码本质上将是他们的 Identity Hash Codes,(查一下,)所以将对象放在地图中字符串的速度将无限快。我们这里讨论的是时钟周期。

这同样适用于比较:组件可能也没有实现 equals(),因此它们将通过引用进行比较,这将比比较字符串稍微快一些。

如果 "probably" 对你来说不够好,如果你不能查看这些组件的源代码,那么你可以使用 IdentityHashSet 而不是 HashSet,以保证只使用身份哈希码和参考比较。

但谁在乎呢。迄今为止最好的方法是做任何更简单、更容易理解和更易于维护的事情。

刚刚在Java中测试了自己对HashSet元素类型的两种选择。 结果说明了我的一切想法。

HashSet element type: Object, experiment count: 1000, Elapsed time: 16ms
HashSet element type: Object, experiment count: 1000, Elapsed time: 8ms
HashSet element type: Object, experiment count: 1000, Elapsed time: 8ms
HashSet element type: String, experiment count: 1000, Elapsed time: 124ms
HashSet element type: String, experiment count: 1000, Elapsed time: 110ms
HashSet element type: String, experiment count: 1000, Elapsed time: 130ms

要知道,Java的执行速度还是有一些不好的名声的。 您会使用哪种 HashSet 元素类型?

这是显示上述结果的我的代码。

boolean StringUsed = true;

changedComponents = new HashSet<Component>() {};
changedComponentNames = new HashSet<String>() {};

private void changeValueManyTimes() {
    long start = System.currentTimeMillis();

    for (int i = 0; i<count; i++) {
        recordStatisticsCheckBox.setSelected
            (!recordStatisticsCheckBox.isSelected());
    }
    long stop = System.currentTimeMillis();
    System.out.print("HashSet element type: " +
        (StringUsed ? "String" : "Object") + ", experiment count: " + count);
        System.out.println(", Elapsed time: " + (stop - start) + "ms");
        System.out.println("");
}

public static int count = 1000;      
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    StringUsed = false;
    changeValueManyTimes();
}                                        

private void recordStatisticsCheckBoxStateChanged     
    (javax.swing.event.ChangeEvent evt) {                                                      
    recordStatisticsCheckBoxActionPerformed(null);
}                                                     

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    StringUsed = true;
    changeValueManyTimes();        
}    

private void recordStatisticsCheckBoxActionPerformed 
    (java.awt.event.ActionEvent evt) {                                                         
    if (StringUsed) {
        if (recordStatisticsCheckBox.isSelected() == origSelection) {
            changedComponents.remove(recordStatisticsCheckBox);
        } else {
            changedComponents.add(recordStatisticsCheckBox);     
        }
        changeSaveEnabledIfNeeded();
    } else {
        if (recordStatisticsCheckBox.isSelected() == origSelection) {
           changedComponentNames.remove(recordStatisticsCheckBox.getName());
        } else {
           changedComponentNames.add(recordStatisticsCheckBox.getName());     
        }
        changeSaveEnabledIfNeeded();
    }
}

private void changeSaveEnabledIfNeeded() {
    if (changedComponents.size() == 0)
        saveButton.setEnabled(false);
    else
        saveButton.setEnabled(true);    
}