Java-集合进阶

1.集合体系结构

分为单列集合(Collection)和双列集合(Map)

List系列集合:添加的元素是有序(存和取的顺序一样)、可重复、有索引

Set系列集合:添加的元素是无序、不重复、无索引

2.Collection

Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继续使用的。Collection是一个接口,不能直接创建对象,只能创建实现类的对象,比如ArrayList。

2.1基本方法

Collection里面定义的方法是共性的方法,所以不能通过索引对元素进行删除,只能通过元素的对象进行删除。

contains方法的底层是依赖equals方法进行判断是否存在的。如果集合中存储的是自定义对象,也想通过equals来判断是否包含,那在JavaBean中要重写equals方法。

2.2Collection的遍历方式:

1)迭代器遍历:

--特点:迭代器不依赖索引

--迭代器在Java中的类Iterator,迭代器是集合专用的遍历方式

--Collection集合获取迭代器:

--Iterator中常用的方法:

java 复制代码
Iterator<String> it = c.iterator();//创建指针
        while (it.hasNext()) {//判断是否有元素
            String s = it.next();//获取元素,移动指针
            System.out.println(s);
        }

细节:

--报错NoSuchElementException

--迭代器遍历完毕,指针不会复位

--循环中只能使用一次next方法

--迭代器遍历时,不能用集合的方法进行增加或者删除。如果实在要删除,可以使用迭代器里面的方法remove进行删除

2)增强for遍历:

底层就是迭代器,为了简化迭代器的代码书写的,是jdk5之后出现的,其内部原理就是一个iterator迭代器。

所有的单列集合和数组才可以用增强for进行遍历。

java 复制代码
/**
 * 基本格式
 * for(元素的数据类型 变量名:数组或集合){
 *
 * }
 * 修改增强for中的变量,不会改变集合中原本的元素
 */

for(String s:c){
    System.out.println(s);
}

3)Lambda表达式遍历:

java 复制代码
/**
 * 底层原理:自己会遍历集合,依次得到每一个元素,
 * 将得到的元素交给accept方法,s表示依次得到的每一个元素
 */
c.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

//替换为lambda表达式
c.forEach(s-> System.out.println(s));

3.List集合

3.1基本方法

Collection的方法List都继承了,但是List有索引

remove方法删除元素的细节:

继承了Collection的remove方法和自己的remove方法,在调用方法的时候如果方法出现重载现象,优先调用实参类型和形参类型一致的方法,如果实在要通过元素进行删除,可以手动装箱把数据编程包装类。

3.2遍历方式

1)迭代器遍历

2)列表迭代器遍历(独有的)

listIterator()迭代器,和迭代器差不多,使用方法一致,但是额外增加了一个方法,可以使用add方法添加元素

3)增强for遍历

4)Lambda表达式遍历

5)普通for循环

4.ArrayList集合

1)利用空参创建的集合,在底层创建一个默认长度为0的数组

2)添加第一个元素时,底层会创建一个新的长度为10的数组

3)存满时,会扩容1.5倍,也就是15--接着再存满时持续扩容

4)如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

5.LinkedList集合

1)底层数据结构是双链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的

2)LinkedList本身有很多直接操作首尾元素的特有API

6.泛型深入

6.1泛型基本概述

泛型:是jdk5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。

泛型格式:<数据类型>

注意:泛型只能支持引用数据类型

泛型的好处:1)统一数据类型 2)把运行时期的问题提前到了编译时间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来

拓展:Java中的泛型是伪泛型

解释:编译的时候检查添加的字符串是否符合泛型,如果不是,直接编译报错,

细节:

1)泛型中不写基本数据类型

2)指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型

3)如果不写成泛型,默认类型是Object

6.2泛型的使用

泛型可以在很多地方进行定义:类后面(泛型类),方法上面(泛型方法),接口后面(泛型接口)

1)泛型类

使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

格式:修饰符 class 类名<类型>{} 不确定类型时,可以把类型写成E就表示是不确定类型

此处的E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型

2)泛型方法

使用场景:方法中形参类型不确定的时候,可以使用类名后面定义的泛型(所有方法都能使用)或者在方法申明上定义自己的泛型(只有本方法可以使用)

格式:修饰符 <类型> 返回值类型 方法名(类型 变量名){}

3)泛型接口

格式:修饰符 interface 接口名<类型>{}

使用方式:1)实现类给出具体类型 2)实现类延续泛型,创建对象时再确定

6.3泛型的继承和通配符

泛型不具备继承性,但是数据具备继承性

java 复制代码
public class test{
    public static void main(String[] args) {
        
        ArrayList<Ye> list1 = new ArrayList<>();
        ArrayList<Fu> list2 = new ArrayList<>();
        ArrayList<Zi> list3 = new ArrayList<>();
        
        method(list1);
        //因为泛型不具备继承性
        method(list2);//报错
        method(list3);//报错


        //以下方式不会报错--因为数据可以继承
        list1.add(new Ye());
        list1.add(new Fu());
        list1.add(new Zi());
    }
    
    public static void method(ArrayList<Ye> list){
        
    }

    //如果使用E泛型写的话,那任何类型的数据都可以装配进去
    public static<E> void method2(ArrayList<E> list){
        
    }
    
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}

