JavaEE-集合

集合

集合的概述

体系结构

  1. 集合分类:

    • 单列集合:每个元素都是一个单独的个体。
    • 双列集合:每个操作都是针对一对数据来进行的,一对数据作为一个整体。键值对。
  2. 单列集合的体系:

        Collection                      单列集合的顶层接口
    		List                        有序的子接口
    			ArrayList               顺序存储的实现类,查询快,增删慢
    			LinkedList              链式存储,查询慢,增删块
    		Set                         无序的子接口
    			HashSet                 哈希表存储
    				LinkedHashSet       HashSet的子类
    
  3. 双列集合的体系:

        Map                             双列集合的顶层接口
    		HashMap                     哈希表存储Map的实现类
    			LinkedHashMap           HashMap的子类
    

Collection

概述和常用方法

  1. 单词:收集,集合
  2. 单列集合的顶层接口:定义的所有单列集合中共有的功能。
  3. Collection是一个接口,不能实例化,不能创建对象,找一个该接口的实现类对象。
    • 使用接口类型的引用,指向实现类的对象
    • Collection类型的引用,指向ArrayList类型的对象(只能调用接口中的方法)
  4. 常用的方法
    • add(Object obj):将obj这个元素添加到集合中

    • remove(Object obj):将obj元素从集合中移除

    • contains(Object obj)判断集合中是否包含obj这个元素

    • isEmpty()就是集合为空就返回true

    • size()返回就是集合中元素的个数

    • clear();清空集合中的元素

Collection集合的第一种遍历

  1. 转成数组,通过遍历数组,来间接的访问集合
  2. 方法:Object[] toArray():将调用者集合转成Object类型的数组

Collection中带All的方法

  1. addAll(Collection c):将参数c中的所有元素,都添加到调用者集合中

  2. removeAll(Collection c):将参数集合c中的元素都从调用者集合中移除

  3. containsAll(Collection c):判断调用者集合中是否全部包含参数集合c中的元素

  4. retainAll(Collection c) 参数c中有哪些元素,就在调用者集合中保留哪些元素

    ​ (参数c集合和调用者集合中共有的元素)

集合遍历的第二种方式:迭代器

  1. 迭代:更新迭代,从某一个到下一个的过程的含义
  2. 迭代器:专门用于将集合中的元素,一个到另一个逐个进行迭代的过程,就是提供一个方法对集合容器对象都进行访问。而又不去暴露对象容器的内部细节。集合容器内部结构不同,很多时候不知道怎样去遍历一个容器中所有的元素是。所以为了容器中的元素操作起来更为简单,java引入了迭代器模式,把访问不同逻辑从不同类型集合类中抽取出来,避免了向外部暴露集合内部的内部结构。
  3. 获取:集合自己内部有一个可以迭代自己的对象,从集合中获取即可
    Iterator iterator()
  4. 迭代器的使用:
    方法iterator()返回是一个Iterator接口的实现类对象可以使用Iterator接口中提供的方法。
    hastNext():判断集合中是否还有下一个元素
    next():获取集合中的下一个元素,让迭代器指针发生一次移动
    remove();删除迭代器正在遍历的那个元素
  5. 迭代器在使用时候的注意事项
    1. 迭代器对象虽然多次调用next方法,都是同样的名称,但是每次调用方法返回的内容是不一样的。
      next方法既可以获取下一个元素,也会让迭代器对象,向前移动一步。
    2. 如果没有下一个元素,仍然调用next方法,出现NoSuchElementException(没有当前元素异常)可以使用hasNext方法进行判断,如果为true就调用next方法,为false就不调用next方法
    3. hastNext方法不会移动迭代器指针的位置
    4. next方法不仅可以获取下一个元素,也会移动迭代器指针的位置
    5. 不要只判断一次hasNext方法,就调用多次next方法

List

概述

  1. 是Collection有序的子接口
  2. 特点:
    • 有序:每个元素都有自己位置,不同的位置有区别的
    • 有索引:每个元素都有自己的编号
    • 可以重复:即使是值相同的元素,位置和索引是不同的,可以区分相同的值
  3. 特有方法:
    • add(int index,Object obj): 在指定索引上,添加指定的元素

    • remove(int index):删除指定索引上的元素

    • set(int index,Object obj):将指定索引上的值,修改为指定的值

    • get(int index):获取指定索引上的值

