​大家好!我是未来村村长,就是那个“请你跟我这样做,我就跟你这样做!”的村长????‍????!​

||Data Structure||

未来村村长正推出一系列【Data Structure】文章,将从解读数据结构的角度上分析Java集合的源码。因为上的大多数描述java集合的文章,关注点在于其源码和方法,很少从对数据结构的讲解为切入点进行分析。以此为契机,未来村村长希望能从数据结构开始讲起,分析java集合是如何使用和如何实现的。

一、集合框架

1、集合总览

java集合图解源码系列【1】:总览篇_迭代器

注:此图不全,实现关系不一定为上下级。

2、源码从接口读起

我们在此只看Collection和Map接口源码,目的是为了了解java集合规定了哪些基本方法,在此我们只需要简单知道有哪些方法即可。

(1)Collection

  • boolean add(E e):向集合添加元素e,若指定集合元素改变了则返回true
  • boolean addAll(Collection<? extends E> c):把集合C中的元素全部添加到集合中,若指定集合元素改变返回true
  • void clear():清空所有集合元素
  • boolean contains(Object o):判断指定集合是否包含对象o
  • boolean containsAll(Collection<?> c):判断指定集合是否包含集合c的所有元素
  • boolean isEmpty():判断指定集合的元素size是否为0
  • boolean remove(Object o):删除集合中的元素对象o,若集合有多个o元素,则只会删除第一个元素
  • boolean removeAll(Collection<?> c):删除指定集合包含集合c的元素
  • boolean retainAll(Collection<?> c):从指定集合中保留包含集合c的元素,其他元素则删除
  • int size():集合的元素个数
  • T[] toArray(T[] a):将集合转换为T类型的数组
package java.util;

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


public interface Collection<E> extends Iterable<E> {

int size();

boolean isEmpty();

boolean contains(Object o);

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;
}

boolean retainAll(Collection<?> c);

void clear();

boolean equals(Object o);


int hashCode();

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


default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}


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

(2)Map

Map中的常用方法:

  • void clear():删除该Map对象中所有键值对;
  • boolean containsKey(Object key):查询Map中是否包含指定的key值;
  • boolean containsValue(Object value):查询Map中是否包含一个或多个value;
  • Set entrySet():返回map中包含的键值对所组成的Set集合,每个集合都是Map.Entry对象。
  • Object get():返回指定key对应的value,如果不包含key则返回null;
  • boolean isEmpty():查询该Map是否为空;
  • Set keySet():返回Map中所有key组成的集合;
  • Collection values():返回该Map里所有value组成的Collection。
  • Object put(Object key,Object value):添加一个键值对,如果集合中的key重复,则覆盖原来的键值对;
  • void putAll(Map m):将Map中的键值对复制到本Map中;
  • Object remove(Object key):删除指定的key对应的键值对,并返回被删除键值对的value,如果不存在,则返回null;
  • boolean remove(Object key,Object value):删除指定键值对,删除成功返回true;
  • int size():返回该Map里的键值对个数;

内部类Entry,Map中包括一个内部类Entry,该类封装一个键值对,常用方法:

  • Object getKey():返回该Entry里包含的key值;
  • Object getvalue():返回该Entry里包含的value值;
  • Object setValue(V value):设置该Entry里包含的value值,并设置新的value值。
package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;


public interface Map<K,V> {

int size();

boolean isEmpty();

boolean containsKey(Object key);

boolean containsValue(Object value);

V get(Object key);

V put(K key, V value);

V remove(Object key);

void putAll(Map<? extends K, ? extends V> m);

void clear();

Set<K> keySet();

Collection<V> values();

Set<Map.Entry<K, V>> entrySet();

interface Entry<K,V> {

K getKey();

V getValue();

V setValue(V value);

boolean equals(Object o);

int hashCode();

public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}

public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}


public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}


public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
}


boolean equals(Object o);

int hashCode();


default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}

default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}


default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}

// ise thrown from function is not a cme.
v = function.apply(k, v);

try {
entry.setValue(v);
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
}
}

default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}

return v;
}

default boolean remove(Object key, Object value) {
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
remove(key);
return true;
}


default boolean replace(K key, V oldValue, V newValue) {
Object curValue = get(key);
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
put(key, newValue);
return true;
}

