Java集合

一、Collection 接口

Java集合主要是两组(单列集合 , 双列集合)

Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合

Map 接口的实现子类 是双列集合,存放的 K-V

在这里插入图片描述

Collection 接口的两种遍历方式

1.使用 Iterator(迭代器):迭代器主要用于遍历Collection集合中的元素,即所有实现了Collection接口的集合类都有一个Iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。【注意:Iterator仅用于遍历集合,它本身并不存放对象】

2.使用增强for循环:增强for循环本质就是简化版的Iterator,只能用于遍历集合或数组。

类名带个s,一般就表示工具类,

二、List接口

概述
  • List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复。

  • List 集合中的每个元素都有其对应的顺序索引,即支持索引【索引是从 0 开始的】

  • List接口的实现类常用的有ArrayList, LinkedList,Vector

List接口的三种遍历方式【实现了List接口的都具有这三种遍历方式】

1.使用iterator迭代器;

2.使用增强for循环(底层还是使用迭代器)

3.使用普通for循环

List 接口 是Collection 的子接口,因此,常用方法和 Collection 接口一样。

ArrayList集合
  1. ArrayList底层数据结构是数组,查询快、增删慢。
  2. ArrayList可以加入null,并且可以加入多个null。
  3. ArrayList是线程不安全的。
ArrayList扩容的一些细节:

ArrayList中维护了一个Object类型的数组transient Object[] elementData; //transient 表示该属性不会被序列化

  • 当创建ArrayList对象使用的是无参构造器时,则初始elementData容量为0,第一次添加则扩容elementData为10,如果需要再次扩容则扩容elementData为1.5倍;
  • 当创建ArrayList对象使用的是有参构造器就是指定大小时,则初始elementData容量为指定大小,如果需要再次扩容则直接扩容elementData为1.5倍;

​ 通过迭代器获取next值的时候,都会去判断预期修改值和实际修改值是否相等,这时如果使用集合的添加方法list.add去修改时会触发并发修改异常,因为增删会带来元素的移动,增加数据会向后移动,删除数据会向前移动,但是用迭代器自身的功能就不会报并发修改异常,另外迭代器自身的功能只有remove删除方法没有添加add方法,

ArrayList的三种遍历方式

1.使用iterator迭代器;

2.使用增强for循环(底层还是使用迭代器)

3.使用普通for循环

通过普通for循环索引值遍历效率最高,增强for循环遍历次之,迭代器遍历最低。

ArrayList的方法

使用对象名.方法名();调用ArrayList集合中的方法
增:
1).public boolean add(E e) 将指定的元素追加到此集合的末尾.【排队】
2).public void add(int index,E element) 在此集合中的指定位置插入指定的元素【插队】
删:
3).public boolean remove(Object o) 删除指定的元素,返回删除是否成功。返回值:是否删除成功!
4).public E remove(int index) 删除指定索引处的元素,返回被删除的元素。返回值:被删除的对象!
改:
5).public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
查:
6).public E get(int index) 返回指定索引处的元素
7).public int size() 返回集合中的元素的个数

ArrayList集合其它的成员方法:
public boolean isEmpty(): 判断当前集合是否为空。
public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。
public void clear() :清空集合中所有的元素。

JDK1.9之后:ArrayList默认的构造方法只会使用默认的空数组,使用的时候才会开辟新的数。

JDK1.9之前:ArrayList默认的构造会默认开辟大小为10的数组。

Vector
  1. Vector底层也是一个对象数组protected Object[] elementData;
  2. Vector是线程安全的
扩容的细节:
  • 如果是无参,默认是10,如果还需要扩容,就按2倍扩容;

  • 如果是有参也就是指定大小,则每次直接按2倍扩容;

LinkedList
  1. LinkedList底层实现了双向链表和双端队列特点,增删快,查询慢;
  2. LinkedList可以添加任意元素(元素可以重复),包括null;
  3. 线程不安全,没有实现同步;
LinkedList的三种遍历方式

1.使用iterator迭代器;

2.使用增强for循环(底层还是使用迭代器)

3.使用普通for循环

三、Set接口

概述
  • Set集合类中元素无序(即添加顺序和取出顺序不一致);

  • Set集合没有索引

  • Set接口的实现类的对象不能存放重复的元素, 可以添加一个 null;

  • Set接口的实现类常用的有TreeSet,HashSet

和 List 接口一样, Set 接口也是 Collection 的子接口,因此,常用方法和 Collection 接口一样。

Set接口的遍历方式

1.使用iterator迭代器;

2.使用增强for循环(底层还是使用迭代器)

【不能使用索引的方式也就是普通for循环来获取】

HashSet
  1. HashSet底层实际是HashMap;
  2. HashSet可以存放null值,但只能有一个null;
  3. HashSet是无序的(即添加顺序和取出顺序不一致);
  4. HashSet不能有重复元素/对象。
  5. HashSet线程不安全
HashSet添加元素底层实现细节
  1. HashSet底层实际是HashMap,第一次添加时数组扩容到16,加载因子为0.75,临界值为16x0.75=12,如果数组达到临界值12时,就会触发第二次扩容到16x2=32,那么新的临界值就是32x0.75=24,以此类推。
  2. 当添加一个元素时,先得到哈希值,对哈希值进行运算得出一个索引值(即要存放在哈希表中的位置号),看这个索引位置是否已经存放元素;
  3. 如果没有则直接加入;
  4. 如果有就调用equals方法比较,如果相同,就放弃添加,如果不相同,则以链表的方式添加到最后;
  5. 在jdk1.8中,如果一条链表的元素个数到达8,并且数组大小等于64,就会进行树化(红黑树),否则仍然采用数组扩容机制。

