A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小石姐姐 于 2018-8-3 09:05 编辑

集合、异常、线程

一.  集合       (一)数据存储的常用结构:栈, 队列, 数组, 链表, 红黑树
​              1.栈:先进后出(FILO , First In Last Out), 入口和出口在同一侧
​                适用场景:
​                        栈内存:main方法先进栈调用,main方法中的其他方法都调用完毕后,main才能出栈
​                        反转内容:车尾变车头,进去再出来就反转了              
              2.队列:先进先出(FIFO, First In First Out), 入口和出口在集合的两侧
​                适用场景:秒杀,抢购,在线售票,  高并发场景
​             3.数组:
​                查询快:数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引可以快速查找某一个元素
​                增删慢:数组的长度是固定的,我们想要增加/删除一个元素,必须创建一个新数组,把原数组的数据复制过来
​             4.链表:
​                查询慢:链表中的地址不是连续的,每次查询元素,都必须从头开始查询
​                增删快:链表结构,增加/删除一个元素,对链表的整体结构没有影响,所以增删快
​                 单向链表:链表中只有一条链子,不能保证元素的顺序(存储元素和取出元素的顺序有可能不一致)
​                双向链表:链表中有两条链子,有一条链子是专门记录元素的顺序,是一个有序的集合
​                适用场景:查询少,增删多的场景
​             5.红黑树:是一种 平衡 二叉  查找   树
​                特点:趋近于平衡树,查询的速度非常的快,查询叶子节点最大次数和最小次数不能超过2倍
​                添加元素到红黑树:元素自动排序      左小,右大.
                 查找树的遍历:
​                        从根节点开始,每个节点做3个操作:
​                                ①先往左找有没有子节点,直到没有左子节点
​                                ②返回当前节点的数据
​                                ③往右找右子节点,右边没有则返回父节点       (二)List接口
​            1.接口的特点:
​                ①有序的集合,存储元素和取出元素的顺序是一致的(存储132 取出123)
​                ②有索引,包含了一些带索引的方法
​                ③允许存储重复的元素
​            2.接口特有的方法:
                 
​            
[AppleScript] 纯文本查看 复制代码
   ①void add(int index , E element): 将指定的元素,添加到指定索引的位置上[/align]​                 ②E  remove (int index): 移除指定位置的元素,返回的是被移除的元素
​                 ③E  set ( int index, E element): 用指定的元素替换集合中指定位置的元素,返回的是原来的元素
​                 ④E get( int index): 返回集合中指定位置的元素.
​           3.List子集合
​               (1).ArrayList集合
​                   底层为数组结构,查询快,增删慢,线程不安全,效率高
​               (2).LinkedList集合
​                           特点:①底层是一个链表结构:查询慢,增删快
​                                   ②里边包含了大量操作首尾元素的方法
​                            注意:使用LinkedList集合特有的方法,不能使用多态
​                        LinkedList方法:
​                              
[AppleScript] 纯文本查看 复制代码
 ①void addFirst(E  e):将指定元素插入此列表的开头[/align]​                      ②void addLast(E  e):将指定元素插入此列表的结尾
​                      ③void push(E  e):将元素推入此列表所表示的堆栈,等效于addFirst(E  e)
​                      ④E getFirst( ): 获取此列表中的第一个元素
​                      ⑤E getLast( ):获取此列表中的最后一个元素
​                      ⑥E removeFirst( ):移除并返回列表的第一个元素
​                      ⑦E removeLast( ):移除并返回此列表的最后一个元素
​                       ⑧E pop( ):从列表所表示的堆栈处弹出一个元素,等效于 removeFirst( )
      (三). Set接口:元素不可重复,无索引
