Java复习笔记:集合、迭代器、泛型

一、集合

1.集合的概述

①集合与数组的区别:
  • 数组的长度是不可变的,集合的长度是可变的。

  • 数组可以存基本数据类型和引用数据类型。

  • 集合只能存储引用数据类型,如果要存储基本数据类型要存对应的包装类。

② 集合的体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(在这里插入图片描述

2. Collection接口

  • Collection接口是单列集合的根接口
  • Collection接口有两个主要的子类接口(List、Set)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XulQlEDu-1628487296758)在这里插入图片描述

  • Collection接口的常用方法
boolean add(E e)  往集合中添加元素
boolean remove(Object o) 删除指定元素
void clear() 清空集合所有元素
boolean contains(Object o) 判断集合中是否包含某个元素
boolean  isEmpty() 判断集合是否为空(元素个数为0)
int size()获取集合的元素个数
public Object[] toArray() : 把集合中的元素,存储到数组中

3. List接口

List接口下的集合是有索引的,所以List接口在继承Collection接口的基础上,还提供一些特有的方法,可以通过索引操作集合元素。

List接口下特有的方法:

void add(int index, E element)  在指定索引出添加元素
E remove(int index) 根据索引删除元素,返回被删元素
E set(int index, E element) 替换指定索引处的元素,返回被替换的元素
E get(int index)    获取指定索引处的元素
①ArrayList类常用方法
ArrayList集合中常用的成员方法:
        1.boolean add(E e)  往集合中添加元素,末尾追加
        2.void add(int index, E element) 在集合的指定索引处添加元素
        3.boolean contains(Object o) 判断集合中是否包含指定的元素 包含返回true,不包含返回false
        4.E get(int index) 获取集合中指定索引处的元素
        5.int size() 获取集合中元素的个数,获取集合的长度
        6.E remove(int index)  移除并返回指定索引处的元素
        7.boolean remove(Object o) 移除此集合中首次出现的指定元素,元素存在删除成功返回true,元素不存在删除失败返回false
        8.E set(int index, E element) 把指定索引处的元素,替换为新的元素,返回被替换的元素
          0       1         2      3    4
        [柳岩, 迪丽热巴, 赵丽颖, 杨幂, 杨幂]
    注意:
        1.集合的参数是(E,Object),传递集合中的元素
          集合的参数是(int index),传递元素对应的索引
        2.操作集合的索引,一定要避免索引越界异常,不要超出了集合索引的使用范围
            IndexOutOfBoundsException:集合索引越界
            StringIndexOutOfBoundsException:字符串索引越界
            ArrayIndexOutOfBoundsException:数组索引越界
②LinkedList集合(双向链表)
java.util.LinkedList<E> implements List<E>接口
List 接口的链接列表实现。
LinkedList集合底层是一个双向链表:查询慢,增删快
双向:是一个有序的集合,存储元素和取出元素的顺序是一致的
LinkedList集合有一些操作首尾元素的方法:
    public void addFirst(E e) :将指定元素插入此列表的开头。
    public void push(E e) :将元素推入此列表所表示的堆栈。
    public void addLast(E e) :将指定元素添加到此列表的结尾。
    
    public E getFirst() :返回此列表的第一个元素。
    public E getLast() :返回此列表的最后一个元素。
    
    public E removeFirst() :移除并返回此列表的第一个元素。
    public E pop() :从此列表所表示的堆栈处弹出一个元素。
    public E removeLast() :移除并返回此列表的最后一个元素。
   
    public boolean isEmpty() :如果列表不包含元素,则返回true。
注意:
	使用LinkedList集合特有的方法,不能使用多态创建对象
	List<String> list = new LinkedList<>(); 弊端:不能使用实现类特有的操作首尾元素的方法
	LinkedList<String> linked = (LinkedList<String>)list;//向下转型

4. Set接口

java.util.Set 接口和 java.util.List 接口一样,同样继承自 Collection 接口,它与Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比Collection 接口更加严格了。与 List 接口不同的是, Set 接口都会以某种规则保证存入的元素不出现重复

Set集合取出元素的方式可以采用:迭代器、增强for。

Set集合的特点:

  • 无序:元素存入和取出的顺序无法保证一致性
  • 不重复:重复的元素不会被存入。
  • 无索引:集合中没有索引,无法通过索引操作元素
①HashSet
  • HashSet是Set接口的实现类,存储的元素是无序不重复的。
  • 根据元素的哈希值确定存储位置,具有良好的存储和查找性能。
  • 元素没有索引,只能通过迭代器或增强for循环遍历。

HashSet的底层原理:

(1)保证元素唯一性

