Collection。需要说明的是它的无序性、不可重复性、计算hash值时的方法以及判断重复性时的方法。
得到的结果是无序且元素是不可重复的:
这里判断字符串对象是否重复的方法是先调用String的hashcode()进行判断,如果相同,再调用String的equals()方法。其中String的hashcode()方法在计算hash值时,是根据每个字符计算的,相同字符位置处的相同字符运算结果相同。
所以上面几个字符串对象中,前缀"abcd"子串部分的hash运算结果相同,最后一个字符决定了这些字符串对象是否相同。插入时有两个"abcd1",所以总共调用了一次String的equals()方法。
如果是存储自定义的对象,如Student对象,该对象定义方式如下:
即使重写了equals(),插入属性相同的Student对象到HashSet中时,也会认为不重复的。
结果:
这是因为HastSet集合的底层首先调用Student的hashcode()方法,而Student没有重写该方法,而是继承自Object,所以每个对象的hashcode()都不相同而直接插入到集合中。
因此,需要重写Student的hashcode()方法。以下是一种重写方法:
如果不加上"age*31",那么name部分的hash值有可能是相同的,但这很可能不是同一Student对象,所以应该加上age属性作为计算hash值的一部分元素。但不能直接加age,因为这样会导致"new Student("lisi3",23)"和"new Student("lisi2",24)"的hashcode相同(3+23=2+24),因此需要为age做一些修改,例如乘一个非0和1的整数。
在Student中重写hashCode()后,再插入下面这些Student对象,就能相对精确地判断是否为同一个Student元素。
结果:
链表顺序的HashSet集合,相比HashSet,只需多记录一个链表索引即可,这就使得它保证了存储顺序和插入顺序相同。实现方式除了new对象时和HashSet不一样,其他任何地方都是一样的。
结果:
TreeSet集合以二叉树数据结构存储元素。二叉树保证了元素之间是排过序且相互唯一的,因此实现TreeSet集合最核心的地方在于对象之间的比较。
比较对象有两种方式:一是在对象类中实现Comparable接口重写compareTo()方法;二是定义一个专门用于对象比较的比较器,实现这个比较器的方法是实现Comparator接口并重写compare()方法。其中Comparable接口提供的比较方法称为自然顺序,例如字母按照字典顺序,数值按照数值大小顺序。
无论是哪种方式,每个待插入的元素都需要先转型为Comparable,确定了将要存储在二叉树上的节点位置后,然后再转型为Object存储到集合中。