Java HashSet与ArrayList

Java HashSet与ArrayList,java,arraylist,collections,set,hashset,Java,Arraylist,Collections,Set,Hashset,因此,我有一个自定义类,将有一组另一个自定义类的学生。所以它看起来像这样: public class Class { private Set<Student> students; // other methods } 公共类{ 私立学校学生; //其他方法 } 现在,我将在学生集合中添加和删除许多学生,并且我还将更改已经在学生集合中的学生的许多私有字段 问题:我应该使用什么数据结构来最好地实现这一点?由于我将更改set Student中Student对象的属性(

因此,我有一个自定义类,将有一组另一个自定义类的学生。所以它看起来像这样:

public class Class {
    private Set<Student> students;

    // other methods
}
公共类{
私立学校学生;
//其他方法
}
现在,我将在学生集合中添加和删除许多学生,并且我还将更改已经在学生集合中的学生的许多私有字段


问题:我应该使用什么数据结构来最好地实现这一点?由于我将更改set Student中Student对象的属性(从而更改hashcodes),是否应改为使用ArrayList?

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

当对象的
等于
方法的结果将更改时,不应使用
集合
。如果您是通过一个稳定的唯一ID号来识别学生,并且
等于
只需检查该ID,那么使用
集合
就可以了


请注意,
HashSet
将使用
hashCode
进行索引和比较,并且
hashCode
应完全包含用于确定
等于的字段。正如你们所说的学生,一定有像id或rollno这样的东西是独一无二的。如果是,则重写hashcode方法,并根据其id实现hashcode。那么更改student的任何其他属性都不会对哈希代码产生影响

选择集合或列表完全取决于您的需求。阅读此链接,它将澄清Set和list之间的区别

如果您在一个集合中使用对象,那么您可以尝试覆盖这两个属性,以便控制唯一性。

注意:如果将可变对象用作集合,则必须非常小心 元素如果 对象的更改方式会影响equals比较,而 对象是集合中的一个元素。这是一种特殊情况 禁止是指不允许集合包含自身 作为一个元素

因此,如果要使用
HashSet
如果将
hashCode()
equals()
设置为基于inmutable字段,则不会出现此问题。例如,为每个实例使用唯一的studentID

我应该使用什么数据结构来最好地实现这一点?既然我将在set Student中更改Student对象的属性(从而更改hashcode),我是否应该改用ArrayList

如果set元素的hashcode可能更改,则不应使用
HashSet
。(如果这样做,数据结构将中断,集合中的元素可能会丢失。)

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

我认为你应该使用
Map
类型,并使用“学生标识符”作为键


(您也可以重写
hashcode
equals
,这样equality意味着两个对象具有相同的id。但这使得
equals(Object)
对于其他用途毫无用处。)

根据您的要求,我认为最好的结构应该是Map。Set实际上使用了内部的映射结构,并且您还需要注意equals方法重写以更好地查找。set和arraylist find目标对象需要采取一些查找算法,因此它的效率不如预期(特别是在非常大的收集情况下)。即使map会浪费一些空间,但是如果您的ID是某种原始类型,则可以在. 问题:我应该使用什么数据结构来最好地实现这一点? 因为我将更改集合中学生对象的属性 学生(因此更改哈希代码)我应该使用ArrayList吗 相反

如果要更改hashCode或equals使用的值,则不可能使用HashMap或HashSet


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

当涉及到
ArrayList
HashSet
的行为时,它们是完全不同的类

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
    确保没有重复项
  • 提供一个
    O(1)
    contains()
    方法,但不保留顺序

                          add      contains next     notes
    HashSet               O(1)     O(1)     O(h/n)   h is the table 
    
  • 非线程安全和t
    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 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