根据 hashCode() 和 equals() 方法保证元素的唯一性

hashCode()

Object类提供的本地方法,可以获取对象的哈希值。
public native int hashCode();
哈希值:
根据对象的地址和数据算出来的int类型的整数。
同一个对象多次调用 hashCode()方法得到的哈希值是相同的。
不同对象的哈希值通常是不一样的,但是也无法保证唯一,好的哈希算法能尽量保证不同对象的哈希值不同,减少哈希冲突。
可以通过重写 hashCode()方法自定义哈希值的计算规则。

equals()方法

Object类提供的成员方法,默认比较两个对象的内存地址。
public boolean equals(Object obj) {
return (this == obj);
}
所有类都可以重写该方法,自定义比较规则

元素添加流程

1.调用元素的hashCode()方法获取哈希值,确定存储位置。
2.如果位置为空,直接存入元素。
3.如果不为空,调用equals()方法和该位置的所有元素逐一比较,有相同则不存入,都不相同则添加成功。
结论:
当两个元素的哈希值相同,equals方法返回true,则表示两个元素相同,不会重复添加。
使用HashSet存储自定义对象时,需要重写 hashCode()方法和 equals() 方法。

(2) 底层数据结构

HashSet的底层是借助了HashMap实现数据存储的。HashMap底层使用哈希表存储元素,不同版本的JDK对哈希表的实现结构也不一样。

  • JDK7

    在JDK7及之前,哈希表采用数组+链表实现。每个链表被称为桶(bucket)。插入对象时,根据哈希值确定其在桶(数组)中的位置,如果该桶为空,则可将该对象直接插入相应的桶中。如果该桶已经存在元素,则需要将该对象与该桶中的所有对象进行比较,看看是否已经存在该对象,如果全部比较后均不存在,则将其添加到该桶中。

  • JDK8

    从JDK8开始,对于哈希表的实现做了一些改进,通过数组+链表+红黑树实现。当某个桶经常发生哈希冲突时,该链表长度将会变的非常长,下一次新对象将必须依次比较该桶中的所有对象,耗费大量时间降低性能。为此当桶中对象数量超过8个时,在JDK8中会将该链表转换为红黑树进行存储。此举将大大减少新对象在该桶的比较次数,提高性能。

②TreeSet集合

TreeSet集合是Set接口的一个实现类,底层依赖于TreeMap,是一种基于红黑树的实现,其特点为:

  1. 元素唯一 ,不允许存储重复元素
  2. 元素没有索引 ,元素没有带索引的方法
  3. 底层是一个红黑树结构(存储的元素都是有序的)
  4. 使用元素的自然顺序对元素进行排序,或者根据创建 TreeSet 时提供的 Comparator 比较器 进行
    排序,具体取决于使用的构造方法:
public TreeSet(): 根据其元素的自然排序进行排序
public TreeSet(Comparator<E> comparator): 根据指定的比较器进行排序

Comparator比较器排序

  • 如果集合元素没有实现Comparable接口,也可以使用Comparator比较器接口实现自定义排序。
  • 实现Comparator接口,需要重写 int compare(T o1, T o2) 方法。
  • TreeSet集合既支持自然排序,也支持比较器排序(使用带比较器参数的构造方法)
static <T> void sort(List<T> list, Comparator<? super T> c) 根据指定比较器产生的顺序对指定集合进行排序。
    参数:
        List<T> list:要排序的List集合
        Comparator<? super T> c:对集合进行排序的比较器
        java.utl.Comparator<T>接口:强行对某个对象 collection 进行整体排序 的比较函数。
        Comparator接口中的抽象方法:
            int compare(T o1, T o2) 比较用来排序的两个参数。
            参数:
                T o1, T o2:内部自动获取的集合中的元素[1,2,3,4]
            比较的规则(重点):
                升序:o1-o2
                降序:o2-o1
                两个元素相等:o1==o2

Comparable自然排序

  • 使用无参构造方法创建TreeSet集合时,元素排序默认使用自然排序
  • 自然排序要求元素类实现Comparable接口,并重写 compareTo 方法

注意:TreeSet集合元素实现实现Comparable接口,并重写 compareTo 方法 后,使用带比较器参数的构造方法创建TreeSet集合对象,其元素排序优先使用Comparator比较器排序

③LinkedHashSet集合
  • LinkedHashSet继承了HashSet,底层在哈希表的基础上,又维护了一个双向链表。
  • LinkedHashSet通过哈希表保证元素唯一性,又通过双向链表实现了元素存取的有序性。

5.Collections工具类

