Java集合

目录

一、单列集合 Collection

1.1 前言知识

1.1.1 Collection接口常用的方法

1.1.2 Collection集合与数组间的转换

1.2 Collection实现遍历的两种方式

1.2.1 迭代器Iterator

1.3 Collection集合的List接口

1.3.1 源码分析

1.4 Collection集合的Set接口

1.4.1 常用实现类

1.4.2 元素添加过程(源码分析)

1.4.3 存储对象所在类的要求

二、双列集合 Map

一、单列集合 Collection

1.1 前言知识

----Collection接口:单列集合,用来存储一个一个的对象

        ----List接口:存储有序的、可重复的数据。 -->“动态”数组

                ----ArrayList、LinkedList、Vector

        ----Set接口:存储无序的、不可重复的数据 -->高中讲的“集合”

                ----HashSet、LinkedHashSet、TreeSet

图示结构:

使用Collection集合存储对象,要求对象所属的类满足下面要求:

向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()

因为Collection接口提供了contain(Object obj)等方法,用来判断集合是否含有该对象元素,所以会使用到equals()方法

1.1.1 Collection接口常用的方法

add(Object obj),

addAll(Collection coll),

size(),

isEmpty(),

clear();

contains(Object obj),

containsAll(Collection coll),

remove(Object obj),

removeAll(Collection coll),

retainsAll(Collection coll),

equals(Object obj);

hasCode(),

toArray(),

iterator();

1.1.2 Collection集合与数组间的转换

集合 → 数组: toArray()方法

//将集合转换成数组
Object[] arr = coll.toArray();
​
for(int i = 0;i < arr.length;i++){
    //System.out.println(arr[i]);
}

数组 →集合: asList(T ...t)方法

List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
System.out.println(list);
​
List arr1 = Arrays.asList(new int[]{123, 456});
System.out.println(arr1.size());//1
​
List arr2 = Arrays.asList(new Integer[]{123, 456});
System.out.println(arr2.size());//2

1.2 Collection实现遍历的两种方式

  • 使用迭代器Iterator

  • foreach循环

1.2.1 迭代器Iterator

//通过需要操作的集合获取迭代器
Iterator iterator = coll.iterator();
//hasNext():判断是否还下一个元素,最开始指针指在第一个元素的上面一个位置
while(iterator.hasNext()){
    //next():①指针下移 ②将下移以后集合位置上的元素返回
    System.out.println(iterator.next());
}

1.2.2 使用增强for循环foreach

    Collection coll = new ArrayList();
    coll.add(123);
    coll.add(456);
    coll.add(new Person("Jerry",20));
    coll.add(new String("Tom"));
    coll.add(false);
    //for(集合元素的类型 局部变量 : 集合对象)
    for(Object obj : coll){
        System.out.println(obj);
    }

1.3 Collection集合的List接口

存储数据的特点:有序、可重复

常用方法:

增:add(Object obj)

删:remove(int index) / remove(Object obj)

改:set(int index, Object ele)

查:get(int index) 这一个是Collection接口中没有声明的

插:add(int index, Object ele)

长度:size()

遍历:① Iterator迭代器方式 ② 增强for循环 ③ 普通的循环

常用实现类:

----Collection接口:单列集合,用来存储一个一个的对象

        ----List接口:存储有序的、可重复的数据。 -->“动态”数组,替换原的数组

                ----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储

                ----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;线程不安全的;底层使用双向链表存储

                ----Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储

1.3.1 源码分析

1.3.1.1 ArrayList

ArrayList list = new ArrayList(); 底层Object[] elementData初始化为{}。为空

  • list.add(123); //第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]

  • 默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中

  • jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。

  • 结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)

1.3.1.2 LinkedList

LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为null

list.add(123); //将123封装到Node中,创建了Node对象。

Node类定义如下:

private static class Node<E> {
     E item;
     Node<E> next;
     Node<E> prev;
​
     Node(Node<E> prev, E element, Node<E> next) {
         this.item = element;
         this.next = next;
         this.prev = prev;
     }
 }

1.3.1.3 Vector

jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。 在扩容方面,默认扩容为原来的数组长度的2倍。

1.3.1.4 ArrayList、LinkedList、Vector三个集合的异同:

同:①三个类都实现了List接口 ②存储数据的特点一样:有序、可重复

不同:具体看上面的常用实现类以及源码分析

1.4 Collection集合的Set接口

存储数据特点:无序的、不可重复

以HashSet集合为例:

  1. 无序性:不等于随机性。存储的数据在底层数组中并非照数组索引的顺序添加,而是根据数据的哈希值决定的。

  2. 不可重复性:保证添加的元素照equals()判断时,不能返回true.即:相同的元素只能添加一个。

1.4.1 常用实现类

----Collection接口:单列集合,用来存储一个一个的对象

        ----Set接口:存储无序的、不可重复的数据 -->高中讲的“集合”

                ----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值

                        ----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历;在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据。对于频繁的遍历操作LinkedHashSet效率高于HashSet.

                ----TreeSet:可以照添加对象的指定属性,进行排序。

1.4.2 元素添加过程(源码分析)

以HashSet为例:

我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值, 此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置,判断 数组此位置上是否已经元素:

如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值: 如果hash值不相同,则元素a添加成功。--->情况2

如果hash值相同,进而需要调用元素a所在类的equals()方法:

        equals()返回true,元素a添加失败

        equals()返回false,则元素a添加成功。--->情况2

对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。对于jdk8,采用尾插法。

1.4.3 存储对象所在类的要求

1.4.3.1 HashSet or LinkedHashSet

要求:①向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals() ②重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码

重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。

1.4.3.2 TreeSet

  1. 向TreeSet中添加的数据,要求是相同类的对象。

  2. 并且因为TreeSet集合会排序,所以实体类要想按照自己要求排序,要实现Comparable接口。重写equals、compareTo方法。

二、双列集合 Map

常用实现类

----Map:双列数据,存储key-value对的数据 ---类似于高中的函数:y = f(x)

        ----HashMap:作为Map的主要实现类;线程不安全的,效率高;存储null的key和value

                ----LinkedHashMap:保证在遍历map元素时,可以照添加的顺序实现遍历。

                原因:在原的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap。

        ----TreeMap:保证照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序,底层使用红黑树

        ----Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value

                ----Properties:常用来处理配置文件。key和value都是String类型

HashMap的底层:数组+链表 (jdk7及之前) ;数组+链表+红黑树 (jdk 8)

存储结构的理解

Map中的key:无序的、不可重复的,使用Set存储所的key ---> key所在的类要重写equals()和hashCode() (以HashMap为例)

Map中的value:有序的、可重复的,使用List存储所的value --->value所在的类要重写equals() 一个键值对:key-value构成了一个Entry对象。

Map中的entry:无序的、不可重复的,使用Set存储所的entry

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值