黑马视频 (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
keySet():获取集合中所有键的集合 - Collection
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 排序,面试用的多。