Java 集合深入理解(5):AbstractCollection
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~
今天好累,来学学 AbstractCollection 吧!
什么是 AbstractCollection
AbstractCollection 是 Java 集合框架中 Collection 接口 的一个直接实现类, Collection 下的大多数子类都继承 AbstractCollection ,比如 List 的实现类, Set的实现类。
它实现了一些方法,也定义了几个抽象方法留给子类实现,因此它是一个抽象类。
抽象方法
public abstract Iterator<E> iterator();public abstract int size();
子类必须以自己的方式实现这两个方法。除此外,AbstractCollection 中默认不支持添加单个元素,如果直接调用 add(E) 方法,会报错:
public boolean add(E object) {
throw new UnsupportedOperationException();
}
因此,如果子类是可添加的数据结构,需要自己实现 add(E) 方法。
实现的方法
1.addAll() 添加一个集合内的全部元素:
public boolean addAll(Collection<? extends E> collection) {
boolean result = false;
//获取待添加对象的迭代器
Iterator<? extends E> it = collection.iterator();
while (it.hasNext()) {
//挨个遍历,调用 add() 方法添加,因此如果没有实现 add(E) 方法,addAll() 也不能用
if (add(it.next())) {
result = true;
}
}
return result;
}
2.clear() 删除所有元素:
public void clear() {
//获取子类实现的迭代器,挨个遍历,删除
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
//单线程使用迭代器的 remove() 方法不会导致 fail-fast
it.remove();
}
}
3.contains() 是否包含某个元素:
public boolean contains(Object object) {
//获取子类实现的迭代器,挨个遍历,比较
Iterator<E> it = iterator();
if (object != null) {
while (it.hasNext()) {
//这个元素的类 需要重写 equals() 方法,不然结果够呛
if (object.equals(it.next())) {
return true;
}
}
} else {
//目标元素是空也能查找,说明 AbstractCollection 默认是支持元素为 null 的
while (it.hasNext()) {
if (it.next() == null) {
return true;
}
}
}
return false;
}
4.containsAll() 是否包含指定集合中的全部元素:
public boolean containsAll(Collection<?> collection) {
Iterator<?> it = collection.iterator();
//挨个遍历指定集合
while (it.hasNext()) {
//contails 里也是遍历,双重循环,O(n^2)
if (!contains(it.next())) {
return false;
}
}
return true;
}
5.isEmpty() 是否为空:
public boolean isEmpty() {
//调用子类实现的 size() 方法
return size() == 0;
}
6.remove() 删除某个元素:
public boolean remove(Object object) {
//获取子类实现的 迭代器
Iterator<?> it = iterator();
if (object != null) {
while (it.hasNext()) {
if (object.equals(it.next())) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (it.next() == null) {
it.remove();
return true;
}
}
}
return false;
}
受不了了,又是 if-else,直接写成这样看着不是更舒服吗:
public boolean remove(Object object) {
Iterator<?> it = iterator();
while (it.hasNext()) {
if (object != null ? object.equals(it.next()) : it.next() == null) {
it.remove();
return true;
}
}
return false;
}
7.removeAll() 删除指定集合中包含在本集合的元素:
public boolean removeAll(Collection<?> collection) {
boolean result = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
//双重循环
if (collection.contains(it.next())) {
it.remove();
result = true;
}
}
return result;
}
8.retainAll() 保留共有的,删除指定集合中不共有的:
public boolean retainAll(Collection<?> collection) {
boolean result = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
//排除异己,不在我集合中的统统 886
if (!collection.contains(it.next())) {
it.remove();
result = true;
}
}
return result;
}
9.toArray(), toArray(T[] contents) 转换成数组:
public Object[] toArray() {
//把集合转换成 ArrayList,然后再调用 ArrayList.toArray()
return toArrayList().toArray();
}
public <T> T[] toArray(T[] contents) {
return toArrayList().toArray(contents);
}
@SuppressWarnings("unchecked")
private ArrayList<Object> toArrayList() {
ArrayList<Object> result = new ArrayList<Object>(size());
for (E entry : this) {
result.add(entry);
}
return result;
}
ArrayList, 集合与数组的桥梁。
10.toString() 把内容转换成一个 String 进行展示:
public String toString() {
if (isEmpty()) {
return "[]";
}
//注意默认容量是 size() 的 16 倍,为什么是 16 呢?
StringBuilder buffer = new StringBuilder(size() * 16);
buffer.append('[');
//仍旧用到了迭代器
Iterator<?> it = iterator();
while (it.hasNext()) {
Object next = it.next();
if (next != this) {
//这个 Object 也得重写 toString() 方法,不然不能输出内容
buffer.append(next);
} else {
buffer.append("(this Collection)");
}
if (it.hasNext()) {
buffer.append(", ");
}
}
buffer.append(']');
return buffer.toString();
}
我们之所以可以使用 System.out.print() 直接输出集合的全部内容,而不用挨个遍历输出,全都是 AbstractCollection 的功劳!
List list = new LinkedList();
System.out.println(list);
其他
1.AbstractCollection 默认的构造函数是 protected:
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected AbstractCollection() {
}
因此,官方推荐子类自己创建一个 无参构造函数:
The programmer should generally provide a void (no argument) and Collection constructor, as per the recommendation in the Collection interface specification.
2.AbstractCollection 的 add(E) 方法默认是抛出异常,这样会不会容易导致问题?为什么不定义为抽象方法?
答案译自 stackoverflow :
- 如果你想修改一个不可变的集合时,抛出
UnsupportedOperationException是标准的行为,比如 当你用 Collections.unmodifiableXXX() 方法对某个集合进行处理后,再调用这个集合的 修改方法(add,remove,set…),都会报这个错; - 因此
AbstractCollection.add(E)抛出这个错误是准从标准;
那为什么会有这个标准呢?
在 Java 集合总,很多方法都提供了有用的默认行为,比如:
- Iterator.remove()
- AbstractList.add(int, E)
- AbstractList.set(int, E)
- AbstractList.remove(int)
- AbstractMap.put(K, V)
- AbstractMap.SimpleImmutableEntry.setValue(V)
而之所以没有定义为 抽象方法,是因为可能有很多地方用不到这个方法,用不到还必须实现,这岂不是让人很困惑么。
个人觉得原因跟和设计模式中的 接口隔离原则 有些相似:
不要给客户端暴露不需要的方法。
Java 集合深入理解(5):AbstractCollection的更多相关文章
- Java 集合深入理解(8):AbstractSequentialList
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天有点无聊,来学学 AbstractSequentialList 解解闷 吧! AbstractSequentialLi ...
- Java 集合深入理解(7):ArrayList
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情有点美丽,学学 ArrayList 放松下吧! 什么是 ArrayList ArrayList 是 Java 集合 ...
- Java 集合深入理解(4):List<E> 接口
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 蓝瘦!香菇! 连着加班几天,醉了.学学 List 放松下! 在 Java 集合深入理解:Collection 中我们熟悉了 ...
- Java 集合深入理解(15):AbstractMap
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天来了解下 AbstractMap. 什么是 AbstractMap AbstractMap 是 Map 接口的的实现类 ...
- Java 集合深入理解(12):古老的 Vector
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天刮台风,躲屋里看看 Vector ! 都说 Vector 是线程安全的 ArrayList,今天来根据源码看看是不是这 ...
- Java 集合深入理解(6):AbstractList
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情比天蓝,来学学 AbstractList 吧! 什么是 AbstractList AbstractList 继承自 ...
- Java 集合深入理解(14):Map 概述
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 终于把 List 常用的几种容器介绍完了,接下来开始 Map 的相关介绍. 什么是 Map Java 中的 Map 接口 ...
- Java 集合深入理解(13):Stack 栈
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情不错,再来一篇 Stack ! 数据结构中的 栈 数据结构中,栈是一种线性数据结构,遵从 LIFO(后进先出)的操 ...
- Java 集合深入理解(11):LinkedList
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情鱼肚白,来学学 LinkedList 吧! 日常开发中,保存一组数据使用的最多的就是 ArrayList, 其次就 ...
随机推荐
- Oracle函数大全之转换函数
chartorowid(c1) [功能]转换varchar2类型为rowid值 [参数]c1,字符串,长度为18的字符串,字符串必须符合rowid格式 [返回]返回rowid值 [示例] SELECT ...
- 第四章 CSS基础
1.CSS是cascading style sheets 层叠样式表.样式定义如何显示html元素,通常存储在样式表中,将样式添加到html中,是为了解决内容与表现分离的问题. 2.外部样式表可以极大 ...
- ASP.NET访问Access的连接字符串配置
由于Access是文件数据库,所以在ASP.NET需要能映射访问到Access文件: 方式一:appSettings中设置连接字符串 web.config的配置 <appSettings> ...
- 1800: [Ahoi2009]fly 飞行棋
#include<cstdio> #include<iostream> using namespace std; ],n,ans; int main() { scanf(&qu ...
- 一模 (3) day2
第一题: 题目大意:和day1一样,给出m个小于n的数,求出出现次数大于m div 2 的数. 数据范围加大,1<=n<=2^31 1<=m<=3000000 解题过程: ...
- 文件浏览器及数码相框 -2.3.2-freetype_arm-1
交叉编译:tar xjf freetype-2.4.10.tar.bz2 ./configure --host=arm-linuxmakemake DESTDIR=$PWD/tmp install f ...
- Linux 常用命令杂记
移动光标:h:向左移动j:向下移动k:向上移动l:向上移动 与window 光标移动键功能一致. 常用命令行:shift + ^ 行首shift + $ 行尾ctrl + v 可视模式 , 选择一个范 ...
- KStar ----BPM应用框架,K2 的新星
“KStar”是基于K2 BPM搭建的应用框架产品,将K2最佳实践方案以产品的形式呈现给用户,该框架面向SOA服务,便于二次开发和扩展,流程设计.用户组织.业务表单.流程管理.系统集成等开发工作,都按 ...
- C语言与MATLAB接口 编程与实例 李传军编着
罗列一下以前自己学习C语言与MATLAB混编的笔记,顺便复习一遍. <C语言与MATLAB接口 编程与实例 李传军编着>(未看完,目前看到P106) 目录P4-8 ************ ...
- [VMware WorkStation]虚拟机网络
桥接模式下复制物理网络连接: 复制物理网卡连接状态,就是说把你指定的.本机的.真是网卡的状态信息复制给虚拟机的虚拟网卡,比如说你的本机真是网卡链接到了家用路由器的LAN口上,获得到了DHCP分配的地址 ...