JAVA集合框架之Set集合
集合框架
包括一系列的接口和类 存放集合数据
接口继承关系图
Collection
接口 父接口,提供List
、Set
等共同的一些方法,例如:add
、remove
、clear
、iterator
、size
。
Set
接口 包含一组不重复的数据,Set
中数据是无序的,没有下标
List
接口 包含一组有序的数组,List
中的数据都是有下标的,可以包含重复的数据
Queue
接口 ”先进先出“
Deque
接口 ”双端队列“
Map
接口 “键值对” K-V
key
就是键 value
就是值(数据)
实现
Set
接口:
(1)HashSet
(2)TreeSet
(与HashSet
几乎相同,唯一不同是它会对存放的数据进行排序,默认只能存放能排序的数据)
(3)LinkedHashSet
链表 查询速度非常快,但添加和删除慢(不常用)
HashSet:
package com.fyypll.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestHashSet {
public static void main(String[] args) {
// 1. 如何实例化(3种)
// ①
HashSet hs1 = new HashSet(); // 没有泛型,hs1里面就可以存放任意类型的数据,不推荐这种方法
hs1.add("abcd");
hs1.add(123465);
// ②
HashSet<String> hs2 = new HashSet<>();
// ③
// HashSet 实现了Set接口,可以向上转型
Set<String> hs3 = new HashSet<>();
hs3.add("诸葛亮");
hs3.add("刘备");
hs3.add("关羽");
hs3.add("张飞");
hs3.add("刘备");
hs3.add(null); // HashSet中元素可以为null,但也只能有一个空值,重复的会被覆盖
hs3.add(null);
System.out.println(hs3.size()); // 集合中元素的个数
// 打印集合中的全部数据,因为HashSet重写了toString方法
// 所以这里我们可以直接用toString即可打印出HashSet中的元素
System.out.println(hs3.toString());
System.out.println("----------遍历HashSet----------");
// 2.如果要取出hs3中的数据该如何做(2种)
// ①
for(int i=0;i<hs3.size();i++) {
// 这个方法循环遍历是不行的,因为set集合中的数据没有下标,那就没法通过下标取出数据喽
}
// ② 使用增强for,增强for取数据不需要下标哦
for(String s : hs3) {
System.out.println(s);
}
// ③
System.out.println("----------Iterator 迭代器---------");
// 调用HashSet类中的iterator方法获取迭代器
// 迭代器泛型类型跟HashSet(hs3)的泛型类型一致
Iterator<String> iterator = hs3.iterator();
// 使用迭代器
while(iterator.hasNext()) { // hasNext判断迭代器中是否还有数据,如果有,返回true
// next方法从迭代器中取出一个数据(取出的是哪一个我们不知道,因为set数据没有顺序)
// 每取出一个数据,就将该数据从迭代器中删除(所以数据只能拿出来一次,因为一拿出来从迭代器中就删除了)
// 因为迭代器是String类型,所以这里用String类型的s来接收数据
String s = iterator.next();
System.out.println(s);
}
System.out.println("----------删除数据-----------");
// 删除数据
// 因为set中的数据没有下标,所以要删除哪个数据就需要传哪个数据
hs3.remove("刘备");
System.out.println("删除之后:"+hs3.toString());
System.out.println("----------批量操作-----------");
// 批量操作(添加、删除)
// 先创建两个集合,以便后面使用
Set<String> hs4 = new HashSet<>();
hs4.add("三国");
hs4.add("演义");
Set<String> hs5 = new HashSet<>();
hs5.add("关羽");
hs5.add("张飞");
// 批量添加:使用addAll方法添加整个集合hs4到hs3中(即合并两个集合)
hs3.addAll(hs4);
System.out.println("批量添加之后:"+hs3.toString());
// 批量删除:使用removeAll方法将会删除所有hs3中与hs5中相同的数据
// 即hs3中的所有数据,只要是和hs5中的数据相同的,都会被删除
hs3.removeAll(hs5);
System.out.println("批量删除之后:"+hs3.toString());
// 把hs3集合转换为数组
String[] a = hs3.toArray(new String[hs3.size()]);
}
}
HashSet代码运行结果:
5
[关羽, null, 张飞, 刘备, 诸葛亮]
----------遍历HashSet----------
关羽
null
张飞
刘备
诸葛亮
----------Iterator 迭代器---------
关羽
null
张飞
刘备
诸葛亮
----------删除数据-----------
删除之后:[关羽, null, 张飞, 诸葛亮]
----------批量操作-----------
批量添加之后:[关羽, null, 张飞, 诸葛亮, 演义, 三国]
批量删除之后:[null, 诸葛亮, 演义, 三国]
HashSet代码解析:
代码31
行运行结果为5
,set
中的数据是不重复的,所以虽然传入的是7个值,但是输出的元素统计个数为5(输入的值中刘备
和null
重复了)。代码32
行运行结果为[关羽, null, 张飞, 刘备, 诸葛亮]
,输出顺序和我们输入的顺序并不一样,可见set
中的数据是无序的。
注释中说过因为HashSet
将toString
方法重写了,所以我们能直接使用toString
方法将HashSet
中的数据直接打印出来。通过查看JDK
源代码可以找到重写代码如下:
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
这里可以很清楚的看出来,如果数据集里面没有数据,就会直接输出[]
,如果有数据那么就会先输出一个[
然后后面用append
方法将逐个输出的数据拼接起来,直到数据输完然后拼接上]
。
HashSet总结:
HashSet
中:
add
添加元素
remove
删除元素
size()
元素个数
遍历HashSet
使用增强for
或迭代器iterator
。
TreeSet:
package com.fyypll.set;
import java.util.Set;
import java.util.TreeSet;
public class TestTreeSet {
public static void main(String[] args) {
// 实例化方式和HashSet一样,有3种
// ①
TreeSet ts1 = new TreeSet();
// ②
TreeSet<Integer> ts2 = new TreeSet<>();
// ③ 因为TreeSet实现了Set接口,所以可以向上转型
Set<Integer> ts3 = new TreeSet<>();
ts3.add(888);
ts3.add(666);
ts3.add(777);
// toString方法是Object类中的方法
// 因为TreeSet重写了toString方法,所以用toString就能打印出结果
// Integer类型输出结果是从小到大
System.out.println(ts3.toString()); // [666, 777, 888]
Set<String> ts4 = new TreeSet<>();
ts4.add("bbb");
ts4.add("ab");
ts4.add("ccc");
ts4.add("Ddd");
// String类型中字母是按字母顺序排的,字符串长度不一就按首字母排,首字母一样就按第二个字母排
// 大写字母优先排
System.out.println(ts4.toString()); // [Ddd, ab, bbb, ccc]
Set<String> ts5 = new TreeSet<>();
ts5.add("可"); // \u53ef
ts5.add("能"); // \u80fd
ts5.add("是"); // \u662f
// String类型中汉字是按照 Unicode 编码来排序的,首字母都是u,判断第二位,第二位都是数字,
// 按小到大排就是 “\u53ef \u662f \u80fd”,即 “可 是 能”,如果第二位有数字和字母那怎么排?
// 那就按16进制来比大小,即将字母看成数字,然后比大小,即a=10,b=11,c=12,d=13,e=14,f=15
System.out.println(ts5.toString()); // [可, 是, 能]
}
}
TreeSet代码运行结果:
[666, 777, 888]
[Ddd, ab, bbb, ccc]
[可, 是, 能]
TreeSet总结:
与HashSet
几乎相同,唯一不同是它会对存放的数据进行排序,默认只能存放能排序的数据。
本文系作者 @枫雨 原创发布在枫林幻境站点。未经许可,禁止转载。
暂无评论数据