第三种遍历方式

  1. 针对就是List集合特有的遍历方式
  2. 可以通过集合中的size方法获取集合中元素的个数,List集合有索引,结合get方法就能够获取List集合中所有的元素。

并发修改异常

  1. ConcurrentModificationException
    并发修改异常
  2. 出现的原因:在使用【迭代器对象】遍历集合的同时,使用【集合对象】增加或删除集合的元素
  3. 避免的方式:两种方式都是针对list
    • 方式1:迭代器遍历,迭代器增加
    • 方法2:集合遍历,集合增加
  4. 方式1:迭代器遍历,迭代器增加:问题普通的迭代器中没有增加的方法,需要使用List中特有的迭代器
    • 迭代器增加:问题普通的迭代器中没有增加的方法,需要使用List中特有的迭代器
      • 列表迭代器:ListIterator是Iterator的子接口,拥有Iterator中所有的方法,还要特有的方法
      • 列表迭代器的获取:listIterator();
  5. 方式2:集合遍历,集合增加
    • list特有的遍历方式,size和get方法相结合
  6. 不是所有的集合在进行迭代器遍历,迭代器增删的时候都会出现并发修改异常
    • 集合中的倒数第二个元素是不会发生的,其他都是会发生了。

List的实现类

  1. 概述
    List是一个接口,根据底层的实现方式不同,具有不同的实现类
  2. ArrayList: 数组实现,顺序存储
  3. LinkedList: 节点实现,链式存储

ArrayList

  1. 也是List一个实现类
  2. 没有特有方法
  3. 存储的方式:
    • 数组实现,顺序存储
    • 通过物理内存位置的关系,来表述逻辑顺序的相邻

LinkedList

  1. List的一个实现类
  2. 存储方式:
    • 节点实现,链式存储
    • 不通过物理位置的相邻,来表示逻辑位置的相邻
    • 每个元素都在一个节点中,节点除了元素数据本身以外,还需要存储是下一个节点内存地址
  3. 特点:
    • 查询速度慢,需要根据前面的节点来获取后一个节点的地址,前面所有的节点都要访问一遍,节点越多,查询速度就越慢
    • 增删速度快:增删一个元素,只需要修改前后两个节点的指针域即可,与集合的规模没有关系
  4. LinkedList中特有的方法:
    • addFirst(Object obj): 在头部添加元素
    • addLast(Object obj): 在尾部添加元素
    • removeFirst(): 移除头部元素
    • removeLast(): 移除尾部元素
    • getFirst(): 获取头部元素
    • getLast(): 获取尾部元素

泛型

泛型的概述和使用

  1. 泛型:广泛的类型,在定义一个类的时候,类型中有些方法参数,返回值类型不确定,就使用一个符号,来表示那些尚未确定的类型,这个符号就称为泛型。

  2. 使用:对于有泛型类,在这些类型后面跟上了一个尖括号,尖括号中写上泛型的确定类型的(在使用该类型创建对象的时候,就可以写出具体类型)

  3. 泛型的好处:

    1. 提高了数据的安全性,将运行时的问题,提前暴露在编译时期
    2. 避免向下转型的问题
  4. 注意事项:

    1. 前后一致:在创建对象的时候,赋值符号前后中尖括号中的类型要一致

    2. 泛型推断:如果创建对象的时候,前面已经写好了泛型,后面创建对象的类型就可以只写一个尖括号。“菱形泛型”

      jdk1.7特性

    3. 不能定义泛型数组,发生泛型擦除问题,失去了泛型存在的意义

泛型类的定义

  1. 泛型类:带着泛型的类
  2. 格式:
    • class 类名<泛型类型1,泛型类型2,泛型类型3,....>{}
  3. 说明
    1. 类名后面跟着的泛型类型,是泛型的声明,一旦泛型声明出来,就相当于这个类型成为了已知类型,这个类型就可以在整个类中使用
    2. 泛型声明的名称:只需要是一个合法的标识符即可,通常我们使用单个大写字母来表示。T,W,Q,K,V,E
    3. 泛型确定的时机:将来在使用这个类,创建对象的时候

