Java集合类是一种非常实用的工具类,主要用于保存、盛装其它数据(集合里只能保存对象),因此集合类也被成为容器类。所有的集合类都位于java.util包下,在java.util.concurrent下还提供了一些支持多线程的集合类。Java的集合类主要由两个接口派生而来:Collection和Map,这两个是Java集合框架的根接口。
一、Collection接口
Collection派生出三个子接口,Set代表不可重复的无序集合、List代表可重复的有序集合、Queue是java提供的队列实现;Collection是最基本的集合接口,它提供了一些通用的方法,供子接口调用。
Collection源码分析如下:
// 位于java.util包下
package java.util;
import java.util.function.Predicate; // 函数式接口,广泛用在支持lambda表达式的API中
import java.util.stream.Stream; // 数据流接口,定义了众多Stream应该具有的行为
import java.util.stream.StreamSupport; //提供了底层的一些用于操作Stream的方法,如果不需要创建自己的Stream,一般不需要使用它。
// 继承于接口Iterable迭代器,即所有Collection集合体系中的集合类,都可以使用forEach进行循环遍历
public interface Collection<E> extends Iterable<E> {
// 1.查询类操作
int size(); // 返回元素个数
boolean isEmpty(); // 判断集合是否为空
boolean contains(Object o); // 判断是否包含元素 o
Iterator<E> iterator(); // 返回集合类的迭代器
Object[] toArray(); // 将集合转换为数组
<T> T[] toArray(T[] a); // 转换为具体某一类型的数组
// 2.修改类操作
boolean add(E e); // 往集合中添加元素 e
boolean remove(Object o); // 删除元素 o
// 3.批量操作
boolean containsAll(Collection<?> c); // 判断 c 是否包含在集合中
boolean addAll(Collection<? extends E> c); // 将 c 中所有元素添加到集合中
boolean removeAll(Collection<?> c); // 移除集合中所包含的 c 中的所有元素
boolean retainAll(Collection<?> c); //移除所有不包含在 c 中的所有元素,即只留下两个集合共有的元素
void clear(); // 清除集合中所有元素
// 删除满足 filter 条件的元素
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;
}
// 4.比较和散列
boolean equals(Object o); // 判断集合和对象 o 是否相等
int hashCode(); // 返回该集合的 hashcode 值
// 重写了 Iterable 接口的 Spliterator 方法
@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);
}
}
二、Map接口
Map实现类都用于保存具有映射关系的数据,它们保存的数据都是key-value对,如果要查找Map中的数据,总是根据key来获取,所以key是不可重复的,它用于标识集合里的每项数据。
Map源码分析如下:
// 位于java.util包下
package java.util;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable; // 通过实现该接口以启用其序列化功能
// Map 接口, K 为键, V 为值
public interface Map<K,V> {
// 1.查询操作
int size(); // 返回元素个数
boolean isEmpty(); // 判断是否为空
boolean containsKey(Object key); // 判断是否包含键 key
boolean containsValue(Object value); // 判断是否包含值 value
V get(Object key); //返回键 key 对应的值
// 2.修改操作
V put(K key, V value); // 添加元素, 元素为 (key,value)
V remove(Object key); // 移除键为 key 的元素
// 3.批量操作
void putAll(Map<? extends K, ? extends V> m); // 将 m 中所有元素添加到集合中
void clear(); // 清空集合
// 4.集合视图
Set<K> keySet(); // 返回 key 的集合视图
Collection<V> values(); // 返回 value 的集合视图
Set<Map.Entry<K, V>> entrySet(); //返回元素 Entry<K,V> 的集合视图
// 集合实体,Map的内部集合,对应Map中的一个元素
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());
}
}
// 5.比较和散列
boolean equals(Object o); // 判断集合和对象 o 是否相等
int hashCode(); // 返回该集合的 hashcode 值
// 6.JDK8出现的新方法 - default新特性
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;
}
}
三、defalut 扩展方法(JDK8新特性)
与以前的集合类相比,JDK8的新特性之一就是提供了很多 default 方法,这些方法拥有具体的实现,子类可以直接调用这些方法的默认实现。defalut方法对Java集合API进行了优化升级,并且在JDK与Lambda表达式的结合中起到了至关重要的作用。示例1:
A 接口中定义了一个 hello() 方法,B 类实现 A 接口,则 B 默认实现了 A 中的 hello() 方法
// A 接口中定义了一个用defalut修饰的 hello 方法
public interface A {
default void hello(){
System.out.println("调用 A 接口的 hello() ");
}
}
// B 类实现 A 接口
public class B implements A {}
public class defaultTest {
public static void main(String[] args) {
B b = new B();
b.hello(); // B 类调用了 A 接口中 hello() 方法的默认实现
}
}
示例2:
A 接口中定义了一个 defaul 修饰的 hello() 方法,B 接口中也有一个 defaul 修饰的 hello() 方法,defaulTest 同时实现 A、B 接口,则 defaultTest中必须重写 hello() 方法,否则报错
public interface A {
default void hello(){
System.out.println("调用 A 接口的 hello() ");
}
}
public interface B {
default void hello(){
System.out.println("调用 B 接口的 hello() ");
}
}
public class defaultTest implements A,B{
public void hello(){
System.out.println("调用 dafultTest 接口的 hello() "); // 调用自身hello方法
A.super.hello(); // A 接口的 hello 方法
B.super.hello(); // B 接口的 hello 方法
}
public static void main(String[] args) {
defaultTest test = new defaultTest();
test.hello();
}
}