Java中的集合详解

一、Colection接口

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

1.1 List接口

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

  • 常用方法
void add(int index, E element)//添加
boolean addAll(int index, Collection<? extends E> c)//添加另一个集合中的元素
E get(int index)//查找
int indexOf(Object o)//通过下标查找
ListIterator<E> listIterator()//迭代器
ListIterator<E> listIterator(int index)
E remove(int index)//删除某下标的数据
E set(int index, E element)//修改数据
List<E> subList(int fromIndex, int toIndex)//求子串

1.1.1 ArrayList

List接口的主要实现类

ArrayList arrayList = new ArrayList();
  • jdk1.6:
public ArrayList() {
    this(10);
}

底层创建的是长度为10的Object[ ]数组elementData

  • jdk1.7:
private static final int DEFAULT_CAPACITY = 10;
 
private static final Object[] EMPTY_ELEMENTDATA = {};
private transient Object[] elementData;
public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

无参构造创建的是一个空的数组,在add方法中初始化的默认值为10

  • 扩容
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);//复制
    }

每次扩容长度为之前的1.5倍,同时将原数组中的数据复制到新的数组

  • 结论:使用时经历避免使用空参构造器
  • jdk1.8
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

1.1.2 LinkedList

LinkedList linkedList = new LinkedList();

其底层是双向链表,存储单元为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.1.3 Vector

List接口的古老实现类(JDK1.0),不太常用
它底层和Arraylist一样,是通过数组实现的,但是它支持线程的同步
默认扩容为2倍

public Vector() {
        this(10);
    }

1.1.4 三者的异同

  • ArrayList:
    • 线程不安全,效率高
    • 底层使用Object[ ] elementData存储
  • LinkedList:
    • 底层使用双向链表存储
    • 对于频繁的插入、删除操作,效率较高
  • Vector:
    • 线程安全,效率低
    • 底层使用Object[ ] elementData存储
  • 相同处
    • 三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据

1.2 Set接口

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

  • 无序性:数据在底层数组中并非按照数组索引的顺序添加,而是由hashcode决定数组的索引
  • 不可重复性:通过hashcode()和equals()判断是否重复,先判断hashcode()是否相等,相等就再判断equals()

1.2.1 HashSet

Set接口的主要实现类,线程不安全,可以存储null值,实际上底层是用hashmap实现的

public HashSet() {
        map = new HashMap<>();
    }

1.2.2 LinkedHashSet

作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历
在HashSet的基础上添加了两个索引指针方便按添加遍历

1.2.3 TreeSet

底层使用的是红黑树存储,可以按照添加对象的指定属性进行排序

  • 向TreeSet中添加的数据必须是相同的对象
  • 自定义的类型必须有排序的方法,用于比较,而不是使用equals()

1.3 Map接口

image.png

  • 双列数据,存储key-value对的数据

1.3.1 HashMap

  • Map的主要实现类
  • 线程不安全
  • 效率高
  • 可以存储null的key和value
  • 底层
    • 数组+链表(jdk7之前)
    • 数组+链表+红黑树(jdk8)
  • CRUD:
    • V put(K key, V value)
    • void putAll(Map m)
    • V remove(Object key)
    • void clear()
    • V get(Object key)
    • int size()
    • boolean containsKey(Object key)
    • boolean containsValue(Object value)
    • boolean equals(Object o)
  • 遍历
  • 遍历key集合
//遍历key集合
Set set = hashMap.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
      System.out.println(iterator.next());
}
  • 遍历value集合
//遍历value集合
Collection values = hashMap.values();
for (Object value : values) {
	System.out.println(value);
}
  • 遍历所有的key-value
  • entrySet()
//entrySet()
        Set entrySet = hashMap.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()){
            Object obj = iterator1.next();
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey()+"----->"+entry.getValue());
        }
  • 遍历key和value本质都是获取entrySet再获取key和value,所以其顺序是对应的
  • JDK7
    • new HashMap()
      • 底层创建了长度为16的一维Entry[ ] table
    • map.put(key1,value1)
      • 首先,调用key1所在类的hashcode() 计算key1的哈希值,以此得到在Entry数组中的位置。如果位置为空,则添加成功。如果不为空(此位置上有一个或者多个数据(链表)),则比较两者的哈希值:
        • 如果key1的哈希值与已经存在的数据的哈希值不同,则key1-value1添加成功------情况2
        • 如果key1的哈希值与已经存在的某一个数据(key2-value2)的哈希值相同,则继续比较:调用key1所在类的euqals(key2)
          • 如果equals()返回false:此时key1-value1添加成功------情况3
          • 如果equals()返回true:使用value1覆盖value2
        • 情况2和情况3时key1-value1和原来的数据以链表的形式存储
        • 在添加的过程中,默认扩容为原来的2倍,并将原有的数据复制过来
  • JDK8
    • new HashMap():底层没有创建长度为16的数组
    • JDK8底层的数组是Node[ ],而非Entry[ ]
    • 首次调用put()方法时,底层创建长度为16的数组
    • JDK7底层只有:数组+链表。JDK8底层结构:数组+链表+红黑树。
    • 当数组的某一个索引位置上的元素以链表的形式存在的数据个数 > 8,且当前数组的长度 > 64时,此索引位置上的所以数据改为使用红黑树存储(二叉树能提高查找效率)
  • 负载因子:
DEFAULT_LOAD_FACTOR = 0.75f;

threshold = loadFactor * 容量,当已存入的数据个数>threshold时扩容

1.3.2 ConcurrentHashMap

1.3.3 LinkedHashMap

  • 在HashMap的基础上添加了前后指针,能够按照添加的顺序遍历
  • 对于频繁的遍历操作,执行效率高于HashMap
static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;//双向链表
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

1.3.4 TreeMap

  • 保证按照添加的key-value对进行排序,实现排序遍历
  • 底层使用红黑树
  • 自然排序
  • 定制排序

1.3.5 Hashtable

  • 古老的实现类
  • 线程安全,效率低
  • 不能存储null的key和value

1.3.6 Properties

  • Hashtable的子类,常用于处理配置文件,key、value都是String
  • 常配合文件流读取配置文件

1.3.7 Collections工具类

  • Collections是操作Collection、Map的工具类
  • Reverse(List):逆序排序
  • Shuffle(List):打乱顺序
  • Sort(List):排序
  • Swap(List,int,int):交换
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值