Java学习——集合进阶

Java中集合的体系结构:

单列集合:

Collection(接口)

        Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的

常见方法:

        public boolean add(E e):把给定的对象添加到当前的集合中

                1.往List系列的集合中添加数据,方法永远返回true

                2.往Set系列的集合中添加数据,当前添加的数据不存在,方法返回true,如果已经存在,返回false

        public void clear():清空集合中所有元素        

        public boolean remove(E e):把给定的对象在当前集合中删除

                1.只能通过元素的对象进行删除,而不能通过元素的索引进行删除

                2.删除成功返回true,删除失败返回false

                                public boolean contains(Object obj):判断当前集合中是否存在给定的对象

                                                底层依赖对象的equals方法进行判断的,需要重写Javabean类中的equals方法

                                public boolean isEmpty():判断当前集合是否为空

                                public int size():返回集合中元素的个数/集合的长度

                        Collection的遍历方式:

                                迭代器遍历:

                                        迭代器不依赖索引

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

                                        获取迭代器:

                                                Iterator iterator():返回迭代器对象,默认指向当前集合的0索引

                                        常用方法:

                                                boolean hasNext():判断当期位置是否有元素,有元素返回true,没有元素返回false

                                                E next():获取当前位置的元素,并将迭代器对象移向下一个位置

                                                1.当迭代器指向最后一个位置时如果依旧调用next会报NoSuchElem entException的错误

                                                2.迭代器遍历完毕后指针不会复位

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

                                                4.迭代器遍历时不能用集合的方法进行增加或删除

                                增强for遍历:

                                                增强for的底层就是迭代器,是为了简化迭代器的代码书写

                                                JDK5之后出现的,其内部原理是一个Iterator迭代器

                                                所有的单列集合和数组才能使用增强for遍历

                                                修改增强for中的变量,不会改变集合中原本的数据

for(元素的数据类型 变量名:数组或集合){
}

                               Lambda表达式遍历:

                                                default void forEach(Consumer action):结合lambda表达式遍历集合

                                                action为lambda表达式

                         List(接口): 添加元素是有序(存取元素顺序一致)、可重复(存储的元素可以重复)、有索引的(可以通过索引操作元素)

                                特有方法:

                                        void add(int index,E element):在此集合的指定位置处插入指定的元素

                                                        原先索引处的元素依次往后移动

                                        E remove(int index):删除指定索引处的元素,返回被删除的元素

                                                        调用方法时如果发生了重载的现象那么会优先调用实参和形参类型完全一致的那个方法

                                        E set(int index,E element):修改指定索引处的元素,返回被修改的元素

                                        E get(int index):返回指定索引处的元素

                                List集合的遍历方式:

                                        1.迭代器遍历:在遍历的过程中需要删除元素

                                        2.列表迭代器遍历:在遍历的过程中需要添加元素

                                                next()\hasNext()\previous()\hasPrevious()

                                                获取一个列表的迭代器对象,里面的指针默认是指向0索引的

                                                额外添加了一个方法,在遍历的过程中,可以添加元素

                                        3.增强for遍历:仅仅想遍历元素

                                        4.Lambda表达式遍历:仅仅想遍历元素

                                        5.普通for循环遍历:如果遍历的时候想要操作索引

                                               size方法和get方法结合,对list中的每一个元素进行遍历

                                LinkedList(实现类):

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

                                        特有的方法:

                                                public void addFrist(E e):在该列表开头插入指定的元素

                                                public void addLast(E e):将指定的元素追加到此列表的末尾

                                                public E getFirst():返回此列表中的第一个元素

                                                public E getLast():返回此列表中的最后一个元素

                                                public E removeFirst():从此列表中删除并返回第一个元素

                                                public E removeLast():从此列表中删除并返回最后一个元素

ArrayList(实现类):

        底层原理:

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

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

                3.存满时,会扩容1.5倍

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

Vector(实现类):已经被淘汰

Set(接口):添加元素是无序、不可重复、无索引的

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

HashSet(实现类):无序、不可重复、无索引的

         底层原理:采用哈希表存储数据

        哈希表是一种对于增删改查数据性能都较好的结构

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

        根据hashCode方法算出来的int类型的整数

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

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

对象哈希值的特点:

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

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

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

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

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

LinkedHashSet(实现类):有序、不可重复、无索引的 hashSet的子类

        可以保证数组的存储和取出的元素顺序是一致的

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

TreeSet(实现类):可排序、不可重复、无索引的

        默认排序规则:

                对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序

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

        自定义排序方法:

                添加的Javabean类实现Comparable接口,并重写里面的抽象方法,再指定排序规则

        比较器排序:

                创建TreeSet对象的时候传递比较器Comparator指定规则

        如果自定义排序方法和比较器排序都存在,那么以比较器排序方式为主。

使用场景:

        1.如果想要集合中的元素可以重复:使用ArrayList集合,基于数组的

        2.如果想要集合中的元素可以重复,而且当前的增删操作明显多于查询:使用LinkedList集合,基于链表

        3.如果想对集合中的元素去重:使用HashSet集合,基于哈希表

        4.如果想对集合中的元素去重,而且保证存储顺序:使用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet

        5.如果想对集合中的元素进行排序:使用TreeSet集合,基于红黑树,后续也可以用List集合实现排序

双列集合:

双列集合的特点:

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

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

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

        4.键+值这个整体称之为键值对或键值对对象,在Java中叫做Entry对象

常见的API:

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

        V put(K key,V value):添加元素

                添加数据时,如果键不存在,那么直接把键值对对象添加到Map集合中,返回null

                添加数据时,如果键已经存在,那么会把原有的键值对对象覆盖,并返回被覆盖的值

        V remove(Object key):根据键删除键值对元素

        void clear():移除所有的键值对元素

        boolean containsKey(Object key):判断集合是否包含指定的键

        boolean containsValue(Object value):判断集合是否包含指定的值

        boolean isEmpty():判断集合是否为空

        int size():集合的长度,也就是集合中键值对的个数

