List Set
1. 数据结构
数据结构: 就是数据的存储方式
2. 栈
栈的特点:
1. 先进后出
2. 出入口在同一侧
3. 队列
队列的特点:
1. 先进先出
2. 入口和出口在两端
适用于高并发场景
4. 数组
数组的特点:
1. 查询快
2. 增删慢
5. 链表
链表是由多个节点组成
链表的特点:
1. 查询慢
2.增删快
6. 红黑树
红黑树的特点 :
1. 元素存储过程中就完成了大小排序
2. 查询比链表快, 增删比数组快
7. List集合
file:///C:/Users/%25E7%25A5%259E%25E5%25A5%2587%25E5%25AE%259D%25E8%25B4%259D/AppData/Local/YNote/data/qqED41ADEF79E33AADEEC40B27412B0329/7a130220b55a492dbaa96b23797ae1bc/e78172ef4a2040a7875303e55b20e90a.jpg
List 集合体系的特点 :
1. 元素有序的 (存入和取出的顺序一致) 排序 : 从小到大
2. 元素可重复的
3. 有索引
List子体系中的实现类都具有上述特点
add(int index, E element): 将指定的元素, 添加到该集合中的指定位置上
get(int index): 返回集合中指定位置的元素
remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素
set(int index, E element): 用指定元素替换集合中指定位置的元素
7.1 ArrayList集合的特点
ArrayList底层的数据结构:
数组
ArrayList的特点:
查询快
增删慢
线程不安全, 效率高
7.2 LinkedList集合的特点和特有方法
LinkedList底层的数据结构:
链表
LinkedList的特点:
1. 查询慢
2. 增删快
3. 线程不安全, 效率高
特有方法 :
addFirst(E e): 将指定元素插入此列表的开头
addLast(E e): 将指定元素添加到此列表的结尾
getFirst(): 返回此列表的第一个元素
getLast(): 返回此列表的后一个元素
removeFirst(): 移除并返回此列表的第一个元素
removeLast(): 移除并返回此列表的后一个元素
7.3 Vector集合
Vector底层的数据结构 :
数组
Vector的特点:
1. 查询慢
2. 增删快
8. Set集合体系
8.1 Set集合
Set集合的特点 :
1. 元素不可重复
2. 没有索引
8.2 HashSet
HashSet特点 :
1. 元素不可重复
2. 没有索引
3. 元素存取无序
4. 底层采用 哈希表 结构. (查询快)
哈希表 = 数组 + 链表或红黑树
8.3 LinkedHashSet
LinkedHashSet集合特点 :
1. 元素存取有序
2. 元素不可重复
3. 没有索引
9. 可变参数
1. 可变参数可以传递的参数个数, 可以是 0个, 1个, 多个
2. 一个方法的参数列表中, 只能有一个可变参数
3. 如果方法的参数有多个, 可变参数必须写在参数列表的后
10. Collections集合工具类
addAll(Collection<? super T> c, T... elements):往集合中添加一些元素
shuffle(List<?> list): 打乱集合顺序
sort(List<T> list): 将集合中元素按照默认规则排序
sort(List<T> list,Comparator<? super T> c):将集合中元素按照指定规则排序
Day - 04
Map
1. Map集合
Map特点:
1. 是双列集合, 一个元素包含两个值 (键key, 值value) 键值对
2. key和value的类型可以相同, 也可以不同
3. key不允许重复, value可以重复
4. key和value是一一对应的, 一个键只能对应一个值
2. Map常用子类
1. HashMap
底层哈希表. key存取无序不可重复
2. LinkedHashSet
底层哈希表+链表. key存取有序不可重复
3.Map常用方法
1. put(K key, V value): 添加/修改 键值对.
2. remove(Object key): 根据键删除键值对, 返回被删除元素的值
3. get(Object key): 根据键获取值
4. containsKey(Object key): 判断是否包含指定的键
5. keySet(): 获取Map集合中所有的键, 存储到Set集合中
6. entrySet(): 获取到Map集合中所有的Entry对象的集合(Set集合)
4.Map遍历方式一: keySet()方法实现通过键找值
keySet()遍历步骤 :
1. Map对象调用 keySet() 方法, 获取包含所有key的Set集合
2. 遍历Set集合, 获取每个key
3. 通过Map对象调用 get(Object key) 方法根据key获取到value
Map<String, String> map = new HashMap<>();
Set<String> keys = map.keySet();
5. Entry键值对对象介
entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)
getKey(): 获取Entry对象中的键
getValue(): 获取Entry对象中的值
5.1 Map遍历方式2: 通过entrySet()获取Entry对象形式遍历
entrySet()方法遍历Map步骤:
1. Map对象调用 entrySet() 获取包含所有Entry对象的Set集合
2. 遍历Set集合, 获取每个Entry对象
3. 调用Entry对象的 getKey() 和 getValue() 方法获取键和值
6. HashMap存储自定义数据类型作为
HashMap存储自定义JavaBean对象作为key保证key唯一不重复, 需要让JavaBean重写 hashCode() 和 equals() 方法
7. LinkedHashMap类
LinkedHashMap底层: 哈希表 + 链表 key不允许重复, 但key存取有序
Day - 05
异常 多线程
1. 异常的概念
异常: 指的是程序在执行过程中, 出现的非正常的情况, 最终会导致JVM的非正常停止
2. 异常的分类
1. 错误(Error): 不能捕捉处理的严重问题, 只能修改代码
2. 异常(Exception): 可以捕获处理的问题
①. 编译时异常:
编译时期就会发生的异常, 必须在编译时期处理
②. 运行时异常:
编译时正常, 运行时才会发生的异常
3. 异常关键字: throw制造异常
1. throw 必须写在方法的内部
2. throw 后面new的异常对象, 必须是 "Exception" 或 "Excetion的子类" 的对象
格式:
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
4. 异常的处理方式1: throws声明抛出异常
格式:
修饰符 返回值类型 方法名() throws 异常类名1, 异常类名2,...{
}
示例 :
public static void readFile(String filename) throws FileNotFoundException
5. 异常的处理方式2: 捕获异常
try...catch : 捕获并处理异常
try {
// 可能产生异常的代码
} catch (异常类名 变量名) {
// 处理异常的代码
// 一般会将异常信息存储到日志中
}
注意:
1. try 中可能会抛出多种异常, 就可以写多个 catch 分别处理每种异常
6. Throwable中的3个异常处理方法
String getMessage(): 异常的信息. 没有原因返回null
String toString(): 异常的类型和原因信息
void printStackTrace(): 使用标准错误输出流打印异常信息
System.out.println(e.getMessage());
7. finally代码块
1. finally 必须和 try...catch 一起使用
2. finally 一般用于释放资源 (IO流时用到)
catch(异常类型 异常变量名) {
// 处理异常
} finally {
// 无论是否发生异常, 是否捕获, 最后都会执行的代码.
// 通常在这里执行释放资源的操作
}
8. 自定义异常类
定义编译时异常: 继承 Exception
定义运行时异常: 继承 RuntimeException
为了在抛出异常时, 显示一些提示信息, 我们可以定义2个构造, 一个无参, 一个有String参数
// 自定义编译时异常
public class RegisterException extends Exception {
public RegisterException() {
super();
}
public RegisterException(String message) {
super(message);
}
}
9. 多线程
并发: (交替执行) 指两个或多个事件在"同一时间段内"发生
并行: (同时执行) 指两个或多个事件在"同一时刻"发生 (同时发生)
9.1 进程
进程: 一个应用程序在内存中的一次执行过程
9.2 线程
线程: 是进程内的一个独立执行单元 (一条代码执行路径)
一个程序运行后至少有一个进程, 一个进程中可以包含多个线程
9.3 线程的调度
1. 分时调度: 所有线程轮流使用CPU, 平分占用CPU的时间
2. 抢占式调度: 优先让优先级高的线程使用CPU; 如果优先级相同, 则随机选择一个线程执行
9.4 主线程
主线程:
我们以前编写的代码, 也在一条线程中执行, 该线程叫作"main线程", 也称
为"主线程"
9.5 创建多线程程序的第一种方式: 继承Thread类
实现多线程的第一种方式:
1. 定义类, 继承 Thread 类
2. 重写 run() 方法, run方法内部是线程要执行的任务
3. 创建Thread子类的对象, 调用 start() 方法启动线程
void start(): 启动线程, 即让线程开始执行run()方法中的代码
注意:
必须调用 start() 方法来开启线程, 不能直接调用 run() 方法, 调用 run() 会
变成单线程
同一个线程对象, 不能多次调用 start() 方法
Java是抢占式调度, 不同线程的代码, 执行顺序是随机的
Day - 06
线程 同步 线程间通信
1. 多线程的内存
多线程情况下, 每个线程都有各自的栈内存 每个线程各自的方法调用, 进的是各自线程的栈 "栈"是每个线程各自的, "堆"是所有线程共用的
2. Thread常用方法: getName(), currentThread()
getName(): 获取线程的名称
Thread currentThread(): 返回对当前正在执行的线程对象的引用
run(): 用于让子类重写, 表示该线程要执行的任务.不能直接调用
start(): 启动线程, 即让线程开始执行run()方法中的代码
3. 创建多线程程序的方式: 实现Runnable接口
创建多线程的第二种方式:
1. 定义类,实现Runnable接口
2. 重写run( )方法, 要执行的代码
3. 创建Runnable实现类对象
4. 创建Thread类对象,在构造方法中传入Runnable实现类对象
5. 通过Thread对象调用start()方法启动线程
4. Thread 和Runnable的区别
1. 避免单线程的局限性
2. 增强了程序的扩展性, 降低了程序耦合性
5. 匿名内部类方式创建线程
new 父接口/父类() {
重写方法 };
继承Thread类 实现Runnable接口
new Thread(new Runnable(){
@Override
public void run() {
// 要执行的任务
}
}).start();
6. 线程安全问题
6.1 线程安全问题的原因
问题发生的场景:
多个线程操作共享资源
问题发生的原因:
JVM是抢占式调度, CPU在每个线程之间切换是随机的, 代码执行到什么位
置是不确定的
在操作共享资源时, 由于一个线程还没有执行完, 另一个线程就来操作, 就会
出现问题
6.2 解决线程安全问题方式1: 同步代码块
同步代码块: 使用synchronized关键字修饰的代码块,并传入一个当作锁的对象
格式:
synchronized(锁对象) {
}
6.3 解决线程安全问题方式2: 同步方法
同步方法: 使用synchronized关键字修饰的方法,具有默认的锁对象
非静态同步方法的锁对象: this
public synchronized void method(){
// 可能会产生线程安全问题的代码
}
静态同步方法的锁对象: 当前类的字节码对象 Class对象
RunnableImpl.class -> Class对象
获取一个字节码对象的3种方式:
1. 对象名.getClass()
2. 类名.class
3. Class.forName("类的全名")
6.4 解决线程安全问题3: Lock锁
lock(): 获取锁
unlock(): 释放锁
@Override
public void run() {
// 加锁
lock.lock();
try {
// 操作共享变量的代码...
} finally {
// 在finally中保证释放锁
lock.unlock();
}
7. 线程间的通信
notify(): 随机唤醒在同一个锁对象上的某一个处于等待状态的线程
notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线
wait(): 让当前线程处于"无限等待"状态
线程生命周期中, 可以出现有6中状态:
1. NEW 新建
2. RUNNABLE 可运行
3. BLOCKED (锁)阻塞
4. WAITING 无限等待
5.TIMED_WAITING 计时等待
6. TERMINATED 终止
8. Object类中wait(long timeout)和notifyAll()方法
wait() 和 sleep() 的区别:
1. wait会释放锁, 恢复时需要重新获取锁; sleep不会释放锁
2. wait可以被notify/notifyAll唤醒; sleep不会
3. wait要用锁对象调用; sleep要用Thread类名调用
这就是这四天的笔记,感谢观看,谢谢!