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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。