集合类体系分为List、Set和Map三个接口,其中List和Set归类为Collection。
- List 有序、可重复的集合,实现类为ArrayList、LinkedList和Vector等;
- Set 无序、不可重复的集合,实现类为HashSet、TreeSet和LinkedHash等;
- Map 键值对存储的集合,实现类为HashMap和TreeMap;
List
List接口是一个有序的Collection,线性列表接口,能够精确的控制每个元素插入的位置,能够通过索引来访问LIst中的元素,第一个元素的索引为0,而且允许有相同的元素,接口存储一组不唯一,有序的对象。
常见的实现类:
ArrayList:
- 基于数组实现,是一个动态的数组队列,但和java中的数组又不一样,它的容量可以自动增长;
- 可以存储任意多的对象,但是只能存储对象,不能存储原生数据类型例如int;
LinkedList:
- 基于链表数据结构,一个双向链表,链表数据结构的特点是每个元素分配的空间不必连续;
- 插入和删除元素时速度非常快,但访问元素的速度较慢;
常见List API语法
import java.util.ArrayList; import java.util.LinkedList; public class ListTest { public static void main(String[] args) { ArrayList<String> arrayList = new ArrayList<>(); LinkedList<String> linkedList = new LinkedList<>(); // 添加元素 arrayList.add("Laobai"); arrayList.add("AILynn"); arrayList.add("PLScript"); System.out.println(arrayList); linkedList.add("Laobai"); linkedList.add("AILynn"); linkedList.add("PLScript"); System.out.println(linkedList); // LinkedList特有API 获取第一个元素和获取最后一个元素,其他与ArrayList一致 System.out.println(linkedList.getFirst()); System.out.println(linkedList.getLast()); // 更新一个元素 arrayList.set(1,"Lynn"); System.out.println(arrayList); // 返回大小 System.out.println(arrayList.size()); // 根据索引获取元素 System.out.println(arrayList.get(1)); // 根据索引删除一个元素 System.out.println(arrayList.remove(1)); // 根据对象删除元素 arrayList.remove("Laobai"); System.out.println(arrayList); // 清空元素 arrayList.clear(); System.out.println(arrayList); // 判断是否为空 System.out.println(arrayList.isEmpty()); } }执行结果:
[Laobai, AILynn, PLScript] [Laobai, AILynn, PLScript] Laobai PLScript [Laobai, Lynn, PLScript] 3 Lynn Lynn [PLScript] [] true
ArrayList和LinkedList两者的异同:
- 两个都是List的接口,两个都是非线程安全的;
ArrarList是基于动态数组的数据结构,而LinkedList是基于链表的数据结构;- 对于随机访问get和set,
ArrayList要优于LinkedList,因为LinkedList要移动指针; - 对于增删操作,
LinkedList优于ArrayList;
Map
什么是Map数据结构:底层就是一个数组结构,数组的每一项又是一个链表,即数组和链表的结合体;Table是数组,数组的元素是Entry。Entry元素是一个Key-value键值对,它持有一个指向下一个Entry元素的引用,table数组的每个Entry元素同时也作为当前Entry链表的首节点,也指向了该链表的下一个Entry元素。
常见实现类:
- HashMap
- 一个散列表(数组和链表),它存储的内容是键值对(key-value)映射
- 是基于hashing的原理,使用put(key,value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当put()方法传递键和值时,会先对键调用hashCode方法,计算并返回hashCode是用于找到Map数组的bucket位置来存储Entry对象的,是非线程安全的,所以HashMap操作速度很快。
- TreeMap
- 在数据的存储过程中,能够自动对数据进行排序,实现了SotredMap接口,它是有序的集合;
- TreeMap使用的存储结构是平衡二叉树;
- 默认排序规则:按照key】的字典顺序来排序(升序),也可以自定义排序,要实现Comparator接口。
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MapTest {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
// TreeMap<String,String> map1 = new TreeMap<>();
// 往map中存放key-value
map.put("Laobai","北京");
map.put("AILynn","天津");
// 根据key获取value
String getValue = map.get("Laobai");
System.out.println("getValue = " + getValue);
// 判断是否包含某个key
System.out.println(map.containsKey("AILynn"));
// 返回map的元素数量
System.out.println(map.size());
// 获取所有value集合
System.out.println(map.values());
// 返回所有key的集合
System.out.println(map.keySet());
// 返回一个Set集合,集合的类型为Map.Entry,是Map声明的一个内部接口
// 接口为泛型,定义为Entry<K,V>,它表示Map中的一个实体(key-value),主要有getKey和getValue方法
Set<Map.Entry<String,String>> ertrySet = map.entrySet();
System.out.println(ertrySet);
// 清空容器
map.clear();
// 判断map是否为空
System.out.println(map.isEmpty());
}
}
执行结果:
getValue = 北京
true
2
[天津, 北京]
[AILynn, Laobai]
[AILynn=天津, Laobai=北京]
true
Set
Set相对于List是简单的一种集合,具有和Collection完全一样的接口,只是实现上不同,Set不保存重复的元素,存储一组唯一、无序的对象。Set中的元素是不能重复的,实现细节可以参考Map,因为这些Set的实现都是对应的Map的一种封装。比如HashSet是对HashMap的封装,TreeSet对应TreeMap。Set底层是HashMap,由于HashMap的Put()方法是一个键值对,当新放入HashMap的Entry中key与集合中原有Entry的key相同(hashCode()返回值相等,通过equals比较也返回true),新添加的Entry的value会将覆盖原来Entry的value,但key不会有任何改变。Set允许包含值为null的元素,但最多只能有一个null元素。
常用的实现类
- HashSet
HashSet类按照哈希算法来存取集合中的对象,存取速度比较快;- 对应的
Map是HashMap,是基于Hash的快速元素插入,元素无顺序;
- TreeSet
TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序;
import java.util.HashSet;
public class SetTest {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
// 添加元素
set.add("Laobai");
set.add("AILynn");
set.add("PLScript");
System.out.println(set);
// 返回大小
System.out.println(set.size());
// 根据对象删除元素
System.out.println(set.remove("Laobai"));
// 清空元素
set.clear();
// 判断是否为空
System.out.println(set.isEmpty());
}
}
执行结果:
[AILynn, PLScript, Laobai]
3
true
true
HashSet和TreeSet的异同:
HashSet不能保证元素的排列顺序,TreeSet是SortedSet接口的唯一实现类,可以确保集合元素处于排序状态;HashSet底层用的是哈希表,TreeSet采用的数据结构是二叉树;HashSet中元素可以是null,但只能有一个,TreeSet不允许放入null;- 一般情况下都使用
HashSet,只有在需要排序功能时,才使用TreeSet(性能原因)
迭代器
迭代器:Iterator是java中的一个接口,核心作用就是用来遍历容器的元素,当容器实现了Iterator接口后,可以通过调用Iterator()方法获取一个Iterator对象。
由于容器的实现有多种,不同的容器遍历规则不一样,比如ArrayList/LinkedList/HashSet/TreeSet等,所以设计了Iterator接口,让容器本身实现这个接口,实现里面的方法,即可以不用关心容器的遍历机制,执行使用对应的方法即可。
核心方法:
boolean hashNext():用于判断iterator内是否有下个元素,如果有则返回true,没有则返回false;Obejct next():返回Iterator的下一个元素,同时指针也会向后移动1位;void remove():删除指针的上一个元素(容易出问题,删除元素不建议使用容器自己的方法)(需要注意是否有上一个元素,需先next()再remove())。
import java.util.*;
public class IteratorTest {
public static void main(String[] args) {
testSet();
testList();
testMap();
}
public static void testSet(){
Set<String> set = new HashSet<>();
set.add("Laobai");
set.add("AILynn");
set.add("PLScript");
set.add("NichengWe");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()){
String str = iterator.next();
System.out.println(str);
}
}
public static void testList(){
List<String> list = new ArrayList<>();
list.add("NichengWe");
list.add("Laobai");
list.add("AILynn");
list.add("PLScript");
list.add("NichengWe");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String str = iterator.next();
System.out.println(str);
if ("NichengWe".equals(str)){
iterator.remove();
}
}
System.out.println(list);
}
public static void testMap(){
Map<String,String> map = new HashMap<>();
map.put("Laobai","老百");
map.put("AILynn","AI琳");
map.put("PLScript","漂亮的脚本");
Set<Map.Entry<String,String>> entrySet = map.entrySet();
Iterator<Map.Entry<String,String>> iterator = entrySet.iterator();
while (iterator.hasNext()){
Map.Entry<String,String> entry = iterator.next();
String str = entry.getKey() + " = " + entry.getValue();
System.out.println(str);
}
}
}
执行结果:
AILynn
NichengWe
PLScript
Laobai
NichengWe
Laobai
AILynn
PLScript
NichengWe
[Laobai, AILynn, PLScript]
AILynn = AI琳
PLScript = 漂亮的脚本
Laobai = 老百
迭代器与for循环:for循环适合顺序访问,或者通过下标进行访问;迭代器适合链式结构。
Collections工具类
Collection是接口,提供了对集合对象进行基本操作的通用接口方法,List、Set等多种具体的实现类;
Collections是工具类,专门操作Collection接口实现类里面的元素。
常用方法:
排序
sort(List list)按自然排序的升序排序
import java.util.*; public class IteratorTest { public static void main(String[] args) { testSort(); } public static void testSort(){ List<String> list = new ArrayList<>(); list.add("LLLL"); list.add("AAAA"); list.add("YYYY"); list.add("NNNN"); list.add("IIII"); System.out.println(list); Collections.sort(list); // 操作的是容器本身 System.out.println(list); } }sort(List list, Comparator c)自定义排序规则,由Comparator控制排序逻辑import java.util.*; public class IteratorTest { public static void main(String[] args) { testSort(); } public static void testSort(){ List<String> list = new ArrayList<>(); list.add("LLLL"); list.add("AAAA"); list.add("YYYY"); list.add("NNNN"); list.add("IIII"); System.out.println(list); // Collections.sort(list); // 操作的是容器本身 // System.out.println(list); // 默认是是升序 上面的排序等价于这个 Collections.sort(list, Comparator.naturalOrder()); System.out.println(list); // 降序 Collections.sort(list, Comparator.reverseOrder()); System.out.println(list); } }
随机排序
shuffle(List list)import java.util.*; public class IteratorTest { public static void main(String[] args) { testShuffle(); } public static void testShuffle(){ List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); list.add("6"); list.add("7"); list.add("8"); list.add("9"); list.add("10"); list.add("J"); list.add("Q"); list.add("K"); System.out.println(list); Collections.shuffle(list); System.out.println(list); } }获取最大元素
max(Collection coll)默认比较,不适合对象比较获取最大元素
max(Collection coll, Comparator Comparator)获取最小元素
min(Collection coll)import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class CollectionsTest { public static void main(String[] args) { List<Student> list = new ArrayList<>(); list.add(new Student("Laobai", 18)); list.add(new Student("AILynn", 17)); list.add(new Student("PLScript", 19)); list.add(new Student("NichengWe", 16)); System.out.println(list); Student maxAgeStudent = Collections.max(list, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); } }); System.out.println(maxAgeStudent); Student minAgeStudent = Collections.min(list, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); } }); System.out.println(minAgeStudent); } } class Student{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }创建不可变集合
unmodifiablleXXX()package test04; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class CollectionsTest { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Spring"); list.add("SpringBoot"); list.add("SpringCloudAlibaba"); // 设置只读集合 list = Collections.unmodifiableList(list); list.add("Docker"); } }上面的代码可以改写为
public class CollectionsTest { public static void main(String[] args) { List<String> list; list = List.of("Spring", "SpringBoot", "SpringCloudAlibaba"); list.add("Docker"); } }
Comparable排序接口
Comparable是一个接口,定制排序规则。对实现它的每个类的对象进行整体排序,里面compareTo方法是实现排序的具体方法。比如TreeSet、SortedSet、Collections。sort()方法调用进行排序;String、Integer等类默认实现了这个接口,所以可以排序。
public interface Comparable<T> { // T 泛型
public int compareTo(T o);
}
compareTo方法
- 用于比较当前对象和指定对象的排序,o为要比较的对象
- 返回int类型
- 大于0,表示this大于传过来的对象o,则往后排,即升序;
- 等于0,表示this等于传过来的对象o
- 小于0,表示this小于传过来的对象o
被排序的对象类需要实现Comparable接口
import java.util.*;
public class CompareToTest {
public static void main(String[] args) {
Set<Student> studentSet = new TreeSet<>();
studentSet.add(new Student("Laobai", 18));
studentSet.add(new Student("AILynn", 17));
studentSet.add(new Student("PLScript", 19));
studentSet.add(new Student("NichengWe", 16));
System.out.println(studentSet);
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("Laobai", 18));
studentList.add(new Student("AILynn", 17));
studentList.add(new Student("PLScript", 19));
studentList.add(new Student("NichengWe", 16));
System.out.println(studentList);
Collections.sort(studentList);
System.out.println(studentList);
}
}
class Student implements Comparable<Student>{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
执行结果:
[Student{name='NichengWe', age=16}, Student{name='AILynn', age=17}, Student{name='Laobai', age=18}, Student{name='PLScript', age=19}]
[Student{name='Laobai', age=18}, Student{name='AILynn', age=17}, Student{name='PLScript', age=19}, Student{name='NichengWe', age=16}]
[Student{name='NichengWe', age=16}, Student{name='AILynn', age=17}, Student{name='Laobai', age=18}, Student{name='PLScript', age=19}]