泛型方法

  1. 在方法声明中,带着泛型声明的方法,就是泛型方法
  2. 格式
    • 修饰符 <泛型的声明1,泛型声明2 ...> 返回值类型 方法名称(参数列表){}
  3. 说明
    1. 在方法上声明的泛型,可以在整个方法中使用,当做已知类型去使用
    2. 如果是非静态方法,在方法上没有任何泛型的声明,可以使用类上声明的泛型
    3. 如果是静态方法,在方法上没有任何泛型的声明,不可以使用类上声明的泛型,只能在静态方法上,声明泛型

泛型的通配符《了解》

使用泛型的时候,没有使用具体的泛型声明T,而是使用了和声明的某个泛型T有关的一类类型,就称为泛型的通配符
三种形式

  1. 第一种形式,使用?来表示可以是任意的类型
    removeAll(Collection<?> c) 表示可以接受任意泛型类型的集合c
    作为该方法的参数,参数集合的泛型可以和调用者集合泛型E没有任何关系
  2. 第二种形式,使用? extends E来表示某个泛型类型或是该泛型类型的子类
    addAll(Collection<? extends E> c) 表示的是参数集合c中的泛型,必须是调用者集合泛型E的子类类型或者是本类类型,作为该方法的参数
  3. 第三种形式:使用?super E来表示必须是某个泛型类型或者是该泛型类型的父类类型
    Arrays工具类中排序方法sort(T[] t,Comparator<? super T> c)
    T就是该方法的泛型,T表示的就是数组中元素的类型<? super T>,表示的是可以接受泛型的类型必须是T类型或者是T类型的父类类型

Set集合

  1. set集合是Collection下的一个子接口
  2. 特点:
    无序:没有任何前后的区别,存入的顺序和取出的顺序是不一样的,所有的元素在集合中没有位置上的概念
    没有索引
    不能重复,没有位置上的区别,相同的元素没有任何区分,所有不能重复
  3. Set的实现类:
    HashSet:使用哈希表的存储方式来存储元素
  4. 存储特点:
    相同的元素不能存入到set集合中
    集合本身不保证顺序的,存入的顺序和取出的顺序是不一样的

Set集合的遍历

  1. 没有特有的方法,只能使用Collection接口中定义的方法,只能使用Collection的遍历方式

  2. 第一种:转成数组toArray(),不带泛型的数组,得到的是Object类型的数组

  3. 第二种: 转成数组 T[] toArray(T[] t),带泛型的数组,得到的是T类型的数组

    1. 自己创建的数组大小,小于集合元素的个数
      在方法中,就会创建一个新的数组,用来存储集合中的元素,将数组返回

    2. 自己创建的数组大小,等于集合元素的个数
      在方法中,就不会创建一个新的数组,使用集合中的元素将传入的数组进行填充,将原数组进行返回

    3. 自己创建的数组大小,大于集合元素的个数
      在方法中,不会创建一个新的数组,直接将集合中的元素填充到数组中的前面的位置,后面的位置用默认值填充

    4. 第三种:迭代器

    5. 第四种:增强for循环(foreach)
      格式:for(元素的数据类型 元素名称 :要遍历的集合或者数组){
      使用元素名称代表当前访问的元素;
      }
      说明:
      元素的数据类型:指的是要遍历集合中元素的数据类型
      元素名称:元素名称虽然是固定的,但是随着循环的执行,每次代表的元素是不同的
      要遍历的集合:可以是数组也可以是集合
      本质:
      底层迭代器,只不过使用这种格式更为简单
      注意事项:

      ​ 使用增强for,没有拿到元素的索引,无法修改集合或者数组中的元素值
      ​ 底层迭代器,所在在遍历集合的时候,使用集合对象添加元素,也会发生并发修改异常

HashSet保证元素唯一性的原理

HashSet存储jdk提供的元素的类型

HashSet存储jdk提供的元素的类型,发现直接保证了元素的唯一性,值相同的元素都去掉了

