java基础集合类之set

时间:2023-02-15 10:01:30

Set也是Collection的一种扩展,而与List不同的时,在Set中的对象元素不能重复。Set的常用具体实现有HashSet和TreeSet类。

一、HashSet和TreeSet类的区别

HashSet能快速定位一个元素,但是你放到HashSet中的对象需要实现hashCode()方法,它使用了哈希码的算法。而TreeSet则将放入其中的元素按序存放,这就要求你放入其中的对象是可排序的,这就用到了集合框架提供的另外两个实用类Comparable和Comparator。一个类是可排序的,它就应该实现Comparable接口。有时多个类具有相同的排序算法,那就不需要在每分别重复定义相同的排序算法,只要实现Comparator接口即可。集合框架中还有两个很实用的公用类:Collections和Arrays。Collections提供了对一个Collection容器进行诸如排序、复制、查找和填充等一些非常有用 的方法,Arrays则是对一个数组进行类似的操作。

二、Comparable接口和Comparator接口

在“集合框架”中有两种比较接口:Comparable接口和Comparator接口。像String和Integer等Java内建类实现Comparable接口以提供一定排序方式,但这样只能实现该接口一次。对于那些没有实现Comparable接口的类、或者自定义的类,你可以通过Comparator接口来定义您自己的比较方式。

1.Comparable接口:

int compareTo(Object o): 比较当前实例对象与对象o,如果位于对象o之前,返回负值,如果两个对象在排序中位置相同,则返回0,如果位于对象o后面,则返回正值。
JDK中实现了Comparable接口的类的排序方式

(1)按数字大小排序:BigDecimal,BigInteger,Byte, Double, Float,Integer,Long,Short

(2)按 Unicode 值的数字大小排序:Character

(3)按字符串中字符 Unicode 值排序:String
利用Comparable接口创建您自己的类的排序顺序,需要实现compareTo()方法。通常就是依赖几个数据成员的自然排序。同时类也应该覆盖equals()和hashCode()以确保两个相等的对象返回同一个哈希码。

2.Comparator接口:

若一个类不能用于实现java.lang.Comparable,或者不需要缺省的Comparable行为并想提供自己的排序顺序(可能多种排序方式),你可以实现Comparator接口,从而定义一个比较器。

(1)int compare(Object o1, Object o2): 对两个对象o1和o2进行比较,如果o1位于o2的前面,则返回负值,如果在排序顺序中认为o1和o2是相同的,返回0,如果o1位于o2的后面,则返回正值
注释:与Comparable相似,0返回值不表示元素相等。一个0返回值只是表示两个对象排在同一位置。由Comparator用户决定如何处理。如果两个不相等的元素比较的结果为零,您首先应该确信那就是您要的结果,然后记录行为。

(2)boolean equals(Object obj): 指示对象obj是否和比较器相等。
注释:该方法覆写Object的equals()方法,检查的是Comparator实现的等同性,不是处于比较状态下的对象。

三、SortedSet接口

1.集合框架提供了个特殊的Set接口:SortedSet,它保持元素的有序顺序。SortedSet接口为集的视图(子集)和它的两端(即头和尾) 提供了访问方法。当您处理列表的子集时,更改视图会反映到源集。此外,更改源集也会反映在子集上。发生这种情况的原因在于视图由两端的元素而不是下标元素 指定,所以如果您想要一个特殊的高端元素(toElement)在子集中,您必须找到下一个元素。
添加到SortedSet实现类的元素必须实现Comparable接口,否则您必须给它的构造函数提供一个Comparator接口的实现。TreeSet类是它的唯一一份实现。

2.因为集必须包含唯一的项,如果添加元素时比较两个元素导致了0返回值(通过Comparable的compareTo()方法或Comparator 的compare()方法),那么新元素就没有添加进去。如果两个元素相等,那还好。但如果它们不相等的话,您接下来就应该修改比较方法,让比较方法和 equals() 的效果一致。

3.常用函数:

(1) Comparator comparator(): 返回对元素进行排序时使用的比较器,如果使用Comparable接口的compareTo()方法对元素进行比较,则返回null

(2) Object first(): 返回有序集合中第一个(最低)元素

(3) Object last(): 返回有序集合中最后一个(最高)元素

(4)SortedSet subSet(Object fromElement, Object toElement): 返回从fromElement(包括)至toElement(不包括)范围内元素的SortedSet视图(子集)

(5) SortedSet headSet(Object toElement): 返回SortedSet的一个视图,其内各元素皆小于toElement

(6) SortedSet tailSet(Object fromElement): 返回SortedSet的一个视图,其内各元素皆大于或等于fromElement

四、AbstractSet抽象类

AbstractSet类覆盖了Object类的equals()和hashCode()方法,以确保两个相等的集返回相同的哈希码。若两个集大小相等 且包含相同元素,则这两个集相等。按定义,集的哈希码是集中元素哈希码的总和。因此,不论集的内部顺序如何,两个相等的集会有相同的哈希码。

五、Set有关类的常用函数

1.HashSet的常用函数:

(1)HashSet(): 构建一个空的哈希集

(2)HashSet(Collection c): 构建一个哈希集,并且添加集合c中所有元素

(3)HashSet(int initialCapacity): 构建一个拥有特定容量的空哈希集

(4)HashSet(int initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空哈希集。LoadFactor是0.0至1.0之间的一个数

2.TreeSet的常用函数:

(1)TreeSet():构建一个空的树集

(2)TreeSet(Collection c): 构建一个树集,并且添加集合c中所有元素

(3)TreeSet(Comparator c): 构建一个树集,并且使用特定的比较器对其元素进行排序

(4)TreeSet(SortedSet s): 构建一个树集,添加有序集合s中所有元素,并且使用与有序集合s相同的比较器排序

3.LinkedHashSet的常用函数

(1) LinkedHashSet(): 构建一个空的链接式哈希集

(2) LinkedHashSet(Collection c): 构建一个链接式哈希集,并且添加集合c中所有元素

(3) LinkedHashSet(int initialCapacity): 构建一个拥有特定容量的空链接式哈希集

(4) LinkedHashSet(int initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空链接式哈希集。LoadFactor是0.0至1.0之间的一个数

六、Hash表简介

1.Hash表是一种数据结构,用来查找对象。Hash表为每个对象计算出一个整数,称为Hash Code(哈希码)。Hash表是个链接式列表的阵列。每个列表称为一个buckets(哈希表元)。对象位置的计算index = HashCode % buckets (HashCode为对象哈希码,buckets为哈希表元总数)。

2.当你添加元素时,有时你会遇到已经填充了元素的哈希表元,这种情况称为Hash Collisions(哈希冲突)。这时,你必须判断该元素是否已经存在于该哈希表中。

3.如果哈希码是合理地随机分布的,并且哈希表元的数量足够大,那么哈希冲突的数量就会减少。同时,你也可以通过设定一个初始的哈希表元数量来更好地控制哈 希表的运行。初始哈希表元的数量为buckets = size * 150% + 1 (size为预期元素的数量)。

如果哈希 表中的元素放得太满,就必须进行rehashing(再哈希)。再哈希使哈希表元数增倍,并将原有的对象重新导入新的哈希表元中,而原始的哈希表元被删 除。load factor(加载因子)决定何时要对哈希表进行再哈希。在Java编程语言中,加载因子默认值为0.75,默认哈希表元为101。