Map集合的遍历:

        1.键找值

// 获取所有的键,把这些键放到一个单列集合中
Set keys = map.keySet();
//遍历单列集合,得到每一个键
for(String:key in keys){
    String value = map.get(key);
}

        2.键值对

//通过一个方法获取所有的键值对对象,返回一个Set集合
Set> entries = map.entrySet();
//遍历entires集合,得到里面的每一个键值对对象
for(Map.Entry entry:entries){
    String key = entry.getKey();
    String value = entry.getValue();
    
}

        3.结合Lambda表达式:

default void forEach(BiConsumer action):结合Lambda表达式遍历Map集合

HashMap的特点:

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

        2.没有额外需要学习的特有方法,直接使用Map里面的方法即可

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

        4.和HashSet底层原理一模一样,都是哈希表结构

        5.依赖hashCode方法和equals方法保证键的唯一

        6.如果键存储的是自定义对象,需要重写hashCode和equals方法,如果值存储的是自定义对象,则不需要重写hashCode和equals方法

LinkedHashMap:

        由键决定:有序、不重复、无索引

        这里有序指的是保证存储和取出的元素顺序一致

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

TreeMap:

        TreeMap和TreeSet底层原理一样,都是红黑树结构

        由键决定特性:不重复、无索引、可排序

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

可变参数:

        方法形参的个数是可以发生变化的

        数据类型...形参名字

        底层就是一个数组,Java会帮助我们创建该数组

        1.在方法的形参中最多只能写一个可变参数

        2.在方法当中,如果除了可变参数外,还有其他的形参,那么可变参数要写在最后 

Collections:

        java.util.Collections:集合的工具类

        常用API:

                public static boolean addAll(Collection c,T ... elements):批量添加元素

                public static void shuffle(List list):打乱List集合元素的顺序

泛型:

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

        格式:<数据类型>

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

        好处:

                1.统一数据类型

                2.把运行时期的问题提前到编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来

        细节:

                1.泛型中不能写基本数据类型

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

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

        泛型类:

                当一个类中某个变量的数据类型不确定时可以定义带有泛型的类

                格式:

修饰符 class 类名<类型>{

}
此处E可以理解为变量,但不是用来记录数据的,而是记录数据的类型,可以写成T、E、K、V等等

        泛型方法:

                方法中形参类型不确定时,可以使用类名后面定义的泛型,也可以在方法申明上定义自己的泛型

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

}
此处类型可以理解为变量,但是不是用来记录数据的,而是记录类型的,可以写作:T,E,K,V等

        泛型接口:

修饰符 interface 接口名<类型>{

}
1.实现类给出具体类型
2.实现类延续泛型,创建对象时再确定

        泛型的继承和通配符:

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

                ?:表示不确定的类型

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

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

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

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

不可变集合:

不可变集合:不可以被修改的集合,包括长度和内容,只能进行遍历访问

应用场景:

        1.如果某个数据不能被修改,把它防御性的拷贝到不可变集合中

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

List list = List.of(E1,E2,....,En);

Set set = Set.of(E1,E2,....,En);

创建Map的不可变集合:

        1.键不可重复

        2.Map里面的of方法参数是有上限的,最多只能传递20个参数

        3.如果要传递的键值对对象多于10个,使用ofEntries方法

Stream流:

结合Lambda表达式简化集合、数组的操作

使用步骤:

1.先得到一条Stream流,并把数据放上去

单列集合: default Stream stream():Collection中的默认方法

双列集合:无,无法直接使用stream流

数组:public static Stream stream(T[] array):Arrays工具类中的静态方法

 一堆零散数组:public static Stream of(T...values):Stream接口中的静态方法

2.利用Stream流中的API进行各种操作

中间方法:方法调用完毕后还可以调用其他方法

a.Strean filter(Predicate predicate):过滤

        predicate如果返回true,表示当前数据保留,否则舍弃掉当前数据

b.Stream limit(long maxSize):获取前几个元素

c.Stream skip(long n):跳过前几个元素

d.Stream distinct():元素去重,依赖hashCode和equals方法

e.static Stream concat(Stream a,Stream b):合并a和b两个流为一个流

f.Stream map(Function mapper):转换流中的数据类型

注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程

注意2:修改Stream流中的数据,不会影响原来的集合或者数组中的数据           

终结方法:最后一步,调用完毕后不能调用其他方法

a. void forEach(Consumer action):遍历

        consumer的泛型表示流中数据的类型

        accept方法的形参s依次表示流中的每一个数据

        方法体对每一个数据进行相关的处理操作

b.long count():统计

c.toArray():收集流中的数据,并放到一个数组中

        IntFunction的泛型表示具体类型的数组

        apply的形参表示流中数据的个数,要跟数组的长度保持一致

        apply的返回值:具体类型的数组

d.collect(Collector collector):收集流中的数据,放到一个集合中

        收集到List中:Collectors.toList()

        收集到Set中:Collectors.toSet()

        收集到Map中:Collectors.toMap()

                参数一:

                        Function泛型一:表示流中每一个数据的类型

                                      泛型二:表示Map集合中键的数据类型

                        方法apply形参:依次表示流里面的每一个数据

                                       方法体:生成键的代码

                                        返回值:已经生成的键

                参数二:

                        Function泛型一:表示流中每一个数据的类型

                                      泛型二:表示Map集合中值的数据类型

                        方法apply形参:依次表示流里面的每一个数据

                                       方法体:生成值的代码

                                       返回值:已经生成的值

                

你可能感兴趣的:(Java学习,学习,java)