Java集合为什么设计为:实现类继承了抽象类,同时实现抽象类实现的接口
更好阅读体验:Java集合为什么设计为:实现类继承了抽象类,同时实现抽象类实现的接口
问题
Java集合源码为什么设计为:「实现类继承了抽象类,同时实现抽象类实现的接口?」
看着List 集合的UML图来分析
如图:接口+抽象类都是成对出现,Collection 和 AbstractCollection;List 和 AbstractList。ArrayList 继承了AbstractList,同时实现了List 接口。
再看下其他集合的UML 图,看看是不是也是这样设计的
这样设计的意义
有的人说接口只能使用抽象方法,为了实现公共的方法抽出来用抽象类来实现,提高代码复用性,提高代码质量。
其实不是,第一句就错了,接口同样是可以实现方法,用的关键字是 default。如果真的是为了公共的实现方法抽出来用抽象类来实现,那还不如直接在接口上实现不更好,而且具体的实现类(如:ArrayList)还不用继承抽象类,毕竟继承还是单一的。
List 接口继承了Collection 接口绝大部分方法,并新定义了List 特有的抽象方法,而这些特有的抽象方法都交给了AbstractList 来实现。
抽两个方法来看看
// AbstractList
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
在AbstractList中,这两个方法只是抛了个“不支持的操作异常”,并没有具体的内容。要明白抽象类是多种类的再一次抽象,也就是说具体的实现方法还是要针对不同的类来编写,所以还要看看ArrayList 和 LinkedList 对add(int index, E element)的具体实现
// ArrayList
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element;
size++;
}
// LinkedList
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
可见,这两个方法的实现完全不同(底层数据结构不同),到此应该明白一点了:「List 接口定义个List 特有的规范,AbstractList 对这个规范做了通用实现,而具体实现还是要在具体类里面落实」。但并不是只是为了高复用性、减少代码重复度。
比如:public int indexOf(Object o); 虽然抽象类实现了,但具体类还是重写了这方法,显然不是为了解决代码复用的问题,而是提供了通用实现,具体的还有看具体类使用了什么类型的数据结构,然后在具体类中重写方法定制化的实现。
// AbstractList
public int indexOf(Object o) {
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
// ArrayList
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
// LinkedList
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
意义
1.接口实现的解耦:接口新增或删除方法时,只需在抽象类中做个方法初始实现(对于删除方法可以不做处理),即可避免一个接口变动导致所有实现类都需要更新代码的问题。
2.多态特性的运用,向上转型:ArrayList 、Vector、LinkedList 都可以实现对数据的存储,都可以用List 作为引用(面向接口编程)。
「总结」
提高接口的灵活性:接口只需要按需重写方法;
提高接口的易扩展:接口变动不影响实现类,只需要更改相应的抽象类实现即可;
抽象类和接口的互补:接口规定行为规范,抽象类补充属性和接口实现的解耦。
个人理解,如有不对,还望纠正。

Java集合为什么设计为:实现类继承了抽象类,同时实现抽象类实现的接口的更多相关文章
- Java 集合系列之六:工具类Collections和Arrays基本操作
1. Collections Collections类主要是完成了两个主要功能 提供了若干简单而又有用的算法,比如排序,二分查找,求最大最小值等等. 提供对集合进行包装的静态方法.比如把指定的集合包装 ...
- Android(java)学习笔记118:类继承的注意事项
/* 继承的注意事项: A:子类只能继承父类所有非私有的成员(成员方法和成员变量) B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法. C:不要为了部分功能而去 ...
- Android(java)学习笔记59:类继承的 注意事项
1. 类继承的注意事项: /* 继承的注意事项: A:子类只能继承父类所有非私有的成员(成员方法和成员变量) B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法. ...
- Java集合框架:Collections工具类
java.util.Collections工具类提供非常多实用的方法.使得程序员操作集合类的时候更加的方便easy,这些方法都是静态的. 整个Collections工具类源代码几乎相同有4000行.我 ...
- java 集合(一)ArrayList的继承树
这是ArrayList的继承树,它继承了AbstractCollection抽象类,AbstractCollection类实现了Collection接口,Collection接口继承Iterable接 ...
- Java集合框架:Arrays工具类
java.util.Arrays类能方便地操作数组,它提供的方法都是静态的.整个Arrays工具类的实现有3000+行.可是归纳总结一下可知它有下面功能(9个): 1. asList 定义: @Saf ...
- Java集合(3):使用Abstract类
每个java.util容器都有其自己的Abstract类,它们提供了该容器接口的部分实现.下面是一个定制自己的Map的例子(List set就省略了): 定制自己的Map实现AbstractMap-- ...
- Java集合(1):Collections工具类中的static方法
与Arrays一样,Collections类中也有一些实用的static方法. (1) 排序操作 reverse(List list):反转指定List集合中元素的顺序 shuffle(List li ...
- 某类继承thread,同时实现runnable
package com.giserve.test; public class ThreadTest { public static void main(String[] args) { new Thr ...
随机推荐
- CURD系统怎么做出技术含量惊艳面试官
在<CURD系统怎么做出技术含量--怎样引导面试>有朋友开玩笑说都用上了领域驱动了,就不叫CURD系统了吧.这里我解释一下,怕大家对DDD领域驱动设计有什么误解. DDD是为解决软件复杂性 ...
- Python multiprocessing 基础使用和小trick
最近进行数据预处理时(噪声插入),单进程严重影响实验周期,故学习了multiprocessing并发执行不同数据集的处理,加快执行效率.现于此进行一些简单记录以供日后参考. 1. 基础: From m ...
- C++STL标准库学习笔记(三)multiset
C++STL标准库学习笔记(三)multiset STL中的平衡二叉树数据结构 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标 ...
- Mysql资料 mysqldump
目录 一.简介 备份过程 优缺点 命令使用 myisam引擎 二.安装 配置 日志 三.日常使用 备份全库 备份单个库(带建立库的语句) 备份单个库(不自动建立库) 备份表合集 从全备中恢复单个库 其 ...
- Java 在Word中嵌入多媒体(视频、音频)文件
Word中可将Office(Word/Excel/PowerPoint).PDF.txt等文件作为OLE对象插入到文档中,双击该对象可直接访问或编辑该文件,除了以上常见的文件格式对象,也可以插入多媒体 ...
- GIT最基本使用
带'*':必须操作 不带'*':可能需要而且经常用的 常见步骤为下: *1.克隆项目:有两种不同类型的网址(https/ssh) git clone [url] *2.初始化本地仓库 git init ...
- [BUUCTF]PWN——picoctf_2018_rop chain
picoctf_2018_rop chain 附件 步骤: 例行检查,32位,开启了NX保护 试运行一下程序,看到输入太长数据会崩溃 32位ida载入,习惯性的检索程序里的字符串,看见了flag.tx ...
- Docker从入门到精通(七)——容器数据共享
什么是容器数据共享?简单来说就是容器与容器之间数据共享,容器与宿主机数据共享. 1.为什么需要数据共享? ①.数据持久化 比如我们有一个MySQL集群,通过容器启动,那么项目运行过程中的数据是保存在容 ...
- CF1108A Two distinct points 题解
Content 有 \(q\) 次询问,每次询问给定四个数 \(l_1,r_1,l_2,r_2\).对于每次询问,找到两个数 \(a,b\),使得 \(l_1\leqslant a\leqslant ...
- java 图形化小工具Abstract Window Toolit ;布局管理器FlowLayout流式布局;BorderLayout边界布局;GridLayout网格布局;CardLayou重叠卡片布局;BoxLayout方框布局;绝对定位
1.FlowLayout流式布局管理器: FlowLayout布局管理器中,组件像水流一样向某方向流动(排列),遇到障碍(边界)就折回,重头开始排列 .在默认情况下,FlowLayout局管理器从左向 ...