集合类体系分为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}]