Java 17 Set 接口知识点
思维导图
对于 Set 集合, 它是一个不可包含重复元素的集合。对于添加方法实现了限制重复元素的条件。对于 Set 接口有三个通用的实现, 分别是:
- HashSet:将元素存储在 哈希表 中,是性能最佳的实现。但是它只保证不重复元素, 但是不保证元素的顺序。
- TreeSet:将元素存储在 红黑树 中,根据元素的值对其元素进行排序。
- LinkedHashSet:它是作为哈希表实现的, 其中的实现规则是包含了一个 链表 ,它根据元素插入到集合中的顺序对其元素进行排序。
它的用途包含不限于, 对于包含相同元素的元素集合, 可以消除对应的所有重复项。
Set 接口
接口的定义:
public interface Set<E> extends Collection<E>
通过查看 Set 的 第一手资料 API。地址: java /util/Set.html
可以知道和 Set 接口相关的知识点包含:Collection、HashSet、TreeSet、 Abstract Set、SortedSet。
根据上两篇内容知道, 有抽象类的时候, 已经是因为接口中有些通用的方法可以中间抽出来一层, 不需要所有的都又最下层实现类进行实现。 Collection 详解, 可以参考上面针对 Collection 讲解的知识点。
AbstractSet
接下来, 我们来看看 AbstractSet 抽象类。
抽象类 的定义:
public abstract class AbstractSet<E>
extends AbstractCollection<E>
implements Set<E>
此抽象类, 主要是提供了 Set <E> 接口的实现,在最大程度上减少了实现此接口所需要的工作量。
这里需要注意, 对于 AbstractSet 抽象类并没有重写类中的任何实现, 只是添加了 AbstractCollection 抽象类的 equals、 hashCode 、removeAll 的实现。
方法的含义:
HashSet
现在说说 HashSet 类, 实现了 Set 接口, 并且继承 AbstractSet 抽象类。
类的定义:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
此类的实现是有哈希表支持的接口。 但是内部的实现是使用 HashMap 实现的。该实现不保证迭代的顺序, 也就是说随着使用变化, 顺序不会保持不变。
并且该集合不是同步的, 如果 多线程 访问的情况下, 使用的时候就需要注意需要同步该哈希集合。 否则会出现数据不一致的情况。
可以使用如下代码进行同步使用:
Set sHashSet = Collections. synchronized Set([HashSet集合]);
该类的API 文档如下:
使用案例, 字符串 去重:
再看一个例子。
我们按照顺序插入到 HashSet 集合中的数据, 在读取的时候顺序并不会按照插入的顺序进行读取。 所以想要读取顺序和写入的顺序一致怎么办呢?
LinkedHashSet
这个类是基于哈希表和链表基于 Set 实现的。 并且类继承自 HashSet 类。
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable
该集合同样不是同步的。 异步使用可以使用封装类 Collections。
Set s = Collections.synchronizedSet([LinkedHashSet集合]);
API 文档如下:
重新按照 HashSet 的代码改造如下:
import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetTest {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<>();
for (int i = 10; i < 30; i++) {
set.add(String.valueOf(i));
System.out.print(" " + i);
}
System.out.println();
for (String str : set) {
System.out.print(" " + str);
}
System.out.println();
}
}
该方法可以用于网站的菜单动态展示中, 接口返回按照指定顺序返回菜单数据中。 当然也可以指定用户权限。 不同的应用之间可能存在重复的权限, 对于权限来说有没有必要重复, 所以可以按照这种格式去重就得到了唯一的权限值。 处理一次, 后续都能减少遍历次数。
TreeSet
对于 TreeSet 类实现了 NavigableSet 接口, 并且基于 TreeMap 实现。该集合提供两种排序方式, 默认的情况下按照自然排序, 另外一种方式就是重写 Comparator 进行排序。
定义格式:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
基础代码演示:
上面的代码正常允许, 并且保证了其顺序, 这个时候, 如果传入的数据是个对象。 例如下面的代码:
上面的代码虽然可以正常编译, 但是无法运行。错误信息如下:
这个错误的原因是因为并没有给 MenuInfo 的类重写对应的比较方法。 所以无法转换成对应的比较接口。
修改方式也很简单, 只需要 MenuInfo 实现 Comparable 接口就好了。
class MenuInfo implements Comparable<MenuInfo>{
private String id;
private String name;
public MenuInfo(String id, String name){
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MenuInfo [id=" + id + ", name=" + name + "]";
}
@Override
public int compareTo(MenuInfo o) {
return 0;
}
}
compareTo (Object o) 方法通常有三个返回值: -1、0、1。
分别代表的含义是:
- 1 代表着插入新的元素永远比上一个元素大, 这样读取的时候就是正序的排序了。
- 0 代表着数据相等。 相等的元素集合只会保留一个。 所以集合都等于 0 的情况下该集合只有一条数据了。
- -1 代表着插入的新元素永远比上一个元素小, 这样读取的时候就是倒序的排序了。
演示一下等于 0 的情况。
当等于 1 时,和插入顺序一致。
当等于 -1 式。 插入的顺序是倒序。
以上只是强制的根据插入数据走, 真实的情况是要和当前数据业务匹配的。
compareTo 代码可以修改如下:
public int compareTo(MenuInfo o) {
if(this.id.equals(o.id)){return 0;}
int i = Integer.parseInt(this.id) < Integer.parseInt(o.id) ? 1 : -1 ;
return i;
}
compareTo 也可以用于两个相同类型数据的比较。 比较规则如下:
- 如果指定的数与方法参数相等返回 0。
- 如果指定的数小于方法参数返回 -1。
- 如果指定的数大于方法参数返回 1。
int a = 10;
x.compareTo(3); // 结果为 1
x.compareTo(10);// 结果为 0
x.compareTo(18);// 结果为 -1
最终演示代码如下:
多多理解 compareTo 的概念。 这个在排序的方法中使用很广。
Set 接口和相关的实现, 小案例演示就到这了。 有什么问题, 随时评论区见。
当你纠结学习哪一个 编程语言 好的时候, 其实不防先把其中一个学精通,到达这领域的专家级别,在别的编程语言的学习的时候,就会变得更容易。因为很多知识点都是相同的, 本人是在这方面是走了很多弯路。各种语言的语法记住的挺多。 但是这只是流于表面的。要多学习“ 内核 ”的东西。 一个编程语言学习的是其内核, 除非你一致想做一个高级新手。 加油吧!
点赞,关注, 收藏。 码字不易。 感谢!