目录
庖丁解牛术法总纲
第一重境界:所见莫非全牛者
1、概述:
2、Set集合特点:
3、分类(实现子类):
?4、所有已知实现类:
?5、注意事项
?6、所有方法
第二重境界:未尝见全牛也
HashSet
1、HashSet特点:
2、HashSet集合添加一个元素的过程:
3、代码演示
?4、注意事项(特殊之处,遍历无序的原因不是排序的无序,而是底层哈希值的存放地址的原因)
5、LinkedHashSet集合概述和特点
TreeSet
1、TreeSet集合特点
2、注意事项
3、代码展示(比较器排序)
第三重境界:官知止而神欲行
1、哈希值(hashCode)
概念:
特点:
代码展示:
2、哈希表
概念:
哈希表的实现:
哈希表的优缺点:
哈希表的学习:
庖丁解牛术法总纲
? ? ? ?吾生也有涯,而知也无涯 。以有涯随无涯,殆已!已而为知者,殆而已矣!为善无近名,为恶无近刑。缘督以为经,可以保身,可以全生,可以养亲,可以尽年。
? ? ? ?“庖丁为文惠君解牛,手之所触,肩之所倚,足之所履,膝之所踦,砉然向然,奏刀騞然,莫不中音。合于《桑林》之舞,乃中《经首》之会。
? ? ? ?文惠君曰:“嘻,善哉!技盖至此乎?”
? ? ? ?庖丁释刀对曰:“臣之所好者,道也,进乎技矣。始臣之解牛之时,所见无非牛者。三年之后,未尝见全牛也。方今之时,臣以神遇而不以目视,官知止而神欲行。依乎天理,批大郤,导大窾,因其固然,技经肯綮之未尝,而况大軱乎!良庖岁更刀,割也;族庖月更刀,折也。今臣之刀十九年矣,所解数千牛矣,而刀刃若新发于硎。彼节者有间,而刀刃者无厚;以无厚入有间,恢恢乎其于游刃必有余地矣,是以十九年而刀刃若新发于硎。虽然,每至于族,吾见其难为,怵然为戒,视为止,行为迟。动刀甚微,謋然已解,如土委地。提刀而立,为之四顾,为之踌躇满志,善刀而藏之。”
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ——《庄子·养生主》
呔,妖怪。看法宝!
第一重境界:所见莫非全牛者
1、概述:
? ? ? ?Set集合类似于一个罐子,程序可以依次把多个对象“丢进”Set集合,而Set集合通常不能记住元素的添加顺序。实际上Set就是Collection,只是行为略有不同(Set不允许包含重复元素)。 ? ? ? ?Set集合不允许包含相同的元素,如果试图把两个相同元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。
2、Set集合特点:
(1)、不包含重复元素的集合
(2)、没有带索引的方法,所以不能使用普通for循环遍历
3、分类(实现子类):
(1)、HashSet
(2)、TreeSet
?4、所有已知实现类:
?5、注意事项
不包含重复元素的集合。 更正式地,集合不包含一对元素e1 和e2 ,使得e1.equals(e2) ,并且最多只有一个空元素。 正如其名称所暗示的那样,这个接口模拟了数学集抽象。
该Set 接口放置额外的约定,超过从继承Collection 接口,所有构造函数的合同,而位于该合同add , equals 和hashCode 方法。 其他继承方法的声明也包括在这里以方便。 (这些声明中附带的规格已针对Set 接口进行了定制,但不包含任何其他规定。)
构造函数的额外规定并不奇怪,所有构造函数都必须创建一个不包含重复元素的集合(如上所定义)。
注意:如果可变对象用作设置元素,则必须非常小心。 如果对象的值以影响equals 比较的方式更改,而对象是集合中的元素,则不指定集合的行为。 这种禁止的一个特殊情况是,一个集合不允许将其本身作为一个元素。
一些集合实现对它们可能包含的元素有限制。 例如,一些实现禁止空元素,有些实现对元素的类型有限制。 尝试添加不合格元素会引发未经检查的异常,通常为NullPointerException 或ClassCastException 。 尝试查询不合格元素的存在可能会引发异常,或者可能只是返回false; 一些实现将展现出前者的行为,一些实现将展现出后者。 更一般来说,尝试对不符合条件的元素的操作,其完成不会导致不合格元素插入到集合中,可能会导致异常,或者可能会成功执行该选项。 此异常在此接口的规范中标记为“可选”。
?6、所有方法
-
-
Modifier and Type | 方法 | 描述 |
---|
boolean | add?(E?e) | 如果指定的元素不存在,则将其指定的元素添加(可选操作)。 |
---|
boolean | addAll?(Collection<? extends E>?c) | 将指定集合中的所有元素添加到此集合(如果尚未存在)(可选操作)。 |
---|
void | clear?() | 从此集合中删除所有元素(可选操作)。 |
---|
boolean | contains?(Object?o) | 如果此集合包含指定的元素,则返回 true 。 |
---|
boolean | containsAll?(Collection<?>?c) | 如果此集合包含指定集合的所有元素,则返回 true 。 |
---|
boolean | equals?(Object?o) | 将指定的对象与此集合进行比较以实现相等。 |
---|
int | hashCode?() | 返回此集合的哈希码值。 |
---|
boolean | isEmpty?() | 如果此集合不包含元素,则返回 true 。 |
---|
Iterator<E> | iterator?() | 返回此集合中元素的迭代器。 |
---|
static <E>?Set<E> | of?() | 返回一个包含零个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1) | 返回一个包含一个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E...?elements) | 返回一个包含任意数量元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2) | 返回一个包含两个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3) | 返回一个包含三个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3, E?e4) | 返回一个包含四个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3, E?e4, E?e5) | 返回一个包含五个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3, E?e4, E?e5, E?e6) | 返回一个包含六个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3, E?e4, E?e5, E?e6, E?e7) | 返回一个包含七个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3, E?e4, E?e5, E?e6, E?e7, E?e8) | 返回一个包含八个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3, E?e4, E?e5, E?e6, E?e7, E?e8, E?e9) | 返回一个包含九个元素的不可变集合。 |
---|
static <E>?Set<E> | of?(E?e1, E?e2, E?e3, E?e4, E?e5, E?e6, E?e7, E?e8, E?e9, E?e10) | 返回一个包含十个元素的不可变集合。 |
---|
boolean | remove?(Object?o) | 如果存在,则从该集合中删除指定的元素(可选操作)。 |
---|
boolean | removeAll?(Collection<?>?c) | 从此集合中删除指定集合中包含的所有元素(可选操作)。 |
---|
boolean | retainAll?(Collection<?>?c) | 仅保留该集合中包含在指定集合中的元素(可选操作)。 |
---|
int | size?() | 返回此集合中的元素数(其基数)。 |
---|
default Spliterator<E> | spliterator?() | 在此集合中的元素上创建一个 Spliterator 。 |
---|
Object[] | toArray?() | 返回一个包含此集合中所有元素的数组。 |
---|
<T>?T[] | toArray?(T[]?a) | 返回一个包含此集合中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。 |
---|
第二重境界:未尝见全牛也
HashSet
1、HashSet特点:
(1)底层数据结构是哈希表(查询速度快),使用HashCode哈希值
(2)对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
(3)没有带索引的方法,所以不能使用普通for循环遍历
(4)由于是Set集合,所以是不包含重复元素的集合
2、HashSet集合添加一个元素的过程:
?? ???
3、代码演示
package SetDemo;
import java.util.HashSet;
public class Set01 {
public static void main(String[] args) {
//导包创建对象HashSet
HashSet<String> set=new HashSet<String>();
//添加数据
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ddd");
//增强for循环遍历
for (String i:set){
System.out.println(i);
}
}
}
//代码输出结果
E:\develop\JDK\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition
aaa
ccc
bbb
ddd
Process finished with exit code 0
?4、注意事项(特殊之处,遍历无序的原因不是排序的无序,而是底层哈希值的存放地址的原因)
public static void main(String[] args) {
HashSet<String> set=new HashSet<String>();
set.add("hello");
set.add("world");
set.add("java");
//集合自带排序方式
System.out.println(set);
System.out.println("--------");
//迭代器方式
Iterator<String> it = set.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("--------");
//增强for循环
for (String s:set){
System.out.println(s);
}
}
//输出结果
[world, java, hello]
--------
world
java
hello
--------
world
java
hello
Process finished with exit code 0
?上述代码是正常输出的结果,但是以下的代码的输出,请看:
public static void main(String[] args) {
HashSet<String> set=new HashSet<String>();
set.add("6");
set.add("7");
set.add("8");
set.add("9");
set.add("10");
//集合自带排序方式
System.out.println(set);
System.out.println("--------");
//迭代器方式
Iterator<String> it = set.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("--------");
//增强for循环
for (String s:set){
System.out.println(s);
}
}
//代码输出结果
[6, 7, 8, 9, 10]
--------
6
7
8
9
10
--------
6
7
8
9
10
Process finished with exit code 0
public static void main(String[] args) {
HashSet<String> set=new HashSet<String>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e");
//集合自带排序方式
System.out.println(set);
System.out.println("--------");
//迭代器方式
Iterator<String> it = set.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("--------");
//增强for循环
for (String s:set){
System.out.println(s);
}
}
//代码输出结果
[a, b, c, d, e]
--------
a
b
c
d
e
--------
a
b
c
d
e
Process finished with exit code 0
上述两则代码结果,可以看到输出结果都是有序的,而HashSet特点有一,就是不保证迭代顺序。这不就是矛盾的一处地方吗?
原因:但并不是HashSet的自相矛盾,其原因就是底层实现的特点。哈希表实现,计算哈希值,通过哈希值代替索引的作用,查询存储的值。
而哈希值的计算,有一套自己的计算规则,当一串字符串计算哈希值时,哈希值的区别也许会很大,但如果是有规律的数字、字符进行计算哈希值时,其哈希值有会时有序的。
表现出来的结果就是在控制台输出有顺序有规律的单节字符时,输出也是有规律的。
5、LinkedHashSet集合概述和特点
(1)集合特点:
哈希表和链表实现的Set接口,具有可预测的迭代顺序。
由链表保证元素有序,也就是说元素的存储和取出顺序是一致的。
由哈希表保证元素唯一,也就是说没有重复的元素。
(2)代码案例
TreeSet
1、TreeSet集合特点
(1)元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法 ?? ?TreeSet?():根据其元素的自然排序进行排序 ?? ?TreeSet?(Comparator<? super E> comparator) :根据指定的比较器进行排序
(2)没有带索引的方法,所以不能使用普通for循环遍历
(3)由于是Set集合,所以不包含重复元素的集合
2、注意事项
用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
?自然排序,就是让元素所属的类实现Comparable接口,重写compareTo?(T o)方法 ?? ?重点:如何重写方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写 ?? ?重点:主要条件与次要条件
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
?比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare?(T o1,T o2)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
3、代码展示(比较器排序)
package SetDemo;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class Set003 {
public static void main(String[] args) {
Set<News> set=new TreeSet<News>(new Comparator<News>() {
@Override
public int compare(News n1, News n2) {
int num=n1.getTitle().compareTo(n2.getTitle());
return num;
}
});
News news1=new News("中国多地遭雾霾笼罩空气质量再成热议话题");
News news2=new News("民进党台北举行“火大游行”");
News news3=new News("春节临近北京“卖房热”");
News news4=new News("春节临近北京“卖房热”");
System.out.println("新闻一与新闻二的比较:"+news1.equals(news2));
System.out.println("新闻三与新闻四的比较:"+news3.equals(news4));
System.out.println("--------");
set.add(news1);
set.add(news2);
set.add(news3);
set.add(news4);
for (int i = 0; i < set.size(); i++) {
}
Set<News> set1=new HashSet<News>();
set1.addAll(set);
for (News n:set1){
System.out.println(n);
}
System.out.println("--------");
System.out.println("集合中新闻的长度为:"+set1.size());
}
}
第三重境界:官知止而神欲行
1、哈希值(hashCode)
概念:
? ? ? ?是Jdk根据对象的地址/String/数字算出来一串数字(int),hashCode()是Object类的方法,所以说Java的对象都可以调用这个hashCode方法返回哈希值。
特点:
? ? ? ?(1)如果自定义类没有重写hashCode方法,那么自定义类的对象生成的哈希值是根据对象的内存地址值生成的,所以说即便两个对象的属性一样,哈希值也不一样。 ? ? ? ?(2)诉求:如果两个对象属性一样,那么两个对象哈希值也要一样,所以在自定义的类中重写了? ? ? hashCode方法(不调用Object类hashCode),是根据对象的属性生成哈希值。 ? ? ? ?(3)两个对象哈希值一样,不代表两个对象的属性一样.两个对象的属性一样,则两个对象的哈希值肯定一样。 ? ? ? ?(4)数字的哈希值是它本身。
代码展示:
public static void main(String[] args) {
//创建学生类对象,实例化
Student s1 = new Student02("盘古大神", 100, 100, 100,300);
Student s2 = new Student02("女娲娘娘", 100, 95, 90,285);
Student s3 = new Student02("天皇伏羲", 98, 100, 90,288);
Student s4 = new Student02("地皇神农", 99, 95, 90,284);
Student s5 = new Student02("人皇轩辕", 95, 98, 80,273);
//输出哈希值
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s4.hashCode());
System.out.println(s5.hashCode());
}
//输出结果
356573597
1735600054
21685669
2133927002
1836019240
Process finished with exit code 0
2、哈希表
概念:
散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。
哈希表的实现:
实现哈希表我们可以采用两种方法:
1、数组+链表
2、数组+二叉树
哈希表的优缺点:
优点:
- 无论数据有多少,处理起来都特别的快
- 能够快速地进行?
插入修改元素 ?、删除元素 ?、查找元素 ?等操作 - 代码简单(其实只需要把哈希函数写好,之后的代码就很简单了)
缺点:
- 哈希表中的数据是没有顺序的
- 数据不允许重复
哈希表的学习:
如果大家想再深入学习哈希表的知识,下附链接:
数据结构 Hash表(哈希表)_积跬步 至千里-CSDN博客_哈希表
?ending!!!!!
|