list set map集合的区别

三者可分为两大类别,list和set同时集合,而map是key-value集合,list中元素可重复,set集合中元素不可重复。list的实现有ArrayList,LinkedList;map的实现有HashMap,HashTable,ConcurrentedHashMap;set的实现是依据Map key的不可重复进行实现的,其在实现过程中value值存储的是空的Object对象,具体实现有HashSet,TreeSet。

List: ArrayList和LinkedList的主要实现方式为数组和双向链表。

Map: HashMap的实现方式是数组加链表,在判断插入map中时,首先会依据数组的长度进行取余,然后插入数组中,在java8中,数组的长度大于8后会转变为红黑树,HashMap key和value都可以为null。Map的另外一个实现HashTable,key和value都不可以为null。两者的主要区别是HashTable采用了synchronized进行同步,而HashMap未使用锁进行同步,HashMap的线程安全实现版本是ConcurrentHashMap,其内部使用了分段式锁。Map的实现还有TreeMap类。

Set: set的具体实现有HashSet和TreeSet,HashSet是利用HashMap key的不可重复特性进行实现的,TreeSet是利用TreeMap实现的。

1.list集合

list接口定义,继承了Collection,Collection接口继承了Iterable接口

public interface List<E> extends Collection<E>;
interface Collection<E> extends Iterable<E>;

Iterable接口的作用是能够使用foreach语句对集合进行遍历

/**
 * Implementing this interface allows an object to be the target of
 * the "for-each loop" statement. See
 * <strong>
 */
public interface Iterable<T> {
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

collection接口定义了集合的常用方法

package java.util;

import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * collection的继承有如下,主要分为list,set,map三大类
 * @see     Set
 * @see     List
 * @see     Map
 * @see     SortedSet
 * @see     SortedMap
 * @see     HashSet
 * @see     TreeSet
 * @see     ArrayList
 * @see     LinkedList
 * @see     Vector
 * @see     Collections
 * @see     Arrays
 * @see     AbstractCollection
 * @since 1.2
 */

public interface Collection<E> extends Iterable<E> {
    
    int size(); //集合大小

    boolean isEmpty(); //集合是否为空

    boolean contains(Object o); //是否包含object

    Iterator<E> iterator(); //返回迭代器
    
    Object[] toArray(); //转换成数组

    <T> T[] toArray(T[] a); //转换成数组

    boolean add(E e); //添加元素

    boolean remove(Object o); //移除元素
  
    boolean containsAll(Collection<?> c); //是否包含集合

    boolean addAll(Collection<? extends E> c); //添加集合

    boolean removeAll(Collection<?> c); //移除集合

    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    } //通过predicate来判断是否移除元素

    boolean retainAll(Collection<?> c); //移除所有集合

    void clear(); //清除所有元素

    boolean equals(Object o); //判断对象是否相等

    int hashCode(); //返回hashCode

    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }

    
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    } //返回Stream流对象

    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }//并行流
}

AbstractCollection实现了List的部分接口方法

public boolean isEmpty() {  
    return size() == 0;  
}

public boolean contains(Object o) {  
    Iterator<E> it = iterator();  //获取到迭代器
    if (o==null) {  //如果o为null的话就不能使用o.equals(it.next())
        while (it.hasNext())  
            if (it.next()==null)  
                return true;  
    } else {  
        while (it.hasNext())  
            if (o.equals(it.next()))  
                return true;  
    }  
    return false;  
}


public Object[] toArray() {  
  Object[] r = new Object[size()];   //new Object[]
    Iterator<E> it = iterator();  
    for (int i = 0; i < r.length; i++) {  
        if (! it.hasNext())  
  return Arrays.copyOf(r, i);  //如果it的真实大小小于r.length的话,就不返回上面new的数组,而是返回部分数组对象
        r[i] = it.next();  
    }  
    return it.hasNext() ? finishToArray(r, it) : r;  
}


