第07天 集合 集合(HashSet, HashMap,Map集合嵌套): 一:set体系的特点 *set接口: +继承自collection接口 +特点: (1)元素无序(存入和取出的顺序不一致,但存入后每次取出的顺序都一样) (2)元素不能重复(元素唯一) (3)没有索引 注意:直接打印和获取元素都属于取出, 所以不要把打印当成是HashSet内部存储的样子 二:HashSet存储自定义对象并遍历 *HashSet类是set接口的实现类 +成员方法: boolean add(E e): 添加成功true, 添加失败(重复了)返回false 1.HashSet保证元素唯一的原理: +判断对象相同的两个方法:(HashSet且去重原理(简单版)) (1)hashcode() 如果判定哈希值不相同,则认为不重复 如果判定哈希值相同,则需要继续用equals()方法判断 (2)equals() 如果判定不相同, 则认为不重复 如果判定相同, 则认为重复 (1) HashSet的add()方法, 首先将新添加的元素和当前集合中的已有元素进行hash值比较, 依靠对象的"hashCode()" (2) 如果hash值不一样, 则认为不重复, 直接添加新元素 (3) 如果hash值一样, 则继续与已有元素比较"地址值"或使用"equals()方法"进行比较 如果比较结果一样, 则认为重复, 不添加 如果和所有的已有元素比较都不一样, 则认为不重复, 添加元素 注意:自定义对象的hashCode()和equals()方法决定了该对象能否被去重 *hashCode()方法和equals()方法的优化 优化hashCode()方法, 即让该方法的返回值和成员属性相关联, 减少equals()的调用, 提高效率 (1)让hashCode()方法返回所有成员变量之和. - 基本数据类型直接相加 - 引用数据类型获取该成员变量的hashCode方法返回值后再相加(boolean不能参与运算) (2)优化equals方法 - 提高效率: this ==obj-->return true - 提高向下转型的安全性:this.getClass() == obj.getClass()-->return false 三.Collections工具类 *Collection 和Collections 的区别 - Collection是接口, 是单列集合的顶层, 包含一些共性方法 - Collections是类, 提供操作Collection的一些工具方法, 类似的还有操作数组的Arrays工具类 *Collections类常用的静态方法: (1) static int binarySearch(List list,T key):使用二分查找来查找元素在指定列表的索引位置 *(前提是集合已经排序,查找原理类似猜数字) (2) static voidcopy(List dest, List src): 将源列表中的数据复制到目标列表 *(目标列表的长度至少等于源列表的长度) (3) static voidfill(List list, Object obj): 使用指定对象填充指定列表的所有元素 (4) static voidreverse(List list): 反转集合中的元素 (5) static voidshuffle(List list): 随机打乱集合中元素的顺序 (6) static voidsort(List list): 将集合中的元素按照元素的自然顺序排序 (7) static voidswap(List list, int i, int j): 将指定列表中的两个索引进行位置互换 四:Map接口的概述 * Map<K, V>接口 是双列集合的顶层, 和Collection属于同级 +特点: (1)存储方式是key-value(键值对)方式, 即一个键对应一个值 (2) 一个键只能映射一个值 (3) 键不能重复, 值可以重复 (4) 键是无序的 +Map和Collection的区别 - Map是双列集合, 用于处理有一一对应关系的数据,键不能重复且键无序 - Collection是单列集合, 有不同的子体系,List允许重复且有序, Set不允许重复且无序 五:Map功能概述和测试 *HashMap类 +多态创建对象: (也可以不使用多态) -Map<K, V> map = new HashMap<>(); +常用方法: - 增和改:V put(K key, Vvalue): 添加键值对. 注意: 如果key已经存在, 则会使用新的value覆盖原有value,并将原有value返回 - 删: void clear(): 清空集合 V remove(Object key): 删除指定键的值(key和value都会删除) - 查: -V get(Object key): 通过指定键获取值 - int size(): 获取集合长度 - 判断: -boolean containsKey(Object key): 是否包含指定的键 -boolean containsValue(Object value): 是否包含指定的值 -boolean isEmpty(): 是否为空 - 遍历: -Set<Map.Entry<K, V>> entrySet(): 获取键值对的Set集合 - Set<K> keySet(): 获取所有键的Set集合 -Collection<V> values(): 获取所有值得Collection集合 *Map的遍历方式 + keySet()方法(Map的第一种遍历方式) - 通过get(K key)方法获取key对应的value + entrySet()方法, 遍历值的集合(Map的第二种遍历方式) - 使用Entry的getKey()获取key, 使用Entry的getValue()获取value *注意:HashMap存储数据并遍历:String作为key时,相同的字符串内容会导致key重复,字符串通过equals比较返回true 自定义类的对象作为key, 是否重复取决于自定义对象的类中如何重写hashCode()和equals()方法 六:可变参数: 1.从JDK1.5开始 2.可变参数: 方法的形参可以传入不定数量个参数 3.定义格式: 形参数据类型... 形参名 注意事项: 1.可变参数的数量可以从0个到多个 2.可变参数只能是同一种数据类型 3.可变参数的定义位置必须在方法形参列表的最后一个 可变参数的原理: 底层是一个根据形参数量创建长度的数组, 通过JVM将形参转换为数组 如何使用可变参数? 1.在方法中使用: 把可变参数的形参名当做一个数组变量名, 遍历并获取元素 2.向方法中传入参数: 将多个参数值使用逗号分隔传入方法 七:Map嵌套演示: Map嵌套Map Map<String, Map<String,String>> 理清key和value - 存入: 先处理好内部的Map, 然后再放入外部Map - 取出: 遇到Map就使用2种方式遍历即可 Map嵌套演示: Map嵌套Collection Map<String,Collection<Student>> 理清key和value - 存入: 先处理好内部的Collection, 然后再放入外部Map - 取出: 遇到Map就使用2种方式遍历, 遇到Collection就用3种方式遍历 扩展: 让对象实现排序的2种方式 - 让对象具有自然顺序: 让JavaBean实现Comparable接口, 重写compareTo()方法 - 使用比较器: 定义一个类作为比较器, 实现Comparator接口, 重写compare()方法, 排序时传入该比较器实现类的对象 重写方法的返回值的作用: - 返回值为负数: 则认为当前元素比被比较元素小 - 返回值为0: 则认为当前元素与被比较元素相等 - 返回值为正数: 则认为当前元素比被比较元素大 HashSet去重详细版原理 * 当调用HashSet的add()方法时,该方法内部调用的是一个HashMap的put()方法,将元素作为HashMap的key,存入HashMap中, 利用Map的key的唯一性,保证HashSet的元素唯一性 * 那HashMap的key如何保证唯一呢? * 首先, HashMap的put方法, 会先计算key的hash值. * 然后, 拿该hash值在一个名为table的Entry[]数组中寻找该hash值的索引. * 之后, 在for循环的初始化条件中, 拿该索引值获取Entry[]数组中的Entry元素 * 如果没有该元素,即元素为null,说明元素不重复,则for循环不满足执行条件,直接略过for循环,并添加元素到Entry[]数组中,并在put()方法最后返回一个null * 如果有该元素, 则进入for循环. 继续判断该元素是否与已有元素相同 * 首先,使用当前Entry集合中的每一个元素和新添加的元素进行hash值的比较 * 如果hash值不同, 则直接添加新的元素 * 如果hash值一样, 则比较Entry的key和传入的key是否相同或使用equals方法比较 *如果比较结果相同, 则认为是重复不添加, 且返回已有元素 *如果不重复, 则继续for循环比较下一个 *直到所有比较结果都不相同, 则认为不重复, 添加新的元素 第08天 异常 一:异常的体系结构: Throwable(最顶层) Error:不能处理的异常 Excrption:可以处理的异常,编译异常 RuntimeExcrption:运行异常,编译正常 二:jvm处理异常的方式: 1.将异常的类型,原因还有位置显示在命令行,并且终止程序 三:异常的处理方式: 捕获处理 try..catch语句 try{ 有可能出现问题的代码 } catch(异常类型 类型名){ 处理异常; } try..catch的执行顺序: 首先执行try语句,如果有异常直接调到catch语句中,整个try..catch语句结束, 如果没有异常,try..catch语句不执行 抛出去: 当不想或不能解决异常时,可以使用关键字throws在方法声明处将异常抛出,谁调用方法谁处理 四:多异常处理: 1.可以使用多个try.. catch语句 2.使用一个try和多个catch 多异常执行顺序: 1.多个catch之间可以有子父类关系 2.平级或同级没有子父类关系 3.如果有子父类,父类必须放到后面 五:Throwable的常用方法: (1):1.StringgetMessage():异常原因 2.String toString():异常类型和原因 3.void printStackTrace():异常类型,原因和位置 *该方法只是将异常信息以System.err错误输出流打印到控制台,并不会结束程序 *System.err.println:输出的是红字 (2)finally:组合try。。catch使用,用于释放资源等收尾工作,无论try..catch是如何执行, finally的代码块中的代码都会执行。 try{ 有可能出现问题的代码 } catch(异常类型 类型名){ 处理异常; }finally{ 释放资源; 清理垃圾; } 六:异常的分类: 1.运行时期异常:RuntimeExcrption的子类就是运行时期异常,在编译时期可以自由选择处理或不处理。 2.编译时期异常:是Excrption的子类,非RuntimeExcrption的子类在编译时期必须处理, 七:自定义异常: 1.throws:处理异常的一种方式,把异常抛出,有调用者处理 2.throw:制造异常的方式,并且结束方法 *注意:如果是抛出的编译时期异常,必须在方法声明处抛出 *写一个类去继承Exception或RuntimeException,然后实现多个构造即可 八:递归: 1.概述: (1) 把大问题拆成小问题 在方法本身不断调用方法自己 (2)注意事项: 递归一定要有出口,内存溢出 递归次数不宜过多,内存溢出 九:斐波那契列数: 不死神兔 :第一个月和第二个月都是一对兔子,第三个月生下一对兔子,以后每月都生一对兔子, 即:1--1 2--1 3--2 4--3 5--5 6--8 7--13 . . . 20 从第三个月开始:每个月都是前两个月兔子之和,即n=(n-1)+(n-2);
|