Collections 类在java.util包中,是一个操作 集合的工具类。Collections 类提供了许多操作集合的静
态方法,可以实现集合元素的排序、批量添加,查找,复制等操作。

Collections类常用方法 :
addAll(Collection<T> c, T... elements) 将所有指定的元素添加到指定的集合c中。
sort(List<T> list) 根据自然顺序对list集合的元素进行升序排序。
sort(List<T> list, Comparator<T> c) 根据指定的比较器,对list集合元素进行自定义排序。
shuffle(List<?> list) 随机打乱list集合中元素的顺序。

二、迭代器

1. Iterator迭代器
  • JDK 中提供了一个Iterator接口,称为迭代器,可以实现集合元素的遍历。
  • Collection接口中提供了iterator()方法,可以获取迭代器对象。
②Iterator操作元素的方法
boolean hasNext()		判断是否存在下一个元素。
E next()				获取下一个元素。
void remove()			删除元素
③Iterator遍历集合的步骤:
1.获取迭代器对象:   集合对象.iterator();
2.循环判断是否有下一个元素: 迭代器对象.hasNext()
3.如果有元素,调用 next() 方法,取出元素。
④并发修改异常
产生原因:

	当使用迭代器或者增强for循环遍历集合时,在迭代过程中调用集合类自身的remove或者add等方法改变集合的元素个数时,就会产生发修改异常,即ConcurrentModificationException。

解决办法:
	
	1.在遍历集合的同时,不修改集合长度
	2.Iterator接口中有一个方法叫remove,作用也是删除集合中的元素
		void remove() 删除使用next方法取出的集合中的元素
	3.Iterator接口有一个子接口叫ListIterator接口,在ListIterator接口中定义了往集合中添加元素的方法
		public interface ListIterator<E> extends Iterator<E>
		void add(E e) 将指定的元素插入列表(可选操作)。 ListIterator接口特有的方法
		void remove() 删除使用next方法取出的集合中的元素
	注意:
	1.如果使用迭代器中add|remove方法,往集合中添加|删除元素就相当于迭代器和集合商量好了,可以往集合中添加|删除元素,迭代器就不会抛出并发修改异常了
	2.ListIterator迭代器只能比那里List接口下边的集合(ArrayList,LinkedList),不能遍历Set
接口下的集合(HashSet,LinkedHashSet)


⑤迭代器的实现类是每个集合的内部类(扩展面试)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

2.增强for循环
  • 它是J D K 5之后出现的,其内部原理是一个Iterator迭代器,对迭代器进行了封装。

  • 数组和Collection集合都可以使用增强for循环。

    Collection接口有一个父接口叫Iterable
            public interface Collection<E> extends Iterable<E>
            java.lang.Iterable<T>接口
                实现这个接口允许对象成为 "foreach" 语句的目标。
                Collection接口继承了Iterable,所以可以使用增强for循环
                Collection接口所有的实现类,都可以使用增强for循环
    
  • 作用:简化迭代器遍历的语法。

  • 增强for使用注意:

    • 需要遍历的集合或数组不能为null。
    • 遍历过程中不能增删集合元素,否则会出现并发修改异常
  • 增强for的格式:
    for(元素数据类型 变量名 : 数组或者Collection集合) {
    //在此处使用变量即可,该变量就是元素
    }

三、泛型:可以在类或方法中预知地使用未知的类型

是JDK5中引入的特性,它提供了编译时类型安全检测机制

泛型的好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换
1.泛型的定义和使用

①泛型的接口

定义格式:

修饰符 interface接口名<代表泛型的变量> { }

泛型的接口使用:

  • 定义类时确定泛型的类型
  • 始终不确定泛型的类型,直到创建对象时,确定泛型的类型

泛型类:

定义格式:

修饰符 class 类名<泛型标记> {   }

泛型类的使用:

  • 泛型类在创建对象时确定泛型的真实类型。
  • 类中引用到泛型的地方都会替换成具体类型。

②泛型方法:

定义格式:

修饰符 <泛型标记> 返回值类型 方法名(类型 变量名) {  }

泛型方法使用:

  • 调用方法,传参时确定泛型类型。
  • 方法中引用泛型的地方会替换成具体类型。

2.通配符

当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用
泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。

①通配符基本使用 :

不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符

此时只能接受数据,不能往该集合中存储数据

② 通配符高级使用----受限泛型

之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定
一个泛型的上限和下限。

(1)泛型的上限:

  • 格式: 类型名称 <? extends 类 > 对象名称
  • 意义: 只能接收该类型及其子类

(2)泛型的下限:

  • 格式: 类型名称 <? super 类 > 对象名称
  • 意义: 只能接收该类型及其父类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值