文章目录
前言
本篇文章只展示一些基本的集合
之前我们了解了数组可以存储多个元素,但是弊端是数组的长度固定,不可扩展;因此我问引进了集合的概念,集合的优点在于长度可以随着要添加的元素个数而扩展;但是集合的存储类型只能是引用数据类型。
1、Collection的分类
- 集合分类:
- ArrayList:List的实现类,属于单列集合,元素可以重复
- LinkedList:List的实现类,属于单列集合,元素可以重复
- hashSet:Set的实现类,属于单列集合,元素不可以重复
- TreeSet:Set的实现类,属于单列集合,元素不可以重复
- HashMap:Map的实现类,属于双列集合,
- TreeMap:Map的实现类,属于双列集合,
2、Collection
Collection是单例集合的顶级接口,JSK不提供它的实现类,只提供具体的子接口(List或Set)去实现;通过多态的方式创建集合对象。2.1、集合的常用方法
方法名 | 解释 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 移除元素 |
boolean removeIf(Object o) | 根据条件移除,参数为集合对象 |
void clear | 清空集合元素 |
boolean contaions(Object o) | 判断集合中是否存在指定元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 获取集合长度 |
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bb");
list.add("ccc");
list.add("dddd");
// s表示集合中的每个元素
list.removeIf(s -> {
return s.length() == 3;
});
System.out.println(list);
}
2.2、集合的遍历
- 迭代器遍历(一般用于删除元素)
方法名 | 解释 |
---|---|
Iterator iterator() | 返回集合的迭代器对象,默认指向集合的0索引处 |
boolean hasNext() | 判断迭代器所在位置是否有元素 |
E next() | 迭代器获取当前位置元素,并将指向移向下一位 |
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
// 获取迭代器对象
Iterator<String> iterator = list.iterator();
// 判断迭代器当前所指向的位置是否存在元素
while (iterator.hasNext()) {
// 取出当前位置的元素,并将迭代器指向移动到下一位
System.out.println(iterator.next());
}
}
- 迭代器删除元素
迭代器的 void remove() 方法会自动删除迭代器所指的元素
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
// 获取迭代器对象
Iterator<String> iterator = list.iterator();
// 判断迭代器当前所指向的位置是否存在元素
while (iterator.hasNext()) {
String next = iterator.next();
if (next.equals("b")) {
iterator.remove();
}
}
System.out.println(list);
}
- 增强 for 的使用(JDK1.5之后)
只有实现 Iterator 接口的类才可以使用迭代器和增强for,一般用于简化遍历。
代码示例格式:
for(元素数据类型 变量名 数组或集合对象) {
//在此次使用变量(集合中的元素)
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
for (String s : list) {
System.out.println(s);
}
}
3、List集合
List是单例可重复复集合的接口,实现类有ArrayList和LinkedList3.1、List集合的基本认识
- List集合的特点:
有序:存取有序
有索引:可以通过索引操作元素
可重复:集合中的元素可以重复
- List集合的特有方法:
方法名 | 解释 |
---|---|
void add(index, E element) | 在集合的指定索引出添加元素 |
E remove(int index) | 删除指定索引的元素,返回被删除的元素 |
E set(int index, E element) | 修改指定索引的元素,返回被修改的元素 |
E get(int index) | 获取指定索引处的元素 |
3.2、数据结构
- 栈和队列的数据加载方式
栈:数据先进后出,例如手枪弹夹
队列:数据先进先出,例如排队买票
- 数组
数组查询快:查询数据通过地址值和索引定位
数组增删慢:因为增删数据时,数据会经过重新排序
- 链表
节点:链表中的元素被称为节点,每一个节点都是一个对立的对象,节点中存储着具体数据和下一个节点的地址值。
地址值:节点在内存中的位置。
查询慢:因为要从头节点开始顺序查询地址值。
增删快:只需在要增加或删除的位置断开节点中的地址值和下一个节点的连接,重新修改节点之间的连接即可。
- 链表的节点增加
- ArrayList的底层结构:
ArrayList底层结构是一个数组,默认长度为10,自动扩充原来容量的1.5倍。
- LinkedList的底层结构:
LinkedList底层结构式一个链表,而且是双向链表
双向链表:与单向链表相比,节点中多了一个节点地址的指向,分别叫指向,前一个节点的地址值,后一个节点的地址值。
4、Set集合
Set是单例不可重复复集合的接口,实现类有HashSet和TreeSet- set集合的特点
不可重复、存取无序、无索引(无法用普通for循环遍历)
4.1、TreeSet
- 可以设置排序规则
虽然Set集合存取无序,但是却可以设置排序规则
- 排序方法:
TreeSet有两种设置排序的方法,自然排序和比较器排序
- 自然排序的使用规则:
首先使用空参构造创建TreeSet泛型集合
其次创建泛型实体类实现 Comparable 接口,注意泛型保持一致
重写 compare to 方法,在方法体中设置排序规则
- 自然排序的原理:
代码演示根据compare to 方法的返回值,负数存左边
0 表示重复,不存储
正数表示存右边
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
// this:表示正要存的元素,o:表示已经存入的
int result = this.age - o.age;
// 这里调用的是String类型的compareTo按照字典顺序比较返回int值
result = result == 0 ? this.name.compareTo(o.name) : result;
return result;
}
}
import java.util.TreeSet;
public class Demo {
public static void main(String[] args) {
TreeSet<Student> students = new TreeSet<>();
Student stu1 = new Student("张三", 23);
Student stu2 = new Student("李四", 24);
Student stu3 = new Student("王五", 23);
Student stu4 = new Student("赵六", 25);
students.add(stu1);
students.add(stu2);
students.add(stu3);
students.add(stu4);
for (Student student : students) {
System.out.println(student);
}
}
}
- 比较器排序:
代码演示TreeSet的带参构造方法使用
让集合构造方法接收Comparator的实现类对象,重写compare(T o1, T o2)方法
在compare(T o1, T o2)方法中,定义排序规则
import java.util.Comparator;
import java.util.TreeSet;
public class Demo {
public static void main(String[] args) {
TreeSet<Student> students = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// o1:表示要存入的对象
// o2.表示已经存入的对象
int result = o1.getAge() - o2.getAge();
result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
Student stu1 = new Student("张三", 23);
Student stu2 = new Student("李四", 24);
Student stu3 = new Student("王五", 23);
Student stu4 = new Student("赵六", 25);
students.add(stu1);
students.add(stu2);
students.add(stu3);
students.add(stu4);
for (Student student : students) {
System.out.println(student);
}
}
}
- TreeSet的底层原理:
底层原理是二叉树
节点分为四部分(父节点地址、值、左子节点地址、右子节点地址)
4.2、HashSet
- HashSet的特点:
底层是哈希表
存取无序
无索引,不能使用普通for循环遍历
元素唯一,不重复
- 哈希值
哈希值是 jdk 根据对象地址或属性,计算出的 int 类型的整数
通过 public int hashCode() 可以获取
- 哈希表的结构
jdk8 之前,数组 + 链表
jdk8 之后,数组 + 链表 + 红黑树
5、Map集合
Map是双例集合的接口,实现类有HashMap和TreeMap- 基本特点:
键值一一对应、值重键不重。
- Map集合的常用方法
方法名 | 解释 |
---|---|
V put(K key, V value) | 添加元素 |
V remove(Object key) | 根据键删除元素 |
void clear() | 清空 |
boolean containskey(object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 获取集合长度 |
Set |
- Map集合的遍历方法
public class Demo {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("张三","23");
map.put("李四","24");
map.put("王五","25");
// 先获取所有的键
Set<String> keys = map.keySet();
for (String key : keys) {
// 根据键获取值
String value = map.get(key);
System.out.println(key + "..." +value);
}
}
}
方法名 | 解释 |
---|---|
Set<Map.Entry<K,V>> entrySet() | 获取所有键值对对象的集合 |
K getKey() | 获取键 |
V getValue() | 获取值 |
public class Demo {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("张三","23");
map.put("李四","24");
map.put("王五","25");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "..." + value);
}
}
}
- HashMap
的底层原理: 依然是哈希表,底层是长度为16的数组,默认加载因子为0.75(当数组元素增加到12时,自动扩充为原来的两倍);
添加数据:创建entry对象记录键和值,通过hashCode方法计算出键的哈希值,根据这个哈希值和数组长度计算出应存入的位置;
依赖hashCode方法和equals方法保证键唯一。
- TreeMap
底层原理是红黑树结构
依赖自然排序或比较器排序,对键进行排序
6、不可变集合
- 可变参数
代码示例格式:修饰符 返回值类型 方法名(数据类型…变量名){ }
范例:public static int sum(int…arr){ }
注意:变量指的是一个数组
public class Demo {
public static void main(String[] args) {
int sum = getSum(2, 4, 6, 7, 9);
System.out.println(sum);
}
public static int getSum(int...arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum = sum + arr[i];
}
return sum;
}
}
- 不可变集合
方法名 | 解释 |
---|---|
static List of(E…elements) | 创建一个具有指定元素的List集合对象 |
static Set of(E…elements) | 创建一个具有指定元素的Set集合对象 |
static<K,V> Map<K,V> of(E…elements) | 创建一个具有指定元素的Map集合对象 |