Java中的集合类
1、HashSet
1.1、HashSet的简介
HashSet集合和之前介绍的ArrayList集合和LinkedList集合有共同之处,相同之处在于:HashSet集合也是进行单值存储的集合,因此该集合的顶级父接口也是:Collection接口,此外该集合还继承了AbstractSet类和实现了这些接口:Serializable接口,Cloneable接口,Iterable接口、Set接口,使用该集合时需要进行导包操作,需要导入的包名为:java.util.HashSet。
当然HashSet集合也有自己的特点,该集合的特点在于:HashSet集合不允许存储相同的元素,而且HashSet集合存储元素时默认是无序存储(即:存取的顺序不同)。HashSet存在这种特点与它的底层实现原理有关,下面我就来介绍该集合的底层实现原理。
1.2、HashSet的底层实现原理
该集合的底层实现原理是基于HashMap集合的支持,HashMap集合先不去深入了解,文章结尾有关于HashMap集合的相关博文链接,感性趣的读者可点击了解,这里就先简单知道:HashSet集合进行元素存储依赖的是HashMap集合中键的存储,而同时很重要的一点是:这两个集合的实现结构都是基于哈希表这一结构。
哈希表的底层结构相当于一个可变数组结构里的每一个下标空间都存放着一个链表结构,之所以会有这样的结构取决于:哈希表在存储元素时会计算每个新元素相应的哈希值,该哈希值代表着这个新元素存放在数组中的哪一个下标位置,如果该下标有旧元素则新旧元素之间会先进行equals方法的比较,在HashSet集合中进行equals方法比较后,相等时则舍弃新元素,保留旧元素;不相等则将新元素放在旧元素的下一个节点处,如果该节点也存放着旧元素,依次执行上述的操作,直到新元素被舍弃或存入集合为止,这就形成了链表结构。除此在外,当某一下标位置中的链表的节点数大于8时,该链表会自动转化成红黑树,相反如果某一下标位置中的红黑树的节点数小于8时,红黑树又会自动转化成链表,
此外可变数组这一特点取决于加载因子值(构造方法中会提及),当数组中存放元素的下标数占数组的总容量的百分数等于加载因子的百分数时,数组就会自动进行扩容,并且会重新计算里面元素的哈希值,让里面的元素进行新的排列存储。
从上面的哈希表的结构的原理,就反应了HashSet集合不可以存储相同元素(由equals方法的使用造成)和存取顺序不同的特点(由哈希值的运算、链表结构和哈希表的散列共同造成)。介绍完HashSet集合的底层实现原理,下面来介绍HashSet集合可以执行的操作和对应的方法。
1.3、HashSet的操作方法
1.3.1、构造方法
首先要了解HashSet集合如何创建,即该集合的构造方法。该集合有四种构造方法,格式如下:
- HashSet()
- HashSet(int initialCapacity)
- HashSet(int initialCapacity, float loadFactor)
- HashSet(Collection<? extends E> c)
第一种方法的作用是:构造一个新的空HashSet集合,具有默认初始容量(16)和加载因子(0.75)。
第二种方法的作用是:构造一个新的空HashSet集合,具有指定的初始容量(initialCapacity该参数的值)和默认加载因子(0.75)。
第三种方法的作用是:构造一个新的空HashSet集合,具有指定的初始容量(initialCapacity该参数的值)和指定的加载因子(loadFactor该参数的值)。
第四种方法的作用是:构造一个包含指定集合(该集合实现了Collection接口)中元素的新HashSet集合。
注意:加载因子的值不宜过大或过小,过大会造成数组散列困难,从而使数组中存放了大量的元素,不宜数据的操作,而过小会造成数组散列频繁,从而造成内存空间的浪费。因此加载因子设为默认值(0.75)是效率最高的。
以下是Java代码书写格式
//方法一 注意:尖括号里可以是任何一种类型,不过必须是包装类
HashSet<Integer> set = new HashSet<>();
//方法二
HashSet<Integer> set1 = new HashSet<>(20);
//方法三
HashSet<Integer> set2 = new HashSet<Integer>(20,0.8f);
//方法四
HashSet<Integer> set3 = new HashSet<>(new ArrayList<Integer>());
介绍完HashSet集合的构造方法,下面来介绍该集合可以实现的功能和对应的方法。
1.3.2、add方法
该方法使用后会有一个boolean类型的返回值,使用方法时传入一个参数,该参数的类型与你创建集合时尖括号内声明的类型一致,参数代表的就是你要存储的元素,方法的作用是:将你指定的元素添加进HashSet集合中,添加成功返回true,添加失败返回false。添加失败的原因是:该集合不允许存储相同元素。格式如下:
- boolean add(E e)
以下是具体的Java代码:
public class Test {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(1);
set.add(10);
set.add(20);
set.add(36);
if(set.add(1)){
System.out.println("添加成功!");
}else {
System.out.println("该集合已存在该元素,添加失败!");
}
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()){
Integer i = iterator.next();
System.out.println("该元素为:"+i);
}
}
}
以下是效果图:
从效果图和代码对比来看,该集合不允许存储相同元素和数据的存取顺序不同这两个特点都体现出来了,而且在代码中我还使用了其他的方法:iterator方法,下面就来介绍iterator方法。 。
1.3.3、iterator方法
该方法使用后会返回一个迭代器(iterator),使用时无需传入任何参数。使用方法后获得的迭代器的作用是:可以让迭代器对象调用 iterator 类中的方法(next方法)获取迭代器指针所对应的元素,从而进行HashSet集合元素的遍历,格式如下:
- Iterator< E> iterator()
注意:使用迭代器进行集合元素遍历时,在while循环的循环条件中要先判断迭代器的下一个指针是否存在(即集合中是否还有元素存在)。
具体的Java代码和效果图就不具体演示了,参照上面的add方法的代码即可。
1.3.4、size方法
该方法使用后会有一个int类型的返回值,使用时无需传入任何参数,方法的作用是:获取集合中元素的数量。格式如下:
- int size()
具体的Java代码如下:
public class Test1 {
public static void main(String[] args) {
HashSet<Integer> set =new HashSet<>();
set.add(10);
set.add(25);
set.add(36);
set.add(72);
set.add(102);
System.out.println("该集合中的元素有:"+set.size()+"个");
}
}
效果图如下:
1.3.5、contains方法
使用该方法后会有一个boolean的返回值,使用时传入一个Object类型的参数,该参数代表:你指定的元素,该方法的作用是:判断集合中是否包含你指定的元素,包含返回true,不包含返回false。格式如下
- boolean contains(Object o)
以下是具体的Java代码:
public class Test2 {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(52);
set.add(30);
set.add(25);
set.add(15);
set.add(13);
if(set.contains(13)){
System.out.println("集合中包含元素13");
}else {
System.out.println("集合中不包含元素13");
}
if(set.contains(26)){
System.out.println("集合中包含元素26");
}else {
System.out.println("集合中不包含元素26");
}
}
}
以下是效果图:
从代码中可以看到集合中包含元素13,所以if-else语句执行的是if结构中的代码,而集合中不包含元素26,所以if-else语句执行的是else结构中的代码。
1.3.6、remove方法
使用该方法后会有一个boolean的返回值,使用时传入一个Object类型的参数,该参数代表:你指定的元素,该方法的作用是:删除集合中你指定的元素,如果删除成功返回true,不成功返回false。格式如下:
- boolean remove(Object o)
具体的Java代码如下:
public class Test3 {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(16);
set.add(19);
set.add(21);
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println("删除前集合中的元素为:"+iterator.next());
}
System.out.println("===================");
if(set.remove(16)){
System.out.println("元素16删除成功!");
}else {
System.out.println("元素16删除失败!");
}
if(set.remove(25)){
System.out.println("元素25删除成功!");
}else {
System.out.println("元素25删除失败!");
}
Iterator<Integer> iterator1 = set.iterator();
while (iterator1.hasNext()){
System.out.println("删除后集合中的元素为:"+iterator1.next());
}
}
}
以下是效果图:
从代码中可以看到集合中包含元素16,所以if-else语句执行的是if结构中的代码,而集合中不包含元素25,所以if-else语句执行的是else结构中的代码,而且执行删除方法成功后集合中就不存在被删除的元素16了。
1.3.7、clear方法
该方法使用后没有返回值,使用时也无需传入任何参数,方法的作用是:清空集合中的所有元素,让集合为空。格式如下:
- void clear()
具体的Java代码如下:
public class Text4 {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(56);
set.add(12);
set.add(36);
set.add(47);
if(set.isEmpty()){
System.out.println("使用clear方法前该集合为空");
}else {
System.out.println("使用clear方法前该集合不为空");
}
set.clear();
if(set.isEmpty()){
System.out.println("使用clear方法后该集合为空");
}else {
System.out.println("使用clear方法后该集合不为空");
}
}
}
以下是效果图:
从代码和效果图可以很清楚的看到clear方法的执行结果,而且在代码中我还使用了其他的方法:isEmpty方法,下面就来介绍isEmpty方法。
1.3.8、isEmpty方法
使用该方法后会有一个boolean类型的返回值,使用时无需传入任何参数,方法的作用是:判断集合是否为空,为空返回true,不为空返回false。格式如下:
- boolean isEmpty()
具体的Java代码和效果图就不演示了,参照上面的clear方法的代码即可。
关于HashSet集合的相关的常用知识就介绍到这,想了解更多的小伙伴可以自行百度,希望文章可以给你们带来收获,谢谢阅读。有对Java中其他集合感兴趣的读者可以点击下面的博文链接进行了解。
相关博文,点击即可阅读:
“Java中的集合类:ArrayList”、
“Java中的集合类:LinkedList”
“Java中的集合类:HashMap”