HashSet存储自定义类型元素

  1. HashSet存储自定义类型元素发现并没有保证唯一性

  2. 实验:猜测没有重写equals方法,没有重写之前比较的地址值,如果地址值一样了就不存储,不一样就存储,但是

    • 重写后equals方法比较的是属性值,发现并没有调用,没有去重成功
  3. 猜测Hashset集合是哈希实现,有没有可能跟HashCode方法有关,重写HashCode方法

    • 在重写hashcode方法之前,调用的Object中的hashcode方法,不同的对象(对象的地址值不同)生成的hashcode值就是不同的。

    • 重写hashcode方法之后,让Person中hashcode方法生成的值都为0(实现的效果,不同的对象对象的地址值不同的时候)生成的hashCode值一样的,发现确实hashCode方法执行了,equals方法也执行了。

  4. 发现了,HashSet存储自定义类型元素的时候,确实要调用自定义元素类型中的hashCode方法,根据hashCode方法的值判断是否将自定义元素存入到集合中。发现不同的对象(地址值不同)调用Object类中的hashCode方法生成的是不同的的hashcode值,就直接存储,不能实现去重,equals方法也不调用

    • 重写hashcode方法之后,让Person中hashcode方法生成的值都为0,发现调用equals方法,根据equasl方法比较的结果判断是否添加重复的元素

HashCode方法

  1. Object类型中的方法
  2. 根据对象,生成一个整数,就是哈希吗值,生成数字的方法的就是hashCode()
  3. 生成数字的原则:
    1. 同一个对象,多次调用hashCode()方法【必须】返回的是相同的数字(程序多次运行不要求hashCode码值一致)
    2. 使用equals(Object) 方法判断相同的两个对象【必须】返回相同的整数(equals是Object类型中的,比较的是地址值)
    3. 使用equals(Object) 方法判断不相同的两个对象【尽量】生成不相同的整数(不做强制要求)
    4. Object类型中的HashCode方法,【确实】 会根据不同的对象生成不同的整数。

HashSet保证唯一性原理的总结

  1. HashSet 集合存储一个obj对象的时候,首先计算obj对象的hashcode值
  2. 在集合中的所有的元素的哈希值,都和obj的hashcode值,说明集合中不存在Obj,可以直接将obj存储到集合中
  3. 在集合中有若干个元素的哈希值,和obj的哈希值相同,并不能说明obj已经存在于集合中,需要使用equals方法判断obj时候和那些与自己相同的哈希值的元素是否相等
  4. 如果在equals方法和obj元素比较之后,发现都不相等,那么就说明obj不存在与这个集合,可以将obj存储到hashset中
  5. 如果在equals方法和obj元素比较之后,发现相等,obj已经存在于集合中,obj就不存储了

保证唯一性的操作

  1. 重写HashCode()方法
    • 根据属性值,生成哈希值
    • 不同的属性值,尽量生成不同的整数
    • 相同的属性值,一定会生成相同的整数
  2. 重写equals方法
    • 比较的就是属性值
  3. 操作
    • alt+shift + s
    • 生成hashcode方法和equals方法

LinkedHashSet

  1. 是HashSet的一个子类,和HashSet保证元素唯一性的原理相同
  2. 将来每个元素在存储的时候,都记录了前后元素的地址
  3. 效果:
    可以根据存储元素的顺序,将元素取出
  4. 应用:
    既需要保证元素的唯一,又需要保证原来的顺序,就可以考虑LinedHashSet

Map

  1. 是双列集合的顶层接口

  2. Map:地图

  3. 数据结构: 描述的就是将一个数据(key)到另一个数据(value)的映射关系(对应关系)

    • 一个数据(key):容易记忆的,有规律的,简单的数据
    • 另一个数据(value):没有规律,不容易记忆的,复杂的数据
    • 大多数都是通过key操作value
  4. 映射:对应关系

    函数:y = x * x     	 特点:x是不会重复的                      key
    			    平方         y会重复的                         value
        		x  ----->   y
         		1           1
         		2           4
         		3           9
         		4           16
    
  5. java中map就是使用穷举罗列的方式描述映射关系

  6. map的特点

    • key(键) 是唯一的,不能重复的
    • value(值)不是唯一的,可以重复
  7. Map和Collection的区别

    • Map是双列集合,Collection单列集合
    • Map的键是唯一的,Collection中set子接口中的元素是唯一的
    • Map中大多数方法都是操作键的,Collection中set子接口中的操作对元素有效