​               1.HashSet类:底层是哈希表,元素无序,元素不可重复(用hashCode()和equals()方法来判断)
​                                   获取元素时,先获取hashCode值进行比较,如果相同,则是哈希冲突,进行equals判断如果不重复,则添加
​                                   如果重复,则哈希冲突,再比较相同哈希值元素的equals()
​                                   如果equals()方法比较有相同的,则元素重复,不添加
​                                  如果equals()方法比较没有相同的,则没有重复的,添加
​             2.哈希值:是一个十进制的整数,由系统随机给出,一般是通过将对象的内部地址转换成一个整数来实现的
​             3.哈希表:
​                  JDK 8以前 : 哈希表 = 数组 + 链表
​                  JDK 8以后 : 哈希表 = 数组 + 链表/红黑树(提高查询的速度);
​                  特点 : 速度快             4.LinkedHashSet类:哈希表+链表
​                         特点:①元素存取有序(存入和取出顺序一致)
​                                 ②元素不可重复
​                                 ③没有索引        
                        总结:要存储的元素可以重复的,用List集合:
​                                 增删少,用ArrayList
​                                 增删多,用LinkedList
​               要存储的数据要求不重复,或者相对一个集合去重,用Set集合:
​                                 无序存取,用HashSet
​                                 有序存取,用LinkedHashSet
       (四), 可变参数
​                  1.使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数.
​                  2.使用格式:定义方法时使用
​                       修饰符  返回值类型  方法名( 数据类型...变量名){}
​                  3.可变参数的原理:
​                         可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数传递的参数个                           数,可以是0个,1,2...多个               
​                 4.注意事项:
​                       ①一个方法的参数列表,只能有一个可变参数
​                       ②如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
       (五), Collections集合工具类
                 
​                 
[AppleScript] 纯文本查看 复制代码
 1.static?<T>?boolean?addAll(Collection<T>?c,?T...?elements) :往集合中添加一些元素[/align]​                    2.static?void?shuffle(List<?>?list) :打乱集合顺序
​                    3.static?<T>?void?sort(List<T>?list) :将集合中元素按照默认规则排序
​                         需要实现Comparable<E>接口,重写 int  compareTo(E  e)方法
​                        大小的比较通过compareTo( )方法的返回值确定:
​                                如果是负数:        当前元素比被比较元素小
​                                如果是0:                当前元素与被比较元素相等
​                                如果是整数:        当前元素比被比较元素大
​                        规则:    this-参数: 升序                  参数-this:降序
​                 4.
[AppleScript] 纯文本查看 复制代码
static?<T>?void?sort(List<T>?list,Comparator<??super?T>?) :将集合中元素按照指定规则排序    
  
           (六),Map集合:        java.util.Map<k,v>集合            
   (1)Map集合的特点:
​                        ①.Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
​                        ②.Map集合中的元素,key和value的数据类型可以相同,也可以不同
​                        ③.key不允许重复,value可以重复
​                        ④.key和value是一一对应的,一个键只能对应一个值
​                 Map集合适合存储一对一关系的数据
              (2)Map中的子类:
​                    1.HashMap集合的特点:
​                        ①.Hashmap集合底层是哈希表,是一个线程不安全的集合,是多线程的集合,查询的速度特别快
​                        ②.无序,存储和取出的顺序有可能不一致
​                    2.LinkedHashMap的特点:
​                        ①.LinkedHashMao集合底层是哈希表+链表(保证迭代的顺序)
​                        ②.LinedHashMap集合是一个有序的集合,存储和取出的顺序是一致的
​                补充:
​                        HashSet底层使用的就是HashMap        
​                        LinkedHashSet底层使用的就是LinkedHashMap
​                   3.Hashtable集合底层也是哈希表,是一个线程安全的集合,是单线程的集合,查询速度慢        
​        对比:
​                      ①Hashtable不允许存储null值和null键,而HashMap可以
​                      ②Hashtable线程安全但效率低,而HashMap线程不安全但效率高
​              (3)Map中的常用方法

​               
[AppleScript] 纯文本查看 复制代码
[/align][align=left]             1. V?put(K?key,?V?value): 添加/修改键值对. 如果键存在, 则用新值替换旧的值[/align][align=left]             2. V?remove(Object?key): 根据键删除整个键值对, 返回被删除元素的值 [/align][align=left]             3. V?get(Object?key): 根据键获取值. 如果键不存在, 则返回null [/align][align=left]             4. boolean containsKey(Object key): 判断是否包含指定的键[/align][align=left]             5. Set<K>?keySet(): 获取Map集合中所有的键, 存储到Set集合中                   6. Set<Map.Entry<K,V>>?entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)
         
      (七),  JDK9对集合添加的优化
