刘亚雄:
List.Set.数据结构.COllections一.数据结构栈:特点:先进后出(FILO,First In Last Out)入口出口在一侧 栈适用场景: 栈内存:(main方法先进栈调用,main方法中其他方法都调用完毕后,main才能出栈) 反转内容:(车尾变车头) 队列:特点:先进先出入口出口在两侧 数组:特点:查询快,增删慢查询快:数组的地址是连续的,我们通过数组的地址值可以找到数组,通过数组的索引可以快速查找某一元素 增删慢:数组的长度是固定的,我们想要增加/删除一个元素,必须创建一个新数组,把源数组的数据复制过来. 链表:特点:查询慢,增删快查询慢:链表中的地址不是连续的,每次查询元素都必须从头开始查询 增删快:链表结构,增加/删除一个元素,对链表的整体结构没有影响,所以增删快. 链表中的每一个元素也称之为一个节点,一个节点包含了一个数据源(存储数组),两个指针域(存储地址). 单链表:数据<->下一个节点的地址单向链表:链表中只有一条链子,不能保证元素的顺序(存储和去除元素的顺序可能不一致) 双向链表:链表中有两条链子,有一条链子是专门记录元素的顺序,是一个有序的集合. 红黑树特点: 趋近于平衡树,查询速度非常快,查询叶子节点最大次数和最小次数不能超过2倍使用场景:查询和增删都有,需要元素自动排序的场景 约束: 1.节点可以是红色的或者黑色的 2.根节点是黑色的 3.叶子节点(空节点)是黑色的 4.每个红色的节点的子节点都是黑色的 5.任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同. 树的遍历:往左走
返回当前节点的值
往右走
返回上一层节点二叉树:分支不能超过两个 排序树/查找树:在二叉树的基础上,元素有大小顺序的,左子树小,右子树大 平衡树:左孩子和右孩子相等 不平衡树:左孩子和右孩子不相等 List集合特点: 1.有序的集合,存储元素和取出元素的顺序是一致的. 2.有索引,包含了一些带索引的方法 3.允许存储重复的元素 list接口中带索引的方法(特有):public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。 public E get(int index):返回集合中指定位置的元素。 public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。 public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素
ArrayList集合 ArrayList集合数据存储的结构是数组结构,元素增删慢,查找快.线程不安全,效率高. 适用于查询多,增删少的场景 LinkedList集合LinkedList集合数据存储的结构是链表结构,查询慢,增删快. 线程不安全,效率高 此集合包含了大量操作首位的方法. 下列方法了解即可: public void addFirst(E e):将指定元素插入此列表的开头。 public void addLast(E e):将指定元素添加到此列表的结尾。 public void push(E e):将元素推入此列表所表示的堆栈。相当于addFirst public E getFirst():返回此列表的第一个元素。 public E getLast():返回此列表的最后一个元素。 public E removeFirst():移除并返回此列表的第一个元素。 public E removeLast():移除并返回此列表的最后一个元素。 public E pop():从此列表所表示的堆栈处弹出一个元素。相当于removeFirst public boolean isEmpty():如果列表不包含元素,则返回true。
Vertor集合 集合数据存储的结构是数组结构, 特点: 查询慢,增删快,线程安全,效率低 set接口特点: 1.不允许存储重复的元素 2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历 HashSet(implements set) 特点: 1.不允许存储重复的元素 2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历 3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致 4.底层是一个哈希表结构(查询速度非常的快) 哈希值: 是一个十进制的整数,由系统随机给出(就是对象的地址值) native int hashCode(); "重地"与"通话"的哈希值一样(值一样叫做哈希冲突) HashSet集合存储数据的结构(哈希表): jdk1.8之前:哈希表=数组+链表 jdk1.8之后:哈希表=数组+链表 或者 哈希表=数组+红黑树(提高查询的速度) 哈希表的特点:速度快 数组结构:把元素进行了分组(相同哈希值的元素是一组). 链表/红黑树结构把相同哈希值的元素连接到一起 如果链表的长度超过了8位,那么就会把链表转换为红黑树(提高查询速度) HashSet存储自定义类型元素: set集合保证元素唯一: 储存的元素(String,Integer....Student.Person..).必须重写hashCode方法和equals方法 要求:同名 同年龄的人,视为同一个人,只能储存一次. LinkedHashSet集合:特点: 底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序. 可变参数使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数 使用格式:定义方法时使用: 修饰符 返回值类型 方法名(数据类型...变量名) 可变参数的原理: 可以变参数的底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数 传递参数的个数可以是0个,1,2...多个 注意事项: 1.一个方法的参数列表,只能有一个可变参数 2.如果方法的参数有多个,那么可变参数必须写在参数列表的末尾 终级写法(Object...obj) Collections常用功能: public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。 public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。 public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。 public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。
注意:public static <T> void sort(List<T> list使用前提 被排序的集合里边存储的元素,必须实现Comparable接口,重写接口中的方法compareTo定义排序规则 排序规则: 自己-参数:升序 参数-自己:降序 Comparator与Comparable区别: Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较规则的compareTo方法 Comparator:相当于找一个第三方的彩票,比较两个 Comparator排序规则: o1-o 2:升序 o2-o1:降序 一. List集合特点 二.常见的数据结构 栈队列数组链表红黑树哈希表 = 数组 + 链表/红黑树 三.数组结构特点 查询快增删慢 四.栈结构特点 先进后出入口出口是同一个 五.队列结构特点 先进先出入口出口在两侧 六.单向链表结构特点 查询慢增删快 栈, 队列 七.Set集合的特点 八.哈希表的特点 哈希表 = 数组 + 链表/红黑树 先调用 hashCode()算出哈希值, 根据哈希值判断数组中是否有重复元素 如果要没有, 就添加 如果有元素, 哈希值冲突 则调用元素的 equals() 遍历 链表/红黑树 依次比较 如果有重复的, 则不添加 如果没有重复的, 则添加 九.使用HashSet集合存储自定义元素 去重 重写 hashCode() 重写 equals() 十.说出可变参数的格式 方法名(参数类型... 变量名) { // 当作数组来使用} 方法名(); // 数组 注意事项: 只能有1个可变参数, 必须放在最后 十一.集合工具类 Collections类 static addAll(Collection c, T... t) static shuffle(List list) static sort(List list) static sort(List list, Comparator c) 十二.能够使用Comparator比较器进行排序 static sort(List list, Comparator c) 传递Comparator实现类对象, 重写 compare(T o1, T o2) 规则: o1 - o2 升序 o2 - o1 降序 Map双列集合Map<k,v> K代表键的类型,V代表值的类型 Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值 Map集合特点 1.Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)键值对 2.Map集合中的元素,key和value的数据类型可以相同,也可以不同 3.Map集合中的元素,key是不允许重复的,value是可以重复的 4.Map集合中的元素,key和value是一一对应的 映射:一对一关系,建和值的对应关系 mapping. 常用类:HashMap<K,V> implements Map<K,V> 特点: 1.HashMap集合底层是哈希表:查询的速度特别快 jdk1.8之前:数组+单向链表.............................. jdk1.8之后:数组+单向链表/红黑树 2.HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致. LinkedHashMap集合(HashMap的子类) 特点: 1.LinkedHashMap集合底层是哈希表+链表(保证迭代顺序) 2.LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的. 常用方法public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。 备注:存储键值对的时候,key不重复,返回值V是null 存储键值对的时候,key重复,返回值V是被替换的value值. public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。 public V get(Object key) 根据指定的键,在Map集合中获取对应的值。 boolean containsKey(Object key) 判断集合中是否包含指定的键。 public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。 public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
Map集合第一种遍历方式:键找值 1.使用Map集合的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中 2.遍历set集合,获取Map集合中的每一个key 3.通过Map集合中的方法get(key),通过key找到value Map集合第二种遍历方式:使用Entry对象遍历
1.使用Map集合中的方法EntrySet(),把Map集合中的多个Entry对象取出来,存储到一个Set集合中
2.遍历Set集合,获取每一个Entry对象
3.使用Entry对象中的方法getKey()和getValue()获取键与值.Map.Entry<K,V>:在Map接口中有一个内部接口Entry Entry对象就是一个节点,节点中存储了key和value 作用:当Map集合一创建,那么就会在Map集合中创建一个Entry对象,用来记录键与值(键值对对象) LinkedHashMapextends HashMap 底层原理:哈希表+链表(记录元素顺序) 元素不允许重复,存取有序 Hashtable<k,v>Hashtable iplements Map<k,v>接口 特点: Hashtable与HashMap的区别相同点:底层都是一个哈希表, 1.Hashtable是一个线程安全的集合,是单线程集合,速度慢 而HashMap是一个线程不安全的集合,是多线程的集合,速度快 2.HashMap集合可以存储null值,null键 而Hashtable集合,不能存储null值,null键 3.Hashtable和Vector集合一样,在jdk1.2之后被(HashMap,ArrayList)取代 Hashtable的子类Properties依然活跃 Properties集合是一个唯一和IO流相结合的集合 TreeMap对键排序.与TreeSet类似JDK9对集合添加的优化 jdk9的新特性: List接口,Set接口,Map接口:里边增加了一个静态的方法of,可以给集合一次性添加多个元素. static<E>List<E>of(E...elements) 使用前提: 当集合中存储的元素的个数已经确定了,不在改变时使用 注意:
1.of方法只适用于以上三个接口,不适用于接口的实现类
2.of方法的返回值是一个不能改变的集合,集合不能再使用add.put方法添加元素,会抛出异常.
3.Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常.Debug追踪 又叫(调试bug) Debug调试程序: 可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug. 使用方式: 在行号右边,鼠标左键单击,天机断点(每个方法的第一行,哪里有bug添加到哪里) 右键,选择Debug执行程序 程序就会停留在添加的第一个断点处. F8:逐行执行程序 F7:进入到方法中 shift+F8:跳出方法 F9:跳到下一个断点,如果没有下一个断点,就结束程序 ctrl_+F2:退出debug模式,停止程序 Console:切换到控制台 Debug调试程序:
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug
使用方式:
在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里)
右键,选择Debug执行程序
程序就会停留在添加的第一个断点处
执行程序:
f8:逐行执行程序
f7:进入到方法中
shift+f8:跳出方法
f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
ctrl+f2:退出debug模式,停止程序
Console:切换到控制台一、请简述Map 的特点。 Map每个元素由键与值两部分组成 Map键不能重复,每个键对应一个值 键和值可以为null 二、说出Entry键值对对象遍历Map集合的原理。 Map中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在Map中是一一对应关系,这一对对象又称做Map 中的一个Entry(项)。Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。 Map.entrySet 遍历获取每一个entry Entry.getkey Entry.getvalue 异常,多线程异常:2中处理异常的方式: 1.throws 声名抛出 2.try-catch-finally 捕获并处理 异常 :指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。 在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。 java.lang.Throwable:类是Java语言中所有错误或者异常的超类. Exception:编译器异常 RuntimeException:运行期异常 Error:错误 必须修改源代码,程序猜能执行 异常的处理 throw 关键字: 作用: 可以使用throw关键字在指定的方法中抛出指定的异常 格式: throw new xxxException("异常产生的原因:") 注意: 1.throw关键字必须写在方法的内部 2.throw关键字后边new的对象必须是Exception或者是其子类对象 3.throw关键字抛出指定的异常对象,我们就必须处理这个异常对象 throw关键字后边创建的是RuntimeException或者RuntimeException的子类对象我们可以不处理,默认交给JVM处理 若创建的是编译异常,我们就必须处理这个异常,要么throws要么 try..catch
注意:
在编写程序时,我们必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接受参数。那么,当调用方法使用接受到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。Objects非空判断(了解)public static <T> T requireNonNull(T obj):查看指定引用对象不是null。 Objects.requireNonNull(obj," "); 声明异常throws throws关键字:异常处理的第一种方式,交给别人处理. 声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ } 注意事项:
1.throws关键字必须写在方法声名出
2.throws关键字后边声明的异常必须是Exception或者是其子类
3.方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常
如果抛出的多个异常对象有字符类关系,那么直接声明父类异常即可.
4.调用了一个声名抛出异常的方法,我们就必须处理声明的异常.
要么继续使用throws声明抛出,交给方法调用者处理,最终交给JVM,
要么try,..catch自己吃力异常s.endsWith(".txt")判断当前字符串是否以.txt结尾 s.startWith("txt")判断当前字符串是否以txt开头 捕获异常try…catch格式:try { // 可能产生异常的代码 } catch (异常类名 变量名) { // 处理异常的代码 // 一般会将异常信息存储到日志中 } ... } catch (异常类名 变量名) { // 处理异常的代码 // 一般会将异常信息存储到日志中 } 注意: 1.try中可能会抛出多个异常对象,那么久科院使用多个catch来处理这些异常对象 2.如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try..catch之后的代码. 如果try中没有产生异常,那么就不会执行catch中的异常处理逻辑,执行完try中的代码,继续执行try..catch之后的代码. Throwable类中定义了一些查看方法:public String toString():获取异常的类型和异常描述信息(不用)。返回详细消息 public void printStackTrace():打印异常的跟踪栈信息并输出到控制台。打印的是最全面的信息 finally 代码块有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。 注意: 1.finally不能单独使用,必须和try一起使用 2.finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO); 多个异常使用捕获该如何处理? 多个异常分别处理。 多个异常一次捕获,多次处理。 多个异常一次捕获一次处理。 注意事项: 一个try多个catch,catch里边定义的异常变量,如果有字符类关系,那么子类的异常变量必须写在上面,否则就会报错
运行时异常被抛出可以不处理。即不捕获也不声明抛出。 如果finally有return语句,永远返回finally中的结果,避免该情况. 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出 父类异常什么样,子类异常就什么样
自定义异常异常类如何定义:格式: public class xxxException extends Exception/RuntimeException{ } 注意: 1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类 2.自定义异常类,必须得继承Exception或者RuntimeException 继承Exception:那么自定义的异常类就是一个编译器异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try..catch 继承RuntimeException:是一个运行期异常,无需处理,交给虚拟机处理即可. 多线程并发与并行进程:一个应用程序在内存中的一次执行过程. 每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。 线程: 线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 多线程好处: 效率高 多个线程直接互不影响. 程序>进程>线程 线程调度 线程的调度方式: 1.分时调度 平均占用cpu时间 2.抢占式调度 根据优先级,若优先级一样随机选择一个线程, Java使用的为抢占式调度。 创建线程类 主线程:执行主(main)方法的线程 单线程程序:java程序中只有一个线程 多线程程序的第一种创建方法 1.定义类,继承Thread类 2.重写run()方法,run方法内部是线程要执行的任务 3.创建Thread子类的对象, 4.调用start()方法启动线程 java.lang.Thread类: 表示线程. 实现了Runnable接口 注意: 必须调用start()方法来开启线程,不能直接调用run()方法,调用run()会变成单线程. 同一个线程对象,不能多吃调用start(0方法. java是抢占式调度,不同线程的代码,执行顺序是随机的. 练习一:异常的体系问题: 请描述异常的继承体系 请描述你对错误(Error)的理解 请描述你对异常(Expection的理解) 请描述你对运行时异常(RuntimeException)的理解 1.异常继承体系为: 异常的根类是 java.lang.Throwable,其下有两个子类: java.lang.Error 与 java.util.Exception 。而Exception又分为编译时期异常:checked异常,与运行时期异常:runtime异常。 2.Error:表示不可修复的恶性的错误,只能通过修改代码规避错误的产生,通常是系统级别的,所以很严重。 3.Exception:表示可修复的良性(相对于错误)的异常,异常产生后程序员可以并且应该通过代码的方式纠正,使程序继续运行,是必须要处理的。 4.运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。 throw与throws的区别1.请描述throw的使用位置,作用是什么? throw关键字通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行。 2.请描述throws的使用位置,作用是什么? throws关键字通常被应用在声明方法时,用来指定可能抛出的异常。多个异常可以使用逗号隔开。当在主函数中调用该方法时,如果发生异常,就会将异常对象抛给方法调用处.
public class RunnableImpl implements Runnable {
// 成员变量创建锁对象, 该锁对象也要所有线程共享唯一一个
Lock lock = new ReentrantLock();
@Override
public void run() {
// 加锁
lock.lock();
try {
// 操作共享变量的代码...
} finally {
// 在finally中保证释放锁
lock.unlock();
}
}
}
|