Loading... # 黑马视频 (7/ 4) ---- ## Java SE ------ ### day15 集合框架 * 引用数据类型数组中存储的都是 地址值 。 * 数组长度是固定,当添加的元素超过了数组的长度时需要对数组重新定义,太麻烦,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少 * 数组和集合的区别 * 区别1 : * 数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值 * 集合只能存储引用数据类型(对象),集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象,自动装箱在集合中引用的特别广泛 * 区别2: * 数组长度是固定的,不能自动增长 * 集合的长度的是可变的,可以根据元素的增加而增长 * 数组和集合什么时候用 * 如果元素个数是固定的推荐用数组,效率比较高 * 如果元素个数不是固定的推荐用集合 * 集合框架 ( Collection 集合的基本功能测试 ) * 基本功能演示 * boolean add(E e) ,可以添加任意对象,使用List添加会一直返回 true ,因为 list 中可以保存重复元素,使用 Set 添加重复元素会返回 false ,将一个集合当做一个元素添加进另一个集合 * boolean remove(Object o) ,移除 * void clear() ,清空 * boolean contains(Object o) ,是否包含 * boolean isEmpty(),是否为空 * int size(),获取其中元素个数 * collectionXxx.java 使用了未经检查或不安全的操作,注意:要了解详细信息请使用 -Xlint:unchecked重新编译,java编译器认为该程序存在安全隐患 。 * toArray() 用于将集合转换为数组 * 集合框架 Collection集合的带All功能 * 带All的功能演示 * boolean addAll(Collection c) ,将集合中的每一个元素添加进去另一个集合 * boolean removeAll(Collection c), 删除交集,两个集合中都有的元素 * boolean containsAll(Collection c),判断调用的集合是否包含传入的集合 * boolean retainAll(Collection c),取交集,如果调用的集合改变就返回 true ,不变就返回 false * 集合是用来存储元素,存储的元素需要查看,那么就需要迭代(遍历) * 迭代器原理:迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么就需要在每一个类中定义 hasNext() 和 next() 方法,这样做是可以的,但是会让整个集合体系过于臃肿,迭代器是将这样的方法向上抽取出接。,然后在每个类的内部,定义自己迭代方式:这样做的好处有二,第一规定了整个集合体系的遍历方式都是hasNext() 和 next() 方法,第二,代码有底层内部实现,使用者不用管怎么实现的,会用即可 * next() 方法用于将指针向后移动一位, * 迭代器源码解析 * 1,在eclipse中ctrl + shift + t找到ArrayList类 * 2,ctrl+o查找iterator()方法 * 3,查看返回值类型是new Itr(),说明Itr这个类实现Iterator接口 * 4,查找Itr这个内部类,发现重写了Iterator中的所有抽象方法 * List 集合的特有功能概述 * void add(int index,E element) , 可以在指定位置添加元素。 index 可以小于等于 size ,大于等于0,但是如果是其他的会报异常 * E remove(int index) ,通过索引去删除元素,将删除的元素返回,删除的时候不会自动装箱, * E get(int index), 通过索引得到该元素, * E set(int index,E element),修改指定元素的值 * ConcurrentModificationException出现 :迭代器迭代元素,迭代器修改元素 ( ListIterator 的特有功能 add ) ,这个迭代器是 list 集合特有的,可以在迭代的时候往集合内添加元素 * ListIterator * boolean hasNext() , 是否有下一个 * boolean hasPrevious() , 是否有前一个 * Object next() , 返回下一个元素 * Object previous(),返回上一个元素 * :数组实现 * 查询快修改也快 * 增删慢 * 链表实现 * 查询慢,修改也慢 * 增删快 * List的三个子类的特点 * ArrayList: * 底层数据结构是数组,查询快,增删慢。 * 线程不安全,效率高。 * Vector: * 底层数据结构是数组,查询快,增删慢。 * 线程安全,效率低。 * Vector 相对 ArrayList 查询慢 ( 线程安全的 ) * Vector相对 LinkedList 增删慢 ( 数组结构 ) * LinkedList: * 底层数据结构是链表,查询慢,增删快。 * 线程不安全,效率高。 * Vector 和 ArrayList 的区别 * Vector是线程安全的,效率低 * ArrayList是线程不安全的,效率高 * 共同点:都是数组实现的 * ArrayList 和 LinkedList 的区别 * ArrayList 底层是数组结果,查询和修改快 * LinkedList 底层是链表结构的,增和删比较快,查询和修改比较慢 * 共同点:都是线程不安全的 * List有三个儿子 * 查询多用 ArrayList * 增删多用 LinkedList * 如果都多 ArrayList -------- ### day16 List 集合 * contains 方法,判断是否包含,底层依赖的是 equals 方法, * remove 方法,判断是否删除,底层依赖的也是 equals 方法。 * LinkedList 类特有功能 * public void addFirst(E e) 及 addLast(E e),在集合首部或者集合尾部添加 * public E getFirst()及getLast(),获取第一个或者最后一个元素 * public E removeFirst() 及 public E removeLast() ,删除头或者删除尾部, * public E get(int index) , 通过给的索引查找相应的值,查找慢,因为他的查找不是从头就是从尾开始。 * 栈 (FILO) * 先进后出 * 队列(FIFO ) * 先进先出 * next() 方法只能调用一次,调用多次将导致指针向后移动多次。 * 泛型好处 * 提高安全性 ( 将运行期的错误转换到编译期 ) * 省去强转的麻烦 * 泛型基本使用 * < > 中放的必须是 引用数据类型 ,表示了这个集合能存储什么样的引用数据类型 * 泛型使用注意事项 * Object 泛型加不加无所谓。 * 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性菱形泛型) * 数组要保证前后的数据类型一致 * 泛型的由来:通过 Object 转型问题引入 * 早期的 Object 类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在着隐患,所以 Java 提供了泛型来解决这个安全问题。 * 泛型类,在类上加泛型,public <泛型类型> 返回类型 方法名 ( 泛型类型 变量名 ) ,方法泛型最好和类泛型一致,如果不一致,需要在方法上声明该泛型。 * 泛型接口概述 : 把泛型定义在接口上 * 定义格式: public interface 接口名 < 泛型类型 > ,实现这个接口的方法的类型,和接口所定义的泛型一致。 * 泛型通配符 < ? > ,可以替代任意一种类型,右边不确定泛型的时候,左边可以指定为 问号 。 * 任意类型,如果没有明确,那么就是 Object 以及任意的 Java 类了 * ? extends E : 向下限定,E 及其子类 * ? super E : 向上限定,E 及其父类 * foreach 循环 ,底层依赖的是迭代器, for ( 元素数据类型 变量 : 数组或者 Collection 集合) { 使用变量即可, 该变量就是元素 } * 普通 for 循环 , 可以删除 , 但是索引要自减 ,否则两个相同挨着的元素会漏删。 * 迭代器,可以删除,但是必须使用迭代器自身的 remove 方法,否则会出现并发修改异常 * 增强 for 循环 foreach 不能删除 * 静态导入,导入类中的静态方法 * import static 包名….类名.方法名; * 可以直接导入到方法的级别 * 注意事项:方法必须是静态的,如果有多个同名的静态方法,容易不知道使用谁 ? 这个时候要使用,必须加前缀。由此可见,意义不大,所以一般不用,但是要能看懂。 * 可变参数概述: 定义方法的时候不知道该定义多少个参数,其实是一个数组 * 格式:修饰符 返回值类型 方法名 ( 数据类型 … 变量名 ) { } * 注意事项: * 这里的变量其实是一个数组 * 如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个 * ( Arrays 工具类的 asList( ) 方法的使用 * Arrays工具类的 asList() 方法的使用 ,将数组转换为集合,数组中的必需时引用数据类型,可以使用集合中的其他方法,基本数据类型的数组转换成集合,会将整个数组当做一个对象,当集合转换数组,如果数组长度小于等于 集合 size ,会自动分配,如果大于,那么就和指定的长度一致,剩下的存放空字符串。 * Collection中 toArray ( T [ ] a ) 泛型版的集合转数组 ---------- ### day17 集合Set * 向 Set 中添加重复的元素的时候,会返回 false 。 * HashSet 的继承体系中,有重写 toString() 方法 , * Set 集合 , 无索引,不可重复,无序( 存取不一致 ) ,只要能用 迭代器 迭代的,就能使用增强 for 循环遍历。 * 在存储中,只有两个的 hashCode 值相同,才会调用 equals 方法进行比较。否则不会调用 equals 方法进行比较。 * 重写的 hashCode 方法 ,选择 31 的原因: 31 是一个质数,公约数少,可以降低重复率 ;1不大不小,便于计算, 31 = 2^5 -1,2向左移动五位 - 1 ,方便计算。 * 当 HashSet 调用 add 方法的时候,先调用对象的 hashCode 方法得到一个哈希值,然后在集合中查找是否有 哈希值 相同的对象,如果有,就和 哈希值 相同的对象 逐个调用 equals 方法进行比较,结果为 true 则不存,false 就存入其中, * 存储自定义的 类中 必须 重写 hashCode 方法和 equals 方法: * hashCode 方法,属性相同的对象返回值必须相同,属性不同的对象返回值尽量不同,提高效率 * equals 方法, 属性相同返回 true ,属性不同 返回 false ,返回 false 存储。不重写,默认按照地址值进行比较, * LinkedHashSet , 可以保证怎么存就怎么取,有顺序,保证存入的元素唯一,底层是 链表 实现的,是 set 中 唯一一个能保证怎么存就怎么取的集合对象。是HashSet 子类。 * TreeSet ,可以保证元素唯一且自然排序,可以指定一个顺序,对象存入之后会按照指定的顺序排列, * Comparable , 可以与此对象进行比较的那些对象类型 * ComparaTo ,比较此对象与指定对象的顺序,返回 0 ,集合中只有一个元素,返回 1 ,集合中怎么存就怎么取,返回 -1 ,倒序输出, * ComparaTo 底部是二叉树,小的存储在左边( 负数 ) ,大的存储在右边(正数),相等就不存(0) , * 存储自定义类的时候,需要重写 comparaTo 方法,以确保可以按照顺序有序存储。 * String 中重写的 ComparaTo 是按照字典顺序排序的, * TreeSet 自然排序(Comparable): * TreeSet 类的add () 方法会把存入的对象提升为 Comparable 类型 * 调用对象的 compareTo() 方法和集合中的对象比较 * 根据比较返回的结果进行存储(左边还是右边) * TreeSet 比较器排序(Comparator): * 创建 TreeSet 的时候可以制定一个 Comparator , * 如果传入了 Comparator 的子类对象,那么 TreeSet 就会按照比较器中的顺序排序 * add() 方法内部会自动调用 Comparator 接口中的 compare() 方法, * 调用的对象是 Compare 方法中的第一个参数,集合中的对象是 Compare 方法的第二个参数。 * 如果构造函数什么都不传,默认按照类中 Comparable 的顺序排序,如果传入了 Comparator ,就优先按照 Comparator 来进行排序。 --------------------- ### day18 Map集合 * 将键映射到值的对象 ,一个映射不能包含重复的键 , 每个键最多只能映射到一个值 * Map 接口和 Collection 接口的不同 * Map是双列的, Collection 是单列的 * Map的键唯一,Collection 的子体系 Set 是唯一的 * Map 集合的数据结构值针对 键 有效,跟值无关,Collection 集合的数据结构是针对 元素 有 效 * Map集合的功能概述 * 添加功能 * V put( K key , V value ):添加元素。 * 如果键是第一次存储,就直接存储元素,返回null * 如果键不是第一次存在,就用值把以前的值替换掉,把被覆盖的值返回 * 删除功能 * void clear() :移除所有的键值对元素 * V remove(Object key):根据键删除键值对元素,并把值返回 * 判断功能 * boolean containsKey ( Object key ) :判断集合是否包含指定的键 * boolean containsValue ( Object value ) :判断集合是否包含指定的值 * boolean isEmpty():判断集合是否为空 * 获取功能 * Set<Map.Entry<K,V>> entrySet(): * V get(Object key):根据键获取值 * Set<K> keySet():获取集合中所有键的集合 * Collection<V> values() : 获取集合中所有值的集合,map.values() , * 长度功能 * int size():返回集合中的键值对的个数 * map 集合不能通过迭代器 迭代 * 键找值思路: * 获取所有键的集合 * 遍历键的集合,获取到每一个键 * 根据键找值 * 键值对对象找键和值思路: * 获取所有键值对对象的集合 * 遍历键值对对象的集合,获取到每一个键值对对象 * 根据键值对对象找键和值 * Entry 是 Map.Enter 的一个字对象 * LinkedHashMap的特点 * 底层是链表实现的可以保证怎么存就怎么取 * 存储自定义的 类中 必须 重写 hashCode 方法和 equals 方法,才可以将其存在集合中保持集合的属性: * hashCode 方法,属性相同的对象返回值必须相同,属性不同的对象返回值尽量不同,提高效率 * equals 方法, 属性相同返回 true ,属性不同 返回 false ,返回 false 存储。不重写,默认按照地址值进行比较, * HashMap 和 Hashtable : * 共同点: * 底层都是 哈希算法 ,都是双列集合 * 不同点: * Hashtabl e是 JDK1.0 版本出现的,是线程安全的,效率低,HashMap 是 JDK1.2 版本出现的,是线程不安全的,效率高 * Hashtable 不可以存储 null 键和 null 值 ,HashMap 可以存储 null 键和 null 值 * Collections 常见方法: public static <T> void sort ( List<T> list ) ,排序,需要实现了 public static <T> int binarySearch ( List<?> list , T key) ,二分查找法查找元素的索引, public static <T> T max ( Collection<?> coll ) , 根据字典排序结果,获取最大值 public static void reverse ( List<?> list ), 翻转集合 Public static void shuffle ( List<?> list ) ,随即换,可以用来洗牌 * 泛型固定下边界 : ? super E * 泛型固定下边界 : ? extends E * 集合总结: * Collection * List( 存取有序,有索引,可以重复 ) * ArrayList ( 底层是数组,实现的,线程不安全,查找修改快,增删比较慢 ) * LinkedList ( 底层是链表实现的 , 线程不安全,增删比较快,查找和修改比较慢 ,栈) * Vector( 底层是数组实现的,线程安全,无论增删改查都慢 ) * 查找修改多,用 ArrayList * 增和删多,用 LinkedList * 都多,用 ArrayList * Set ( 存取无序,无索引,不可以重复 ) * HashSet (底层是 哈希算法实现的) * LinkedHashSet ( 底层是 链表实现,但是也可以保证元素唯一,和 HashSet 原理一样 ) * TreeSet ( 底层是二叉树算法实现 ) * 一般开发使用不需要对存储的元素排序,所以大部分使用 HashSet ,效率较高。 * TreeSet 面试时候用, * Map * HashMap ( 底层是 哈希算法,针对键 ) * LinkedHashMap(底层是链表,也是针对键) * TreeMap (底层是二叉树算法,针对键) * 开发中用 HashMap 较多。 * TreeMap 排序,面试用的多。 最后修改:2018 年 07 月 17 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 哇卡哇卡