使用通配符解决以上问题:? extends E:表示可以传递E或者E所有的子类类型

? super E:表示可以传递E或者E所有的父类类型

应用场景:

1.如果在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口

2.如果类型不确定,但是能指定以后只能传递某个继承体系中的,就可以使用泛型的通配符

7.Set集合

Set集合的特点:无序、不重复、无索引

Set接口中的方法上基本与Collection的API一致

7.1HashSet

无序、不重复、无索引

HashSet集合底层是采取哈希表存储数据。哈希表是一种对于增删改查数据性能都比较好的结构

在jdk8之前:哈希表是由数组+链表组成的

在jdk8开始:哈希表是由数组+链表+红黑树组成的

哈希值:哈希值对象整数的表现形式

哈希值是根据hashCode方法算出来的int类型的整数

该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算

一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

对象的哈希值特点:

如果没有重写hashCode方法,不同对象计算出的哈希值是不同的

如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的

在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)

hashSet的底层原理:

jdk8以后,当链表长度超过8且数组长度大于等于64时,自动转换为红黑树

如果集合中存储的是自定义对象,必须要重写hashCode和equals方法

7.2LinkedHashSet

有序、不重复、无索引

底层原理:底层数据结构依然是哈希表,知识每个元素又额外的多了一个双链表的机制记录存储顺序。

7.3TreeSet

可排序、不重复、无索引

底层原理:TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都比较好

TreeSet默认的规则:

对于数值类型:Integer、double,默认找从小到大的顺序进行排序

对于字符、字符串类型:按照字符在ASCII码表中的数字升序进行排序

TreeSet的两种比较方式:

方式一:默认排序/自然排序:Javabean类实现Comparable接口指定比较规则

方式二:比较器排序:创建TreeSet对象时候,传递比较器Comparable指定规则

使用规则:默认使用第一种,如果第一种不能满足当前需求,就使用第二种

8.双列集合

特点:

1)双列集合一次需要存一对数据,分别为键和值

2)键不能重复,值可以重复

3)键和值是一一对应的,每一个键只能找到自己对应的值

4)键+值这个整体称之位键值对

Map常见API:

Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的

put添加元素的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null。

如果键存在,那么原有的键值对对象被覆盖,会把被覆盖的值进行返回。

Map的遍历方式:

1)键找值:map.keySet();获取键集合,map.get(key);获取值

2)键值对:Set<Map.Entry<String, String>> entries = map.entrySet();获取键值对对象,String key = entry.getKey(); String value = entry.getValue();获取键和值

3)Lambda表达式

8.1HashMap

HashMap的特点:

1)HashMap是Map里面的一个实现类

2)没有额外需要学习的特有方法,直接使用Map里面的方法就可以了

3)特点都是由键决定的:无序、不重复、无索引

4)hashMap和hashSet的底层原理是一样的,都是哈希表结构的,依赖hashCode和equals方法保证键的唯一性。如果键存储的是自定义对象,需要重写hashCode和equals方法;如果值存储的是自定义对象,不需要重写hashCode和equals方法

8.2LinkedHashMap

特点:

1)由键决定:有序(存和取的顺序一样)、不重复、无索引

2)原理:底层数据结构是哈希表,只是每个键值对元素额外多了一个双链表的机制记录存储顺序

8.3TreeMap

特点:

1)TreeMap跟TreeSet底层原理一样,都是红黑树结构的

2)由键决定特性:不重复、无索引、可 排序(对键进行排序)

3)默认按照键的从小到大进行排序,也可以自己规定键的排序规则

书写两种排序规则:

1)实现Comparable接口,指定比较规则

2)创建集合时进行传递Comparator比较器对象,指定比较规则

9.Collections

java.util.Collections是集合类工具。作用:Collections不是集合,而是集合的工具类

常用API:

10.不可变集合

应用场景:

1)如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。

2)或者当集合对象被不可信的库调用时,不可变形式是安全的。

在List、Set、Map接口中,都存在静态的of方法,可以获取一个不可变的集合。

一旦创建无法修改、添加、删除,只能进行查询操作。

三个方法的细节:

List:直接使用

Set:元素不能重复

Map:元素不能重复、键值对数量最多10个,超过十个用ofEntries方法。jdk10之后还可以使用copyof的方法

相关推荐
xyq20242 小时前
WebForms 数据库连接详解
开发语言
噗噗123 小时前
基于 Go 语言实现企业大群发任务的平滑限流与多线程漏斗调度器
java·开发语言
fie88893 小时前
基于MATLAB的GPS捕获、跟踪与PVT计算实现
开发语言·matlab
甲方大人请饶命3 小时前
Java-异常、File
java·开发语言
社交怪人3 小时前
【打印菱形】信息学奥赛一本通C语言解法(题号1028)
c语言·开发语言
历程里程碑3 小时前
53 多路转接select
linux·开发语言·数据结构·数据库·c++·sql·排序算法
多敲代码防脱发3 小时前
Spring进阶(Aware接口)
java·后端·spring
Chase_______3 小时前
【Java基础核心知识点全解·01】Java运行机制详解:从 HelloWorld 到 classpath 找类流程
java·开发语言·python
杜子不疼.3 小时前
【C++ AI 大模型接入 SDK】 - LLMProvider 抽象基类与策略模式
开发语言·c++·策略模式