本帖最后由 13333114253 于 2018-11-20 11:16 编辑
01-数据结构
就是数据的存储方式
1).栈: 先进后出 (FILO, First In Last Out) 入口和出口在同一侧
入栈(压栈): 将元素存入栈
出栈(弹栈): 从栈中取出元素
2).对列: 先进先出 (FIFO, First In First Out) 入口和出口在两端
3).数组:
查询快: 通过 (第一个元素地址值 + 索引) 可以快速计算出该索引元素的地址值
增删慢: 增加一个元素, 要创建长度+1的新数组, 然后将原数组元素复制到新数组, 然后存入新元素; 删除类似
4).链表:
查询慢: 要找到其中某个节点, 只能从第一个节点一个一个向后寻找
增删快: 只需要修改保存的下一个节点的地址值, 就可以快速完成增删
5).红黑树:
平衡 二叉 查找 树
平衡: 左子节点和右子节点数量相等
二叉: 每个节点最多有2个子节点
查找: 节点存储的元素是按照大小顺序存储的
特点:
元素存储过程中就完成了大小排序
查询比链表快, 增删比数组快 (数组和链表的折中)
02-List集合
特点:有序集合、带索引、可以有重复的元素、可以用equals方法判断
2.1). 常用方法:
List<E> list = new ArrayList<>();
list.add(int index, E e);//添加到指定位置
list.get(int index);//返回指定位置的元素
list.remove(int remove);//删除指定位置的元素
list.set(int index,E e);//替换指定位置的元素,并更新集合
2.2). ArrayList集合
底层的数 据结构:数组
特点: 查询快 增删慢 线程不安全, 效率高
2.3). LinkedList 集合
底层的数据结构:链表
特点: 查询慢 增删快 线程不安全, 效率高
特有成员方法(主要操作开头和末尾元素)
java.util.LinkedList<E>类:
List<E> list = new LinkedList<>();
list.addFirst(E e); //将指定元素插入此列表的开头
list.addLast(E e);// 将指定元素添加到此列表的结尾
list.getFirst(); //返回此列表的第一个元素
list.getLast(); //返回此列表的最后一个元素
list.removeFirst(); //移除并返回此列表的第一个元素
list.removeLast(); //移除并返回此列表的最后一个元素
list.pop();// 其实就是removeFirst())从此列表所表示的栈中弹出一个元素
list.push(E e); //其实就是addFirst())将元素添加到此列表所表示的栈中
2.4).Vector集合 (几乎不用)
底层的数据结构: 数组
特点: 查询慢 增删快 (同步)线程安全, 效率低
03-Set集合体系
3.1). HashSet集合
1).Set集合体系特点:
元素不可重复 没有索引
2)HashSet特点:
元素不可重复 没有索引 元素存取无序 (存入和取出顺序有可能不一致)
底层采用 哈希表 结构. (查询快)
哈希表 = 数组 + 链表或红黑树
3).常用方法
Set<E> set = new HashSet<>();
set.add();//添加元素 元素的 hashCode() 和 equals() 方法判断是否重复. 重复则不添加并返回false,
不重复则添加并返回true
hashCode() 方法的作用:有可能将"不同的对象"计算出"相同的哈希值", 这称为"哈希冲突", 在出现冲突后,
一般再通过equals() 方法来继续判断对象是否"相等"
4).HashSet原理: 哈希表结构
哈希表:
JDK 8以前 : 哈希表 = 数组 + 链表
JDK 8及之后 : 哈希表 = 数组 + 链表或红黑树
数组中存储的每个元素, 是哈希值相同的一组节点的链表或红黑树
5).HashSet原理: 存储元素不重复的原理
重写equals()和hashCode()方法 先判断hashCode()是否相同,在用equals()进行判断
3.2). LinkedHashSet集合
LinkedHashSet特点:
元素存取有序 (存入和取出顺序一致) 元素不可重复 没有索引
LinkedHashSet底层数据结构:
哈希表 + 链表 (也就是: 数组 + 链表或红黑树 + 链表)
其中, 哈希表用于存储数据, 额外的链表用于记录元素添加时的先后顺序, 以便在获取元素时保持顺序一致
3.3.)可变参数
格式: 用在方法的参数中
修饰符 返回值类型 方法名(int... 变量名) {
// 可以直接将 变量名 当作 数组名 使用
}
3.4).Collections集合工具类
java.util.Collections类: 操作集合的工具类
Collections.addAll(Collection<? super T> c, T... elements);//往集合中添加一些元素
Collections.shuffle(List<E> list);//打乱集合顺序
Collections.sort(List<T> list);//将集合中元素按照默认规则排序
Collections.sort(List<T> list,Comparator<? super T> c);//将集合中元素按照指定规则排序
3.4.1). Comparable接口和Comparator接口区别
*Collections.sort(List<T> list,Comparator<? super T> c);//将集合中元素按照指定规则排序
不能重复:重写hashCode();和equals();方法,查看存入对象重写toString();
Comparable: 让JavaBean自身具有可比较性 (自己和其他人比)
类继承Comparable<E> 重写compareTo( E o);方法 return this.(....) - o.(...);
Comparator: 定义一个比较器类, 用比较器对象比 (让第三个人来帮两个人比较)
Comparator排序 用匿名对象 new Comparator<>() 重写 int compare(E o1, E o2) 方法
return o1.(...) - o2.(..) =-1 升序
return o2.(...) - o2(..) =1 降序
04 - Map集合
java.util.Map<K, V>接口
4.1.1) Map集合特点:
1. 是双列集合, 一个元素包含两个值 (键key, 值value) 键值对
2. key和value的类型可以相同, 也可以不同
3. key不允许重复, value可以重复
4. key和value是一一对应的, 一个键只能对应一个值
4.1.2) Map中常用方法
java.util.Map接口: 双列集合的顶层
Map <E,E> map = new HashSet<>();
map.put(K key, V value); //添加/修改 键值对. 如果键存在, 新值替换已有值, 如果键不存在, 添加键值对, 返回null
map.remove(Object key); //根据键删除键值对, 返回被删除元素的值 如果键不存在, 返回null
map.get(Object key); //根据键获取值. 如果键不存在, 则返回null
map.containsKey(Object key); // 判断是否包含指定的键
Set<K> keySet(); //获取Map集合中所有的键, 存储到Set集合中
Set<Map.Entry<K,V>> entrySet(); //获取到Map集合中所有的Entry对象的集合(Set集合)
4.1.3)Map遍历方式
(-) keySet()遍历步骤:
Map<String, String> map = new HashMap<>();
[Java] 纯文本查看 复制代码 Set<String> keys = map.keySet();
for (String key : keys) {
// 通过每个键获取值
String value = map.get(key);
// 打印当前键值对
System.out.println(key + "=" + value);
}
sout("------------------------------------");
[Java] 纯文本查看 复制代码 Iterator<String> iterator = people.iterator();
while (iterator.hasNext()){
String key = iterator.next();
String value = map.get(key);
System.out.println(key+" "+ value);
}
(二)Entry键值对对象介绍
entrySet()方法遍历Map步骤:
Map<String, String> map = new HashMap<>();
[Java] 纯文本查看 复制代码 Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
// 通过Entry对象获取每个键值对
String value = entry.getKey();
String value = entry.getValue();
// 打印当前键值对
System.out.println(key + "=" + value);
}
sout("------------------------------");
[Java] 纯文本查看 复制代码 Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> it = entries.iterator();
while (it.hasNext()){
Map.Entry<String, Integer> next = it.next();
String key = next.getKey();
Integer value = next.getValue();
System.out.println(key+ " "+ value);
}
HashMap存储自定义数据类型作为键
HashMap存储自定义JavaBean对象作为key保证key唯一不重复, 需要让JavaBean重写 hashCode() 和 equals() 方法
LinkedHashMap底层: 哈希表 + 链表
key不允许重复, 但key存取有序
4.2). Hashtable类
Hashtable和HashMap:
相同点:
1. 底层都是哈希表
不同点:
1. Hashtable不允许存储 null 值和 null 键; HashMap允许存储 null 值和 null 键
2. Hashtable线程安全效率低; HashMap线程不安全效率高
Hashtable目前很少使用.
但其子类 Properties 集合, 可以与IO流结合使用, 应用较多
4.3).JDK9对集合添加的优化
java.util.List接口:
// 静态方法
static List<E> of(E... e): 返回包含指定元素的 不可变List 集合
java.util.Set接口:
// 静态方法
static Set<E> of(E... e): 返回包含指定元素的 不可变Set 集合
java.util.Map接口:
// 静态方法
static Map<K, V> of(K k1, V v1, ...): 返回包含指定键值对的 不可变Map 集合
注意事项:
1. of() 方法只适用于List接口, Set接口, Map接口, 不适用于接口的实现类
2. of() 方法的返回值是一个不可变的集合, 集合不能再使用 add(), put() 方法添加元素, 会抛出异常
3. Set接口和Map接口在调用 of() 方法的时候, 不能有重复的元素, 否则会抛出异常
4.4)Debug调试
f8:逐行执行程序
f7:进入到方法中
shift+f8:跳出方法
f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
ctrl+f2:退出debug模式,停止程序
Console:切换到控制
05 - 异常
5.1).异常的概念与体系
异常:程序执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止
java.lang.Throwable // 体系最顶层
|_ Error // 不应该试图捕获的严重问题, 不能处理的错误
|_ Exception // 可以处理的异常
5.1.1).异常的分类
错误(Error): 不能捕获处理的严重问题. 绝症
必须将程序停下来, 修改代码才能解决
错误的类名都是 "XxxError" 方式
异常(Exception): 可以捕获处理的问题. 发烧感冒吃个药就好了
程序执行起来后, 如果有合适的处理方式, 即使发生异常, 程序也能处理该异常并继续运行
异常的类名都是 "XxxException" 方式
1. 编译时异常:
编译时期就会发生的异常, 必须在编译时期处理 Unhandled exception XxxException
2. 运行时异常:
编译时正常, 运行时才会发生的异常
5.2).throw制造异常
格式: throw new 异常类名("异常原因字符串");
注意:
1. throw 必须写在方法的内部
2. throw 后面new的异常对象, 必须是 "Exception" 或 "Excetion的子类" 的对象
3. 一个方法内部 throw 了一个异常对象, 则该方法可以分为2种情况来处理该异常:
如果 throw 的是"运行时异常"(RuntimeException及其子类)对象, 那么可以不处理
该异常最终会交给JVM处理, 结果就是: 打印异常信息到控制台, 并立刻结束程序
如果 throw 的是"编译时异常"(Exception及其子类), 则必须处理:
处理方式1: throws 抛出
处理方式2: try...catch 捕获
5.3).异常处理的方式
(一).throws声明抛出异常
格式: //throws 后面的异常类名, 一般是 Exception 或 Exception的子类
修饰符 返回值类型 方法名() throws 异常类名1, 异常类名2, ... {
}
// 示例
[Java] 纯文本查看 复制代码
public static void readFile(String filename) [color=Red]throws [color=Blue]FileNotFoundException[/color][/color] {
if (!"a.txt".equals(filename)) { a.java
[color=Red]throw new[color=Blue] FileNotFoundException[/color]("路径不对");[/color]
}
if (filename.endsWith(".txt")) { // name.startsWith("张")
// 判断当前字符串是否以参数的字符串结尾
}
}
(二).捕获异常
try...catch:
捕获并处理异常 (方法内部自己处理异常, 不交给别人, "自己背锅")
格式:
[Java] 纯文本查看 复制代码 try {
// 可能产生异常的代码
} catch (异常类名 变量名) {
// 处理异常的代码
// 一般会将异常信息存储到日志中
}
...
} catch (异常类名 变量名) {
// 处理异常的代码
// 一般会将异常信息存储到日志中
}
或者是:
[Java] 纯文本查看 复制代码 try {
// 可能发生异常的代码
} catch (异常类型1 | 异常类型2 | 异常类型3 | ... 异常对象名) {
// 处理任意一个异常的代码
}
注:
1.如果第一个就是异常,代码就会跳出不会在执行
2. 父类方法声明的异常是什么样的, 子类重写的方法声明异常就什么样, 保持一致即可
5.4)Throwable中的3个异常处理方法
String getMessage(): 异常的信息. 没有原因返回null
String toString(): 异常的类型和原因信息
void printStackTrace(): 使用标准错误输出流打印异常信息
5.5)finally代码块
格式:
[Java] 纯文本查看 复制代码 try {
// 可能发生异常的代码
} catch(异常类型 异常变量名) {
// 处理异常
}
...
catch(异常类型 异常变量名) {
// 处理异常
} finally {
// 无论是否发生异常, 是否捕获, 最后都会执行的代码.
// 通常在这里执行释放资源的操作
}
注:
1. finally 必须和 try...catch 一起使用
2. finally 一般用于释放资源 (IO流时用到)
3.如果 finally 代码块中有 return 语句, 则永远返回 finally 中的 return 语句的值
应该避免在 finally 中写 return 语句
5.6)自定义异常类
如果Java提供的异常类不足以满足我们的需求, 我们也可以自己定义异常类
定义编译时异常: 继承 Exception
定义运行时异常: 继承 RuntimeException
定义2个构造, 一个无参, 一个有String参数
06-多线程
6.1)并发与并行
并发: (交替执行) 指两个或多个事件在"同一时间段内"发生
并行: (同时执行) 指两个或多个事件在"同一时刻"发生 (同时发生)
程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。
随着调用mt的对象 的start方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。
每一个执行线程都有一片自己所属的栈内存空间
6.2)创建多线程程序
(一).继承Thread类
[Java] 纯文本查看 复制代码 MyThread extends Thread
//创建线程对象
MyThread mt = new MyThread();
mt.start(); (=)定义Runnable接口
[Java] 纯文本查看 复制代码 MyRunnable implements Runnable
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t = new Thread(mr, "小强");
t.start();
Thread和Runnable的区别
1. 适合多个相同的程序代码的线程去共享同一个资源。
2. 可以避免java中的单继承的局限性。
3 . 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
6.3)匿名内部类方式实现线程的创建
//new Thread()
[Java] 纯文本查看 复制代码 new Thread(){
@Override
public void run() {
//给线程一个名字
Thread.currentThread().setName("小明");
for (int i = 0; i < 10; i++) {
//获取线程的名字
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}.start();
//普通版Runnable r = new Runnable()
[Java] 纯文本查看 复制代码 Runnable r = new Runnable() {
@Override
public void run() {
Thread.currentThread().setName("小亮");
for (int i = 10; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
};
new Thread(r).start();
//Runnable简化版
[Java] 纯文本查看 复制代码 new Thread(new Runnable() {
@Override
public void run() {
Thread.currentThread().setName("小红");
for (int i = 20; i < 30; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}).start();
}
07-线程安全
7.1).线程同步
(一).同步代码块
Object lock = new Object();
synchronized(lock){
需要同步操作的代码
}
注:
1. 锁对象 可以是任意类型。
2. 多个线程对象 要使用同一把锁。
(二).同步方法
public synchronized void method(){
可能会产生线程安全问题的代码
}
注:
非static 方法 同步锁就是this
static方法,使用当前方法所在类的字节码对象(类名.class)。
(三).Lock锁
Lock lock = new ReentrantLock();
lock.lock();
可能会产生线程安全问题的代码
lock.unlock();
08-线程状态
8.1)六种状态
NEW(新建) Runnable(可运行) Blocked(锁阻塞)
Waiting(无限等待) Timed Waiting(计时等待) Teminated(被终止)
注:
sleep与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。
一个调用了某个对象的 Object.wait 方法的线程会等待另一个线程调用此对象的
Object.notify()方法 或 Object.notifyAll()方法。
|
|