单列集合Collection
- 红色的是接口,蓝色的是实现类
- Vector已经淘汰了
- List系列集合:添加的元素是有序(存和取出来的元素是一样的)、可重复、有索引
- Set系列集合:添加的元素是无序、不重复、无索引
Collection中基本方法
package collectiondemo;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo1 {
public static void main(String[] args) {
Collection是一个接口,不能直接创建它的对象
所以我们学习他的方法时,只能创建它实现类的对象。如ArrayList
Collection<String> coll = new ArrayList<>();
这样利用多态创建对象是为了学习其中的方法,正常情况下直接用以前方法创建就行
//1.添加元素
//往List系列添加元素永远返回true
//由于Set系列不允许重复,所以有可能返回false
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
System.out.println(coll);//[aaa, bbb, ccc]
//2.清空集合
//coll.clear();
//3.删除元素
//因为Collection里面定义的是共性的方法,但是Set系列没有索引,所以只能通过元素的对象删除
coll.remove("aaa");
System.out.println(coll);//[bbb, ccc]
4.判断集合中是否包含给定对象
底层依赖equals方法判断是都存在,所以如果集合中存储的是自定义对象,也想通过contains方法判断是否包含,要重写equals方法。
对于 String 类型:String 类已经重写了 equals 方法,比较的是内容
对于自定义对象:如果没有重写 equals 方法,默认比较的是内存地址
Boolean flag = coll.contains("aaa");
System.out.println(flag);//false
flag = coll.contains("bbb");
System.out.println(flag);//true
//5.判断集合是否为空
flag = coll.isEmpty();
System.out.println(flag);//false
//6.获取集合的长度
int len = coll.size();
System.out.println(len);//2
}
}
Colection的遍历方式
- 普通的for循环用不了,因为Set系列没有索引,而Collection要包含两者共性。
迭代器遍历
- 迭代器不依赖索引
- 如果迭代器指向集合最后+1的位置,在使用next方法会报NoSuchElementException
- 迭代器遍历完毕,指针不会复位
- 循环中只能使用一次next方法
package collectiondemo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
//迭代器遍历
//1.创建集合并添加元素
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
//2.使用集合对象去调用iterator方法获取迭代器对象
//迭代器就好比是一个箭头,默认指向集合的0索引处
Iterator<String> it = coll.iterator();
//3.利用循环不断的获取每一个元素
//next方法不仅获取元素,而且还移动指针(迭代器)
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
}
}
- 迭代器遍历时,不能用集合的方法进行增加或删除,如果实在要删除,可以用迭代器的remove方法,但是如果想添加,是没有办法的。
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String s = it.next();
if("A".equals(s)) {
list.remove("A"); // ❌ 并发修改异常!
// 正确做法:使用迭代器的remove方法
it.remove(); // ✅
}
}
增强for遍历
Lambada表达式遍历
package collectiondemo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class LambdaDemo {
public static void main(String[] args) {
//1.定义一个集合
Collection<String> coll = new ArrayList<>();
//2.添加一些元素
coll.add("xzx");
coll.add("xs");
coll.add("xss");
//3.使用匿名内部类的形式
coll.forEach(new Consumer<String>(){
@Override
public void accept(String t) {
System.out.println(t);
}
});
//4.使用Lambda简化匿名内部类
coll.forEach((String t)->{
System.out.println(t);
});
//5.根据Lambda简化规则继续简化
coll.forEach(t -> System.out.println(t));
//Idea自动简化
coll.forEach(System.out::println);
}
}
List集合的特有方法
- 在删除的时候会有两种删除方法,一个形参是int index 一个是Object o
- 下面第一次删除的时候,因为直接放到括号里的是1,默认int,所以会自动调用删除索引的remove方法,所以会把2删掉。
List集合的遍历方式
- 迭代器遍历
- 列表迭代器遍历
- 增强for循环
- Lambda表达式遍历
- 普通for循环(使用list.size和get方法)
public class ListDemo2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
//额外添加了一个方法,在遍历过程中,可以添加元素。
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
String s = it.next();
if("a".equals(s)){
it.add("lalala");
}
}
System.out.println(list);
}
}
Set系列集合
特点
- 无序:存和取的顺序不一致
- 无重复:可以去除重复
- 无索引:不能使用普通for循环来遍历
Set集合的实现类
- HashSet:无序,不重复,无索引
- LinkedHashSet:有序,不重复,无索引
- TreeSet:可排序,不重复,无索引
package setdemo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;
public class SetDemo1 {
static void main(String[] args) {
//1.实现一个Set集合的对象
//Set是一个接口,不能实例化,要创建它实现类的对象。
Set<String> set = new HashSet<>();
//2.添加元素
boolean r1 = set.add("aaa");
boolean r2 = set.add("aaa");
set.add("bbb");
set.add("ccc");
System.out.println(r1);//true
System.out.println(r2);//false
System.out.println(set);//[aaa, ccc, bbb]
//3.迭代器遍历
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//4.增强for遍历
for (String str : set) {
System.out.println(str);
}
//5.lambda表达式,先写匿名内部类
//set.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
//});
//简化Lambda表达式
set.forEach( s-> System.out.println(s));
}
}
HashSet
- HashSet集合底层采取哈希表存储数据
- 哈希表组成:数组+链表+红黑树(jdk8之前没有红黑树)
- 哈希值:对象的整数表现形式
- 没有重写HashCode方法的情况
- 重写HashCode方法:Alt+Insert自动生成
String类的hashCode()方法计算公式为:s[0]×31(n−1)+s[1]×31(n−2)+⋯+s[n−1]s[0]×31(n−1)+s[1]×31(n−2)+⋯+s[n−1]所以下面两个字符串产生了哈希碰撞
HashSet添加元素
- 加载因子用来进行数组扩容,16*0.75=12,数组长度达到12的时候就会扩容到原来的两倍,即32
- 当链表长度超过8,而且数组长度大于等于64的时候,自动转化成红黑树
LinkHashSet
TreeSet
1.不重复,无索引,可排序
2.可排序:按照元素的默认规则(由小到大)排序
3.TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查效果都较好。
- TreeSet的遍历
package treesetdemo;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.function.Consumer;
public class TreeSetDemo1 {
static void main(String[] args) {
//利用TreeSet存取整数
//1,创建TreeSet集合对象
TreeSet<Integer> ts = new TreeSet<>();
//2.添加元素
ts.add(4);
ts.add(5);
ts.add(3);
ts.add(2);
ts.add(1);
//3.打印集合
System.out.println(ts);//[1, 2, 3, 4, 5]
//4.遍历集合
//迭代器
Iterator<Integer> it = ts.iterator();
while(it.hasNext()){
Integer num = it.next();
System.out.println(num);
}
//增强for循环
for (Integer i : ts) {
System.out.println(i);
}
//lambda表达式,先写匿名内部类
ts.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
System.out.println(i);
}
});
//简化匿名内部类
ts.forEach( i-> System.out.println(i));
}
}
- 自定义对象的排序规则