集合
数组:可以存储引用数据类型,也可以存储基础数据类型
集合:可以存储引用数据类型,基础数据类型必须转为对应的封装类
单列集合collection:每次添加一个数据
双列集合map:数据成对体现
集合的基础操作
java
ArrayList<String> list = new ArrayList<>();
// 添加一个数据,返回是否添加成功
// 添加任何数据都能添加成功
boolean aaa = list.add("aaa");
boolean bbb = list.add("bbb");
boolean ccc = list.add("ccc");
boolean ddd = list.add("ddd");
// 删除指定数据
boolean remove = list.remove("aaa");
// 通过索引位置删除元素,返回被删除的元素
String remove1 = list.remove(0);
// 修改指定元素,返回被覆盖的元素的值
String set = list.set(1, "aaa");
// 查询指定索引的元素
String s = list.get(1);
// 获取集合的长度
int size = list.size();
System.out.println(list);

ArrayList:适用于频繁查找操作的场景。
LinkedList:适用于频繁插入和删除操作的场景。
HashSet:适用于需要唯一元素且顺序不重要的场景。
TreeSet:适用于需要排序的集合。
HashMap:适用于需要快速访问键值对的场景。
TreeMap:适用于需要按自然顺序或自定义顺序遍历键的场景。
Collection
collection的常用方法
public boolean add(E e) 把给定的对象添加到当前集合中
public void clear() 清空集合中所有的元素
public boolean remove(E e) 把给定的对象在当前集合中删除
public boolean contains(Object obj) 判断当前集合中是否包含给定的对象
public boolean isEmpty() 判断当前集合是否为空
public int size() 返回集合中元素的个数 / 集合的长度
Collection是一个接口,不能直接创建他的对象,智能创建他的实现类的对象
java
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>() ;
/**添加元素
* 向List系列集合中添加数据,返回值永远为true,
* 向set系列集合中添加数据
* 如果添加到元素set中不存在,返回true,添加成功
* 如果元素已经在set中,返回false添加失败
*/
coll.add("111");
// 清空数据
coll.clear();
/**删除数据
* collection中不能通过索引删除数据
* 删除成功,返回true,删除失败(要删除的元素不存在),返回false
*/
coll.remove("111");
// 判断元素是否在集合中
/**判断元素是否在集合中
* 底层是通过equals方法进行判断是否存在的
* 如果集合中存储的是自定义对象,想通过contains判断是否包含,javabean类中一定要重写equals方法
*/
coll.contains("aaa");
// 判断集合是否为空
coll.isEmpty();
// 获取集合的长度
coll.size();
}
collection的遍历
迭代器遍历Iterator
迭代器遍历时不能用集合的方法进行增加或者删除
迭代器遍历完毕后指针不会复位
java
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>() ;
// 获取迭代器指针,默认指向0索引的元素
Iterator<String> it = coll.iterator();
// 判断是否铀元素
boolean hasNext = it.hasNext();
// 获取当前元素,并向后移动指针
String str = it.next();
}
增强for遍历
增强for的底层就是迭代器,为了简化迭代器的代码书写的
只有单列集合和数组才能使用增强for
java
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>() ;
// str是一个第三方变量,并不是指针,修改str不会修改集合中的内容
for (String str: coll) {
str="qqq";
}
}
Lambda表达式遍历
java
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>() ;
/**利用匿名内部类的形式
* 底层原理:
* 自己遍历集合,得到集合中的每一个元素
* 把得到的每个元素传给accept方法
* s表示每一个元素
*/
coll.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
// lambda表达式
coll.forEach(s-> System.out.println(s));
}
List集合
list集合特点:
- 有序:存和取的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
list的常用方法
java
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
// 在索引为1的位置加入bbb
// 原来的元素向后移
list.add(1,"bbb");
// 删除指定位置的元素,将被删除的元素返回
String remove = list.remove(1);
}
List除了可以用collection的遍历方法外还可以用普通for循环遍历
列表迭代器
java
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 列表迭代
ListIterator<String> iterator = list.listIterator();
while (iterator.hasNext()){
String str = iterator.next()
if (str == null) {
// 列表迭代允许添加操作
iterator.add("bbb");
}
}
}
ArrayList底层结构
- 利用空参创建的集合,在底层创建一个默认长度为0的数组
- 添加第一个元素时,底层会创建一个新的长度为10的数组
- 存满时,会扩容1.5倍(创建一个长度为原来的1.5倍的新数组,进行拷贝)
- 如果一次添加多个元素,扩容1.5倍仍放不下,则扩容到刚好能放下
LinkedList集合
- 底层结构是双链表,查询慢,首尾操作快
泛型
如果不指定泛型,集合默认接收Object类型,能够存储各种数据类型,这会导致各种问题
通过泛型统一数据类型
把运行时期的问题提前到编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段数据类型就能确定一下
java的泛型是伪泛型,只在编译过程中生效
泛型中不能写基本数据类型,指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
如果不写泛型,类型默认为object
二叉树结构
二叉查找树
每一个节点最多有两个子节点
任意节点左子树的值都小于当前节点
任意节点右子树的值都大于当前节点
二叉查找树不允许重复
平衡二叉树
任意节点左右子树的刚度差不超过1
红黑树
红黑树是一种自平衡的二叉查找树
红黑树是一种特殊的二叉查找树,节点可以是红或者黑,红黑树不是高度平衡的,它的平衡时通过红黑规则实现的
红黑规则
每一个节点或是红色的,或者是黑色的
根节点必须是黑色
如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;