public boolean remove(Object o) { //删除方法同contains
    Iterator<E> it = iterator();
    if (o==null) {
        while (it.hasNext()) {
            if (it.next()==null) {
                it.remove();
                return true;
            }
        }
    } else {
        while (it.hasNext()) {
            if (o.equals(it.next())) {
                it.remove();
                return true;
            }
        }
    }
    return false;
}


public void clear() { //清空所有元素
    Iterator<E> it = iterator();
    while (it.hasNext()) {
        it.next();
        it.remove();
    }
}


public String toString() {  //集合转换成字符串
    Iterator<E> it = iterator();
    if (! it.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder(); //使用的是StringBuilder
    sb.append('[');
    for (;;) {
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}
。。。

ArrayList实现源码分析

ArrayList类中的属性
private static final int DEFAULT_CAPACITY = 10; //默认初始数组大小
private static final <b>Object[]</b> EMPTY_ELEMENTDATA = {}; //ArrayList存储元素采用数组,这也是其与LinkedList的主要区别
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空ArrayList
<b>transient</b> Object[] elementData; // non-private to simplify nested class access
private int size;

public ArrayList(int initialCapacity) { //初始化
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}


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);//对原来的数组进行拷贝,新数组的大小为新生成的值
}

public boolean add(E e) {  //添加元素,首先确保能够添加元素
    ensureCapacityInternal(size + 1);  // Increments modCount!!  
  elementData[size++] = e;  
    return true;  
}


public E remove(int index) { //删除元素
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved); //将index后的元素向前移一位
    elementData[--size] = null; // clear to let GC do its work

    return oldValue; 
}
。。。

LinkedList源码分析

LinkedList的实现是基于双向链表实现的,其数据元素是采用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;
    }
}

transient int size = 0; //list集合大小
transient Node<E> first; //头结点
transient Node<E> last; //尾结点


private void linkFirst(E e) {//将e节点作为一个头结点
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

void linkLast(E e) { //将e节点作为一个尾结点
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

。。。

ArrayList和LinkedList的主要区别及使用场景:
两者本质上的区别是实现数据结构不同,ArrayList使用的是数组,LinkedList使用的双向链表,两者的主要区别也是数组和链表的区别。两者具体的使用场景更适合依据场景具体分析,当场景条件不同时候,可结合数组和链表的特点具体分析。

2.map集合

HashMap的实现源码

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //初始容量大小2^4 16

static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量 2^30

static final float DEFAULT_LOAD_FACTOR = 0.75f; //负载因子

static final int TREEIFY_THRESHOLD = 8; //数组转红黑树阈值

static final int UNTREEIFY_THRESHOLD = 6; //取消红黑树阈值

static final int MIN_TREEIFY_CAPACITY = 64; //数组转红黑树数组最小值

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;

    Node(int hash, K key, V value, Node<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }

    public final K getKey()        { return key; }
    public final V getValue()      { return value; }
    public final String toString() { return key + "=" + value; }

    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }

    public final V setValue(V newValue) {
        V oldValue = value;
        value = newValue;
        return oldValue;
    }

    public final boolean equals(Object o) {
        if (o == this)
            return true;
        if (o instanceof Map.Entry) {
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            if (Objects.equals(key, e.getKey()) &&
                Objects.equals(value, e.getValue()))
                return true;
        }
        return false;
    }
}

3. list set map集合的常用方法


list: add() //添加元素
      get() //删除元素
      remove() //移除元素
      contains() //是否包含某个元素
      clear() //清空list
      isEmpty() //是否为空
      subList() //子列表
      lastIndexOf() //最后一个元素
      
 map: put() //插入值
       get() //依据key获取value
       containsKey() //查看是否包含该key
       containsValue() //查看是否包含value
       isEmpty() //查看是否为空
       remove() //删除key
 
 set:  add() //添加
       remove() //删除
       contains() //包含
       isEmpty() //是否为空
       clear() //清空set

你若安好便是晴天
82 声望10 粉丝