Map集合中的方法

  1. 增加键值对(向map集合中添加数据):
    • put(K key,V value)
  2. 删除方法
    • 根据给定的值,删除对应的键值对:
      • remove(k key)
    • 清空集合:
      • clear()
  3. 获取方法
    • get(k key)获取键所对应的的value值
    • size()返回map集合中所有的键值对的个数
  4. 判断方法
    • containsKey(Object key)
      • 判断集合中是否包含key这个键
    • containsValue(Object value)
      • 判断集合中是否包含value这个值
  5. 修改方法
    • 根据给定的键,修改对应的值:put(k key,v value)
    • 如果在集合中已经存在key这个键,那么使用put方法,就是修改这个键对应的value值
    • 如果在集合中不存在key这个键,那么使用put方法,就是向map集合重添加数据

Map集合的第一种遍历思路(熟练掌握)

  1. 获取Map集合中所有的键,放到一个set集合中,遍历set集合,获取每一个键,根据键再来获取对应的值【根据键获取对应的值】
  2. 获取Map集合中所有的键
    • keySet()
  3. 遍历Set集合拿到map集合中所有的键了
    • 遍历Set集合:
    • 增强for
    • 迭代器
  4. 拿到每个键之后,通过get(K key)获取键对应的值
  5. 特点:
    • 获取了所有键的set集合后,要依赖于原来的map集合

Map集合的第二种遍历思路

  1. 获取的是Map集合中所有的键值对对象(Entry), 到set集合中,遍历set集合,拿到的是每一个键值对对象(Entry),从这个对象中获取键和值
  2. 根据Map集合方法可以获取所有键值对对象到一个Set集合中
    Set<Map.Entry<K,V>> entrySet()
  3. 遍历Set集合
    • 迭代器
    • 增强for
  4. 获取到的就是一个键值对对象
    • Entry是Map接口中的内部接口,访问方式:Map.Entry
    • Entry常用的方法
      • getKey()获取的是键值对中的键
      • getValue()获取的是键值对中的值

HashMap

  1. 就是Map集合中使用哈希表存储方式的一种实现类
  2. HashMap存储jdk中提供的元素类型的键,直接保证元素的唯一性
  3. HashMap存储的键值对中的键是自定义类型元素的时候,无法保证元素的唯一性,要保证自定义元素的唯一性也需要重写hashCode和equals方法保证键的唯一性和HashSet保证元素唯一性的原理是一样的
  4. HashMap和HashSet的关系
    • HashSet是HashMap实现出来的,HashSet就是HashMap键的那一列将HashMap值的那一列隐藏掉就成HashSet
  5. HashMap和Hashtable的区别
    • HashMap是线程不安全的,效率高,出现的版本是1.2
      • 能存储null键与null值
    • Hashtable是线程安全的,
      • 不能存储null键与null值

LinkedHashMap

  1. 是HashMap的一个子类
  2. 和HashMap的不同之处,具有可预知的迭代顺序,存储键值对的顺序和遍历集合时取出的顺序时的键值对的顺序一致。

Collections工具类

  1. binarySearch(List<? extends Comparable<? super T>> list, T key)
    • 在一个升序的List集合中,通过二分查找寻找Key对应的索引
  2. frequency(Collection<?> c, Object o)
    • 返回指定 collection 中等于指定对象的元素数。
  3. replaceAll(List<T> list, T oldVal, T newVal)
    • 使用另一个值替换列表中出现的所有某一指定值。
  4. reverse(List<?> list)
    • 反转指定列表中元素的顺序
  5. shuffle(List<?> list)
    • 将list集合中的元素进行随机置换,打乱
  6. swap(List<T> list, int a, int b)
    • 将list集合中索引为a和b的两个元素进行交换
  7. sort(List<T> list)
    • 将list集合中的元素进行自然排序
  8. synchronizedxxx方法系列:
    • 将一个线程不安全的集合传入方法,返回一个线程安全的集合
  9. unmodifiablexxx方法系列:
    • 将一个可修改的集合传入方法,返回一个只可读的集合
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值