HashSet去重原理是通过重写hashcode()和equals()

TreeSet去重原理是通过排序结果去重通过:1自然排序,实现Comparable接口重写compareto方法;2.比较器排序,在TreeSet的构造方法中传入Comparator的实现类;当这两种并存时也会以比较器优先

TreeSet

对于自定义的类型来说TreeSet无法进行自动排序,因为没有指定元素之间的比较规则,放在TreeSet集合中的元素要实现:java.lang.Comparable接口,并且实现compareTo方法【equals方法可以不写】compareTo方法使用二叉树原理,根据比较器的属性去重。如果compareTo返回0,说明是重复的;如果是负数,则往前面排;如果是正数,往后面排。

TreeSet去重要么实现Comparable接口并重写compareTo()方法,要么创建TreeSet时传入一个比较器。

LinkedHashSet
  1. LinkedHashSet 是HashSet 的子类;
  2. LinkedHashSet 底层是LinkedHashMap,底层是一个数组+双向链表;
  3. LinkedHashSet是根据HashCode值来决定元素的存储位置,同时使用链表来维护元素的次序,这样在遍历LinkedHashSet的时候也能确保元素插入和取出顺序一致。

四、Map

所有Map集合的Key是无序不可重复的,key和value都是引用数据类型,存的都是内存的地址。

Map集合的实现类主要为HashMap、HashTable。子接口有一个SortedMap,SortedMap有一个TreeMap实现类。

Map的遍历方式

Map集合遍历不能迭代,也不能使用foreach

方式1:键找值方式

  • 获取Map中所有的键,方法提示: keySet()

  • 遍历键的Set集合,得到每一个键

  • 根据键,获取键所对应的值。方法提示: get(K key)

    public void test1() {
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1,"测");
        map.put(2,"试");
        map.put(3,"类");
        Set<Integer> set = map.keySet();
        for (Integer i: set) {
            System.out.println(integer+"="+map.get(i));
        }
    }

Map中将每个键和值封装成一个个的Entry<K, V>对象,并提供 getKey() 和 getValue() 方法,用于获取Entry中封装的键和值。

方式2:键值对方式

1、获取map集合中所有 Entry<K,V> 对象的集合: entrySet()方法。
2、遍历Entry的集合,获取每个Entry<K,V>对象。
3、使用 Entry<K,V> 提供的方法获取键和值:getKey() ,getValue()

    public void test2() {
        map<Integer, String> map= new HashMap<>();
        map.put(1,"测");
        map.put(2,"试");
        map.put(3,"类");
        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            Integer key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"  "+value);
        }
    }
HashMap
  1. HashMap底层数据结构JDK1.8之前是:数组+链表;JDK1.8之后是:数组+链表+红黑树。非线程安全的。
  2. 空参的HashMap初始容量是16,扩容的新容量等于旧容量向左移一位,即新容量是旧容量的2倍,默认加载因子为0.75,。
  3. Map集合中,键不允许重复,值可以重复。(比如身份证与姓名)
    键和值是一一对应的,通过键可以找到与之对应的唯一的值,要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。。
  4. 元素的存取无序。(HashSet的底层其实是借助了HashMap实现存储)
  5. HashMap的key可以为null(但只能有一个),value可以为null

HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。

SortedMap

SortedMap继承Map,所以SortedMap也有无序不可重复的特点,但SortedMap集合中key的元素可以自动按照大小排列,称为可排列集合。

TreeMap

TreeMap是SortedMap的实现类,无序不可重复,默认会对存入key的元素会按照大小排列,也可以自己定义排序,TreeMap集合底层的数据结构是红黑树;可以对元素的键进行排序。排序方式有两种:自然排序,比较器排序。(键的排序规则与TreeSet一样)。

HashTable
  1. HashTable底层采用数组+链表的数据结构,HashTable不会转换为红黑树。
  2. HashTable是线程安全的,效率太低,使用较少,如果在非线程安全的情况下使用,建议使用HashMap替换,如果在线程安全的情况下使用,建议使用ConcurrentHashMap。
  3. HashTable的的key和value都不能为null,否则会报空指针异常。
  4. HashTable初始容量是为11,扩容的新容量等于旧容量左移加1,即新容量是旧容量的2倍加1,默认加载因子为0.75

HashTable中的数组长度尽量为素数或者奇数,同时HashTable采用取模的方式来计算数组下标,这样减少了Hash碰撞,计算出来的数组下标更加均匀,这样效率会比HashMap利用位运算计算数组下标低,但是HashTable采用头插法的方式迁移数组,相比较HashMap的尾插法来说效率更高,

Properties

Properties是HashTable下的一个实现类,由于继承了HashTable,所以Properties也是线程安全的,但Properties的key和value只支持String数据类型。

度尽量为素数或者奇数,同时HashTable采用取模的方式来计算数组下标,这样减少了Hash碰撞,计算出来的数组下标更加均匀,这样效率会比HashMap利用位运算计算数组下标低,但是HashTable采用头插法的方式迁移数组,相比较HashMap的尾插法来说效率更高,

Properties

Properties是HashTable下的一个实现类,由于继承了HashTable,所以Properties也是线程安全的,但Properties的key和value只支持String数据类型。

哈希算法存在一个缺点就是哈希冲突,哈希冲突的解决方案有多种:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值