HashSet与ArrayList

时间:2013-08-01 03:57:16

标签: java arraylist collections set hashset

所以我有一个自定义类Class,它将拥有一组另一个自定义类Student。所以它看起来像这样:

public class Class {
    private Set<Student> students;

    // other methods
}

现在我将向学生们添加和删除许多学生,我也将改变已经在学生集中的学生的许多私人领域。

问题:我应该使用哪种数据结构来实现这一目标?由于我将更改set student中的Student对象的属性(从而更改哈希码),我应该使用ArrayList吗?

9 个答案:

答案 0 :(得分:11)

当涉及ArrayListHashSet的行为时,它们是完全不同的类。

的ArrayList

  • ArrayList不验证重复项。
  • get()O(1)
  • contains()O(n),但您可以完全控制条目的顺序。

                          get  add  contains next remove(0) iterator.remove
    ArrayList             O(1) O(1) O(n)     O(1) O(1)      O(1)
    
  • 不是线程安全的并且为了使线程安全,您必须使用Collections.synchronizedList(...)

的HashSet

  • HashSet确保没有重复项。
  • 为您提供O(1) contains()方法,但不保留订单。

                          add      contains next     notes
    HashSet               O(1)     O(1)     O(h/n)   h is the table 
    
  • 不是线程安全的,为了使线程安全,您必须使用Collections.synchronizedSet(...)

答案 1 :(得分:4)

  

我应该使用哪种数据结构来实现这一目标?由于我将更改set student中的Student对象的属性(从而更改哈希码),我应该使用ArrayList吗?

如果set元素的哈希码容易发生变化,那么你就不应该使用HashSet。 (如果这样做,数据结构将会中断,并且集合中的元素可能会丢失。)

但我怀疑你是否应该使用ArrayList,因为如果hashcode()对对象的更改很敏感,那么equals(Object)很可能也是如此。这意味着contains(...)和类似的方法将无法找到对象。

我认为您应该使用Map类型,并使用“学生标识符”作为密钥。

(您也可以覆盖hashcodeequals,以便相等意味着两个对象具有相同的ID。但这使得equals(Object)无法用于其他目的。)

答案 2 :(得分:2)

这取决于。当你在谈论学生时,必须有像id或rollno这样独特的东西。如果是,则覆盖哈希码方法,并根据其ID实现哈希码。然后通过更改学生的任何其他属性对哈希码没有影响。

选择Set或List完全取决于您的要求。阅读此链接,它将阐明Set和列表之间的区别 的 What is the difference between Set and List?

如果您正在使用Set中的对象,那么您可以尝试覆盖 hashcode and the equals method ,以便控制唯一性在您手中。

答案 3 :(得分:2)

如果您的代码中有重复数据,那么您应该使用ArrayList,否则您可以使用hashset,如下所示 因此,如果您的代码不需要重复值,则使用Set而不是list,因为该集合将提供更好的性能(O(n)vs O(n ^ 2)列表),并且&#39;是正常的,因为避免重复是集合的目的。

的ArrayList

public static void main(String [] args){

ArrayList arr =new ArrayList();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr);  //As we are using Arraylist therefore 
                          //the duplicate elements are allowed therefore
                          //"Hello" is not removed in the output

}

HashSet的

public static void main(String [] args){

HashSet arr =new HashSet();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr);  //As we are using Hashset therefore 
                          //the duplicate elements removed therefore
                          //"Hello" is removed in the output

}

答案 4 :(得分:1)

根据您的要求,我认为最好的结构应该是Map。设置实际底层使用内部的Map结构,并且您还需要注意equals方法覆盖以获得更好的查找。并且set和arraylist发现目标对象需要采用一些查找算法,因此效率不如预期(特别是在非常大的收集情况下)。即使map会浪费一些空间,但如果你的ID是某种原始类型,你可以在Trove library中考虑原始类型的地图实现。

答案 5 :(得分:1)

  

问题:我应该使用哪种数据结构来实现这一目标?   因为我将更改集合中Student对象的属性   我应该使用ArrayList来学习(从而改变哈希码)   代替?

当然,如果您要更改hashCode或equals使用的值,则无法使用HashMap或HashSet。

您说要删除并添加很多内容。问题是你是想要顺序地还是随机地(基于索引)。如果你添加,顺序删除,那么肯定最好的选择是LinkedList。如果随机访问对象,则ArrayList效率更高。

答案 6 :(得分:0)

对于散列集合,例如HashSet,密钥应为immutable。 Hashset在内部使用散列来决定存储对象的存储桶。而且在检索对象时,它将使用哈希来查找对象桶。如果在存储后更改对象,则可能会更改对象的哈希码,而Set可能无法检索正确的对象。如果您需要在将对象添加到集合后更改对象,则使用散列集合不是一个好的选择。而是选择Arraylist,但请注意,对于ArrayList,您将失去快速检索所需学生的优势,就像使用Set一样。

答案 7 :(得分:0)

当对象“Set”方法的结果发生变化时,您不应使用equals。如果您使用稳定的唯一ID号识别学生,equals只是检查该ID,那么使用Set就可以了。

请注意,HashSet将使用hashCode进行索引和比较,而hashCode应恰好合并用于确定equals的字段。

答案 8 :(得分:0)

Set的javadoc说

  

注意:如果将可变对象用作set,则必须非常小心   元素。 如果是a的值,则不指定集合的​​行为   对象以影响等于比较的方式改变   对象是集合中的元素。这是一个特殊情况   禁止的是,一套装置不允许包含自己   作为一个元素。

因此,如果您使用不可变字段制作HashSethashCode(),那么您将使用equals(),那么您将不会遇到此问题。例如,为每个实例使用唯一的studentID。