default V replace(K key, V value) {
V curValue;
if (((curValue = get(key)) != null) || containsKey(key)) {
curValue = put(key, value);
}
return curValue;
}

default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}

return v;
}

default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
if ((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
remove(key);
return null;
}
} else {
return null;
}
}

default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);

V newValue = remappingFunction.apply(key, oldValue);
if (newValue == null) {
// delete mapping
if (oldValue != null || containsKey(key)) {
// something to remove
remove(key);
return null;
} else {
// nothing to do. Leave things as they were.
return null;
}
} else {
// add or replace old mapping
put(key, newValue);
return newValue;
}
}

default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if(newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
}

看完源码,发现连接口都不简单,众所周知,java的接口只能定义静态且不可变的常量或者公共抽象方法,不可能定义非抽象的具体方法。但自从jdk1.8横空出世以后,它就被default关键字赋予了另一项很酷的能力——在接口中定义非抽象方法。我们可以通过下面这个例子,看其使用方式。

interface Interface404{
default int doSth(){
return 404;
}
}
public class IfaceTestNotFound implements Interface404{
public static void main(String[] args) {
new IfaceTestNotFound().do();
}
void do(){
System.out.println(Interface404.super.doSth());
}
}

二、迭代器

在Collection的代码中,我们可以看见Collection接口实现了Iterable接口,实现了该接口的类是可以通过迭代器进行遍历的,Java 中的 Collection 继承了 Iterable,List 和 Set 有继承了 Collection,所以 List 和 Set 中元素的遍历都是可以通过迭代器模式来实现。

1、迭代器的使用

在探究迭代器的实现以前,我们先来看看迭代器应该如何使用,以下这段代码来自菜鸟教程。

下面展示了遍历List的三种方式,一是通过For-Each方法,直接取出List中的元素。二是通过将ArrayList使用toArray换为数组,通过for循环遍历。

import java.util.*;

public class Test{
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("HAHAHAHA");

//第一种遍历方法使用 For-Each 遍历 List
for (String str : list) { //也可以改写 for(int i=0;i<list.size();i++) 这种形式
System.out.println(str);
}

//第二种遍历,把链表变为数组相关的内容进行遍历
String[] strArray=new String[list.size()];
list.toArray(strArray);

for(int i=0;i<strArray.length;i++) //这里也可以改写为 for(String str:strArray) 这种形式
{
System.out.println(strArray[i]);
}

//第三种遍历 使用迭代器进行相关遍历

Iterator<String> ite=list.iterator();
while(ite.hasNext())//判断下一个元素之后有值
{
System.out.println(ite.next());
}
}
}

我们重点看第三种,通过list.iterator()创建了属于该list的迭代器,然后通过while循环,不断输出iterator的next元素。当然也可以用for循环结合list.size进行迭代器的使用。这有点像Scanner的hasnext()和nextInt()方法,不断的输入然后取到数据。

2、迭代器的实现

我们来看看Iterator的源码,探究迭代器的实现。

  • 方法iterator()将返回一个Iterator。首次调用next()方法时,它将返回第一个元素
  • next() 返回下一个元素
  • hasNext() 检查集合中是否还有元素
  • remove() 将迭代器新返回的元素删除
  • forEachRemaining() 对每个剩余的元素执行指定的操作
package java.util;

import java.util.function.Consumer;

public interface Iterator<E> {

boolean hasNext();

E next();

default void remove() {
throw new UnsupportedOperationException("remove");
}

default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}

我们从较为简单的ArrayList的iterator去探究iterator的实现。在此要强调,java集合实现Iterable接口,所以拥有迭代器功能,但是每个集合对应的迭代器写法不同。源码较难理解,我们重点关注其hasnext()和next()就行。

public Iterator<E> iterator() {return new Itr();}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;

Itr() {}

public boolean hasNext() {
return cursor != size;
}

@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
}

我们可以看见next()最关键的两行代码

cursor = i + 1;
return (E) elementData[lastRet = i];

我们可以看见对源码对cursor的描述为index of next element to return(要返回的下一个元素的索引)。对lastRet的描述为返回的最后一个元素的索引,如果没有的话为-1(index of last element returned; -1 if no such)。每次返回数组元素后,将cursor指向下一个元素。这里要注意的是,cursor默认初始值为0,则返回的第一个元素为elementData[0],而不是从最后一个开始返回。之后会根据必要陆续推出其他集合类型的迭代器源码分析。