set集合
set集合:不可重复、无索引
HashSet:无序
LinkedHashSet:有序
TreeSet:可排序
HashSet
HashSet集合底层采用哈希表存储
哈希表是一种对于增删改查性能都能较好的结构
哈希值:对象的整数表现形式,根据hashCode方法算出来的int类型的整数
该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
一般情况下会重写hashCode方法,利用对象内部的属性计算哈希值
哈希值的店:
- 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
- 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
- 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也可能相同
插入过程
- 创建数组:默认长度 16、默认加载因子 0.75,数组名 table
- 计算位置:根据元素哈希值和数组长度,算出元素应存入的位置
- 空位置判断:若当前位置为 null,直接存入元素
- 非空位置处理:若位置不为 null(已有元素),调用 equals 方法比较属性值
- 比较结果:
属性值相同:不存储
属性值不同:存入数组,形成链表
链表挂载规则:- JDK8 以前:新元素存入数组,老元素挂在新元素下面
- JDK8 以后:新元素直接挂在老元素下面
JDK8 以后,当链表长度超过 8,而且数组长度大于等于 64时,自动转换为红黑树
如果集合中存储的是自定义对象,必须要重写hashCode和equals方法
LinkedhashSet
有序、不重复、无索引。
这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。

TreeSet
不重复、无索引、可排序
可排序:按照元素的默认规则(有小到大)排序。
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。
TreeSet的排序方式:
方法一:
默认的排序规则/自然排序
Student实现Comparable接口, 重写里面的抽象方法, 再指定比较规则
java
package itheima;
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;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
private int getAge() {
return age;
}
@Override
public int compareTo(Student o) {
// 指定排序的规则
// 只看年龄,我想要按照年龄的升序进行排列
// 返回值为负数表示当前要添加的元素为小的,存左边,否则反之
// this是当前要添加的元素
// o是已经添加的元素
return this.getAge() - o.getAge();
}
}
方法二:
比较器排序:创建Treeset对象时,传递比较器Comparator指定规则
java
//1. 创建集合
// o1: 表示当前要添加的元素
// o2: 表示已经在红黑树存在的元素
// 返回值规则跟之前是一样的
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// 按照长度排序
int i = o1.length() - o2.length();
// 如果一样长则按照首字母排序
i = i == 0? o1.compareTo(o2) : i;
return i;
}
});
Map双列集合
双列集合的特点
双列集合一次需要存一对数据,分别为键和值
键不能重复,值可以重复
键和值是一一对应的,每一个键只能找到自己对应的值
键 + 值这个整体我们称之为 "键值对" 或者 "键值对对象",在 Java 中叫做 "Entry 对象"

