HashMap<K,V>的底层原理
1. 当创建HashMap < K , V > 集合的时候, 会在底层创建一个容量为16 , 加载因子为0.75 的数组
加载因子 : 扩容的时机 0.75 指的是 : 当数组中的元素个数达到( 容量 * 0.75 ) 的时候, 需要扩容
2. 当底层数组中元素的个数达到扩容条件, 会在底层创建一个长度为原来数组长度的2 倍的新数组
3. 当往HashMap 底层数组添加元素的时候, 若添加的Hash 表位置还是默认值null 的时候, 不看加载因子, 不扩容! !
4. 当底层数组的长度未达到64 时, 当同一个Hash 位置的链表挂载超过8 也不会把链表转成红黑树!
面试题: 不考虑其他情况, 当添加第1024 个元素的时候, 请问HashMap 底层数组的长度是多少 ? 2048
集合嵌套的案例
LinkedHashMap<K,V>
LinkedHashMap < K , V > 相较于 HashMap < K , V > 变成了存取有序的双列集合;
TreeMap<K,V>
TreeMap < K , V > : 底层是红黑树的双列集合
使用注意:
当键集中的元素没有提供排序规则, 元素是无法添加到集合中的
TreeMap ( Comparator < ? super K > comparator) 带有独立比较器的TreeMap 构造方法
泛型的概述
泛型: < 字母>
作用: 约束集合中元素的数据类型
特点:
1. 泛型只可以使用引用数据类型去替换
2. 如果有泛型却不处理泛型, 那么泛型默认是Object 类型
3. 泛型只是停留在编译阶段的类型约束
泛型 -> 泛: 广泛( 说不清楚) 型: 类型 -> 说不清楚的引用数据类型( JDK5之后才有的泛型)
格式: < 字母>
格式解释 :
1. 字母可以有多个, 中间用逗号分隔 -> < K , V >
2. 字母"必须" 使用大写 < E > , < T > , < K , V >
3. 一个泛型最好是单个大写字母 < MVP>
泛型类(理解)
格式 :
public class 类名< 泛型> {
}
泛型方法(理解)
格式:
方法的修饰符 < 泛型> 返回值类型 方法名( 形参列表) {
方法体;
}
方法上的泛型一般都作为形参的数据类型使用, 等调用方法的时候确定方法泛型的类型
泛型接口(了解)
格式 :
public interface 接口< 泛型> {
}
泛型的沿用: 集合板块
子类要沿用父类/ 父接口的泛型, 子类必须定义泛型
如果子类把父类/ 父接口的泛型写死, 父类/ 父接口的泛型就不可以继续使用了
泛型的通配符和泛型的上下限(重要)
泛型的通配符 : ? ( ? 代表可以接收任意的引用数据类型)
泛型的上下限:
? extends 类名 : 泛型的上限
? super 类名 : 泛型的下限
注意: 不管是上限还是下限 都是包含extends / super 后面的类型
不管是通配符还是上下限 都是用在方法的形参上的! ! !
JVM如何处理异常
运行时期异常:
1. 立刻终止程序
2. 以红色字体打印异常信息
异常的类型: ArithmeticException
异常产生的原因: / by zero
异常产生的位置: ExceptionDemo . main ( ExceptionDemo . java: 6 )
异常产生的线程: Exception in thread "main"
3. 开启了多线程打印异常信息
4. 在堆内存中创建一个该异常类型的对象
编译时期异常:
如果不处理编译时期异常, 代码无法执行
异常体系
异常的处理方式一: 抛出去
抛出去格式:
方法声明( 形式参数列表) throws 异常的类名{
方法体;
}
抛出去到底是在干吗 ? 把异常丢给调用者处理, 谁调用谁处理
抛出去的方式来处理运行时期异常: 没必要( 也不需要)
注意事项:
1. 如果调用的方法声明上有编译时期异常的抛出, 调用方法的时候需要处理异常
2. 抛出父类异常所有的子类异常都抛出了
异常的处理方式二: 包起来(捕获)
利用Java 中 try . . catch 结构进行异常的捕获
包起来的方式处理编译时期异常: 有意义
1. 异常不用抛出
2. 程序可以继续执行
包起来的方式处理运行时期异常: 有意义
1. 程序可以继续执行
try…catch
包起来的语法格式:
try {
} catch ( 异常的类型 变量名) {
}
try . . catch 执行流程:
1. try 中有异常且catch 捕获到了:
a. 进入try , 遇到try 中异常立刻终止try 中代码执行
b. 进入到catch 执行catch 代码块的代码
c. catch 执行完毕后执行try . . catch 外部代码
2. try 无异常:
不执行catch 中的代码, 按照顺序结构执行代码
3. try 中有异常但是catch 没有捕获到:
遇到异常, 立即终止所有程序执行. JVM介入处理异常. .
4. try 中有异常且catch 捕获到了, 但是catch 有异常
a. 进入try , 遇到try 中异常立刻终止try 中代码执行
b. 进入到catch 执行catch 代码块的代码
c. 在catch 中遇到异常若未处理, JVM介入处理异常. .
catch板块的注意事项
1. 捕获父类型的异常, 小类型的异常也一并捕获
2. 一个catch 的小括号内只能写一个异常类型
3. 一个try 可以有多个catch
4. 多个catch 中, 不能先捕获父类异常再捕获子类异常
5. 多个catch 中, 可以先捕获子类型异常再捕获父类型异常
异常对象的成员方法
String getMessage ( ) : 异常对象的异常信息
String toString ( ) : 异常的类型 + 异常信息
void printStackTrace ( ) : 开启了新的线程 + 红色字体打印 + 异常类型 + 异常信息 + 异常产生的位置
finally代码块
final -> 修饰符 ( 形容词)
finally -> 代码块
使用场景: 配合 try . . catch 语句使用!
finally 代码块 : 一定会执行的代码
自定义异常(理解)
自定义异常类的定义步骤:
1. 定义类, 类名要求: XxxxException
2. 想明白自定义异常类是编译时期异常还是运行时期异常
编译时期异常 : 自定义异常类 extends Exception
运行时期异常 : 自定义异常类 extends RuntimeException
3. 在类中自动生成2 个构造方法 : 无参构造 和 带有String Message 参数的构造
throw 和 throws
throws : 抛出异常
位置 : 方法的声明上
作用 : 抛出异常给调用者
throw : 暴露异常
位置 : 方法内
作用 : 暴露异常对象给调用者
递归算法
递归 : 递进回归
代码中的体现: 方法内部调用方法本身
生活中的案例:
从前有座山, 山里有座庙, 庙里有个老和尚, 老和尚给小和尚讲故事. . .
从前有座山, 山里有座庙, 庙里有个老和尚, 老和尚给小和尚讲故事. . .
从前有座山, 山里有座庙, 庙里有个老和尚, 老和尚给小和尚讲故事. . .
从前有座山, 山里有座庙, 庙里有个老和尚, 老和尚给小和尚讲故事. . .
学编程 -> 赚钱 -> 娶媳妇 -> 生娃娃. .
学编程 -> 赚钱 -> 娶媳妇 -> 生娃娃. .
学编程 -> 赚钱 -> 娶媳妇 -> 生娃娃. .
学编程 -> 赚钱 -> 娶媳妇 -> 生娃娃. .
俄罗斯套娃, 文件的遍历
递归算法的前提
1. 必须定义方法
2. 必须有出口
3. 定义的方法必须有形参
4. 在方法内部调用方法自己时, 传入的参数要发生变化 -- > 变化要往出口方向前进
5. 递归的次数不要太多