​               List接口,Set接口,Map接口:里边增加了yige静态的方法of,可以给集合一次性添加多个元素
​                   使用前提:当集合中存储的元素的个数已经确定了,不再改变时使用.
​                  注意事项:①of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
​                                     ②.of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
​                                  ③.Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
       (八), Debug
​               1. 断点:                 breakpoint, 在debug模式下, 程序运行到断点会暂停住, 便于我们在程序运行过程中查看            
               2. Debug调试程序:                         可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug                 
           使用方式:                          
          在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里) 右键,选择Debug执行程序, 程序就会停留在添加的第一个断点处              
3. 执行程序:               
[AppleScript] 纯文本查看 复制代码
    f8:逐行执行程序                   f7:进入到方法中                   shift+f8:跳出方法                  f9:跳到下一个断点,如果没有下一个断点,那么就结束程序                    ctrl+f2:退出debug模式,停止程序                    Console:切换到控制台

二, 异常   
[AppleScript] 纯文本查看 复制代码
 1.异常:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止 [/align][align=left]     2.分类:​ ①Exception:编译期异常,写代码时出现的问题                ②RuntimeException:运行期异常,程序运行过程中出现的问题                              try{                                //可能会出现异常的代码                        }catch(Excaption e){                        //异常的处理逻辑                        }       Error:错误,绝症,必须将程序停下来,修改代码才能解决[/align][align=left]     3.异常关键字throw              ①.throw关键字必须写在方法的内部              ②.throw关键字后边new的对象必须是Exception或者Exception的子类对象              ③.throw关键字抛出指定的异常对象,我们就必须处理这个异常对象                  throw后边创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM去处理(打印异常对象,中断程序)                  throw后边创建的是编译异常(写代码的时候报错),我们就必须处理[/align][align=left]    4.throws关键字:异常处理的第一种方式,交给别人处理        ①使用格式:在方法声明时使用                修饰符  返回值类型   方法名(参数裂变)  throws AAAException, BBBException...{                        throw new  AAAException("产生原因");                        throw new  BBBException("产生原因");                        .....                }        ②注意事项:a.throws关键字必须写在方法声明处
                             b.throws关键字后边声明的异常必须是Exception或者是其子类                             c.方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常                                 如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可                             d.调用了一个声明抛出异常的方法,我们就必须得处理声明的异常                                  要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM                                   要么try...catch自己处理异常[/align][align=left]    5.try...catch (捕获异常) :异常处理的第二种方式,自己处理异常            ①格式:       try{                                //可能产生异常的代码                              }catch(定义一个异常的变量,用来接收try中抛出的异常对象){                                //产生异常对象之后,怎么处理异常对象                                //一般在工作中,会把异常的信息记录到一个日志中                              }                               . . .                               catch(异常类名   变量名){                                }           ②注意:   try中可能会抛出多个异常对象,可以用多个catch来处理                        如果try中出现了异常,那就会执行catch中的异常处理逻辑,然后继续执行之后的代码                        如果try中没有异常,那就不会执行catch中的异常处理逻辑,而是直接继续执行后面的代码        6.throwable中的3个异常处理方法           ①String getMessage( ):  异常的信息,没有原因返回null           ②String toString( ):  异常的类型和原因信息           ③void printStackTrace( ):  使用标准错误输出流打印异常信息 [/align][align=left] 7.finally代码块            格式:   try{                        可能产生异常的代码                       }catch(定义一个异常的变量,用来接收try中抛出的异常对象){                                //产生异常对象之后,怎么处理异常对象                                //一般在工作中,会把异常的信息记录到一个日志中                        }                        . . .                         catch(异常类名   变量名){                        }finally{                                无论是否出现异常都会执行                        }         注意:①:finally不能单独使用,必须和try一起使用                ②:finally一般用于资源释放(资源回收),无论此程序是否出现异常,最后都要资源释放       8.异常注意事项:        ( 1 )捕获多个异常的3个方式                ①多个异常分别处理(一个try捕获一个异常,并对应一个catch)                ②多个异常一次捕获,多次处理(一个try捕获多个异常,并对应多个catch)                        如果catch里面定义的异常变量有子父类的关系,那么子类的异常变量必须写在上边,否则会报错                ③多个异常一次捕获一次处理(一个try捕获多个异常,并对应一个catch)        ( 2 )finally中有return语句                则永远返回该return语句的值,应该避免在finally中写return语句                ( 3 )子父类继承重写方法时的异常要求(简记:父类异常什么样,子类异常也就什么样)                ①.如果父类抛出多个异常,子类重写父类方法时也抛出相同的异常,或者是父类异常的子类,或者不抛出异常                ②.如果父类没有抛出异常,子类重写该方法时也不可抛出异常.此时子类产生该异常,只能捕获处理,不能抛出       9.自定义异常:           格式:        public class XXXException extends Exception / RuntimeException{                                添加一个空参数的构造方法                                添加一个带异常信息的构造方法                        }           注意: ①.自定义异常类一般都是以Exception结尾,说明该类是一个异常类                      ②.自定义异常类,必须要继承Exception或者RuntimeException                        如果继承的是编译时期的异常,则必须抛出或捕获处理                        如果继承的是运行时期的异常,则不用管,让JVM去处理
三, 多线程      (一)计算机基本概念            1.并发和并行
​                并发:指两个或多个事件在同一时间段内同时发生
​                并行:指两个或多个事件在同一时刻发生(同时发生)
​           2.进程与线程
​                进程:一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;
​                线程:是进程中的一个执行单元,负责当前进程中程序的执行,一个进程至少有一个线程
​                多线程的好处:     效率高,多个线程之间互不影响
​           3.线程的调度
​                分时调度:所有线程轮流使用cpu的使用权,平均分配每个线程占用cpu的时间.
​                抢占式调度:优先级高的优先使用cpu,若优先级相同,则随机选择一个线程执行.  (Java使用)
​           4.主线程
​                主要执行的(main)线程
       (二)​创建多线程            1.第一种方式: 继承Thread类
​                        ①定义类,继承Thread类
​                        ②重写run( )方法,run方法内部是线程要执行的任务
​                        ③创建Thread子类的对象,调用start( )方法启动线程
​                    a.注意:   必须调用start( )方法来开启线程,不能直接调用run( )方法,否则就会变成单线程.
​                            同一个线程对象,不能多次调用start( )方法                    b.Thread中的常用方法:                           (1)获取线程的名称:                                ①使用Thread类中的方法getname( )
​                                String getName( )  返回该线程的名称.
​                              ②可以先获取到当前正在执行的线程,使用线程的方法getName( )获取线程的名称
​                                static Thread currentThread   返回对当前正在执行的线程对象的引用
              2.第二种方式:实现Runnable接口
​                            ①定义类,实现Runnable接口
​                            ②重写run( )方法
​                            ③创建Runnable实现类对象
​                            ④创建Thread类对象,在构造方法中传入Runnable实现类对象
​                             ⑤通过Thread对象调用statrt( )方法启动线程
              3.Thread和Runnable两种方式的区别
​                           实现Runnable接口创建多线程程序的好处:
​                          ①避免了单继承的局限性  :        一个类只能继承一个类,如果继承了Thread类就不能继承其他类了,实现Runnable接口的方式还可以继承其他的类,实现其他的接口
​                             ②增强了程序的扩展性,降低了程序的耦合性    :    线程是Thread,任务是Runnable接口,相当于将线程和任务分开了
              4第三种方式:  匿名内部类创建线程                                     匿名内部类的三种方式:代码如下                                      public class Test {
                                       
[AppleScript] 纯文本查看 复制代码
 public static void main(String[] args) {
                                         // 继承Thread类, 使用匿名内部类简化
                                          new Thread("继承Thread类") {
                                                @Override
                                                      public void run() {
                                                              for (int i = 0; i < 100; i++) {
                                                                       System.out.println(Thread.currentThread().getName() + ":" + i);
                                                                     }
                                                       }
                                        }.start();
                                      // 实现Runnable接口, 使用匿名内部类简化
                                     Runnable r = new Runnable() {
                                         @Override
                                             public void run() {
                                                 for (int i = 0; i < 100; i++) {
                                                     System.out.println(Thread.currentThread().getName() + ":" + i);
                                                 }
                                            }
                                        };
                                         new Thread(r, "可以设置名字").start();
                                    // 更简单的方式
                                       new Thread(new Runnable() {
                                       @Override
                                         public void run() {
                                              for (int i = 0; i < 100; i++) {
                                          System.out.println(Thread.currentThread().getName() + ":" + i);
                                               }
                                             }
                                       }, "实现Runnable接口").start();
                                                }
                                      }

               5.线程安全问题 :  多线程访问共享数据,CPU高速切换,在操作共享数据时还未完成,其他线程又进行操作
               6.解决线程安全问题方式:
​                     ①同步代码块:使用synchronized关键字修饰的代码块,并传入一个当作锁的对象
​                                格式:        synchronized(锁对象){
​                                        可能会出现线程安全问题的代码(访问了共享数据的代码)
​                                }
​                    ②同步方法: 使用synchronized关键字修饰的方法,具有默认的锁对象
​                        非静态同步方法的锁对象:this
​                        静态同步方法的锁对象:本利的class属性-->class本间对象反射()
​                                格式:修饰符 synchronized  返回时类型  方法名(参数列表){
​                                可能会出现问题的代码;
​                        }
​                    拓展:        获取一个类的字节码对象的3种方式:
​                                        1.类名.class属性
​                                        2.对象.getClass( )
​                                        3.Class.forName(字符串的类的全名)
​                   ③锁机制:
​                  
[AppleScript] 纯文本查看 复制代码
  java.util.concurrent.locks.Lock接口: JDK 5 新增的Lock接口                        // 成员方法                        void lock(): 获取锁                        void unlock(): 释放锁        ​                java.util.concurrent.locks.ReentrantLock类: Lock的实现类[/align]​                // 成员变量创建锁对象, 该锁对象也要所有线程共享唯一一个                 Lock lock = new ReentrantLock();
​                @Override
​                public void run() {                            // 加锁                    lock.lock();                     try {                        // 操作共享变量的代码...                    } finally {                        // 在finally中保证释放锁                lock.unlock();                      }                }
                 7.线程的状态:
                       1.1线程的6种状态与生命周期
线程的生命周期中, 可以出现有6种状态:
                          1. NEW 新建
                                   线程被创建, 但没有调用 start() 启动
                          2. RUNNABLE 可运行
                                  调用 start()方法后已启动, 但可能正在执行run()方法的代码, 也可能正在等待CPU的调度
                         3. BLOCKED 阻塞
                                  线程试图获取锁, 但此时锁被其他线程持有
                         4. WAITING无限等待
                                 通过锁对象调用无参的 wait() 进入此状态.
                                 等待其他线程通过锁对象执行 notify()notifyAll() 才能结束这个状态
                        5. TIMED_WAITING 计时等待
                                 如通过锁对象调用有参的 wait(long millis)sleep(long millis), 则进入此状态.直到时间结束之前被其他线程通过锁对象执行notify()notifyAll()唤醒, 或时间结束自动唤醒
                        6. TERMINATED 终止
                                 run()方法结束(执行结束, 或内部出现异常), 则进入此状态
                  1.2 Object类中关于线程的方法:
                     // 成员方法 (只能通过"锁对象"调用)
                 
[AppleScript] 纯文本查看 复制代码
    void notify(): 随机唤醒在同一个锁对象上的某一个处于等待状态的线程                   void notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线程                     void wait(): 让当前线程处于无限等待状态                     void wait(long timeout): 让当前线程处于计时等待状态, 时间到或被唤醒后结束此状态                     void wait(longtimeout, int nanos): 让当前线程处于计时等待状态, 时间到或被唤醒后结束此状态[/align]

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马