V put(K key,V value) 添加元素,如果key已存在,则覆盖并返回原来的value
V remove(Object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(Object key) 判断集合是否包含指定的键
boolean containsValue(Object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数
java
public static void main(String[] args) {
//1.创建Map集合的对象
Map<String,String> m = new HashMap<>();
//2.添加元素
m.put("紫霞","至尊宝");
m.put("小龙女","杨过");
// 覆盖原来的元素,并返回被覆盖的内容
String value = m.put("小龙女","双儿");
System.out.println(value);
//3.打印集合
System.out.println(m);
m.remove("小龙女");
boolean b = m.containsKey("小龙女");
boolean b1 = m.containsValue("双儿");
boolean empty = m.isEmpty();
int size = m.size();
m.clear();
}
Map的遍历
java
//1.创建Map集合的对象
Map<String,String> map = new HashMap<>();
//2.添加元素
map.put("尹志平","小龙女");
map.put("梅念笙","梅念笙");
map.put("欧阳克","黄蓉");
//3.通过键找值
//3.1获取所有的键,把这些键放到一个单列集合当中
Set<String> keys = map.keySet();
//3.2遍历单列集合,得到每一个键
for (String key : keys) {
System.out.println(key);
}
通过对象遍历Map
java
//1.创建Map集合的对象
Map<String,String> map = new HashMap<>();
//2.添加元素
//键:人物的外号
map.put("粉面郎君","段誉");
map.put("大轮明王","明教教");
map.put("北丐上亿","洪七公");
//Map遍历的第二种遍历方式
//3.1通过一个方法获取所有的键值对对象,返回一个Set集合
Set<Map.Entry<String, String>> entries = map.entrySet();
//3.2 增强for循环遍历Set集合,得到每一个键值对对象
for (Map.Entry<String, String> entry : entries) {
//Map.Entry中的get方法获取键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
lambda表达式遍历
java
//1.创建Map集合的对象
Map<String,String> map = new HashMap<>();
//2.添加元素
//键:人物的外号
map.put("粉面郎君","段誉");
map.put("大轮明王","明教教");
map.put("北丐上亿","洪七公");
map.forEach((key, value) -> System.out.println(key + "=" + value));
HashMap
HashMap 是 Map 里面的一个实现类。
没有额外需要学习的特有方法,直接使用 Map 里面的方法就可以了。
特点都是由键决定的:无序、不重复、无索引
HashMap 跟 HashSet 底层原理是一模一样的,都是哈希表结构
LinkedHashMap
由键决定:有序、不重复、无索引。
这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。

java
//1.创建集合
LinkedHashMap<String,Integer> lhm = new LinkedHashMap<>();
//2.添加元素
lhm.put("a",123);
lhm.put("a",111);
lhm.put("b",369);
lhm.put("c",789);
System.out.println(lhm);
TreeMap
TreeMap 跟 TreeSet 底层原理一样,都是红黑树结构的。
由键决定特性:不重复、无索引、可排序
可排序:对键进行排序。
注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则
- 实现 Comparable 接口,指定比较规则。
- 创建集合时传递 Comparator 比较器对象,指定比较规则。
java
//1.创建集合对象
//Integer Double 默认情况下都是按照升序排列的
//String 按照字母在ASCII码表中对应的数字顺序进行排列
TreeMap<Integer,String> tm = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//o1:当前要添加的元素
//o2:表示已经在红黑树中存在的元素
return o2 - o1;
}
});
//2.添加元素
tm.put(5,"可可可乐");
tm.put(4,"九个核桃");
tm.put(3,"康帅傅");
tm.put(2,"脉劫");
tm.put(1,"粤利粤");