Java 抽象容器类源码剖析

总体介绍

抽象容器类接口和具体容器类的关系如图所示,顶层包括Collection、List、Set、Queue、Deque和Map6个抽象容器类。

AbstractCollection:实现了Collection接口,被抽象类AbstractList、AbstractSet、AbstractQueue继承,ArrayDeque也继承自AbstractCollection。

AbstractList:父类是AbstractCollection,实现了List接口,被ArrayList、Abstract-SequentialList继承。

AbstractSequentialList:父类是AbstractList,被LinkedList继承。

AbstractMap:实现了Map接口,被TreeMap、HashMap、EnumMap继承。

AbstractSet:父类是AbstractCollection,实现了Set接口,被HashSet、 TreeSet和EnumSet继承。

AbstractQueue:父类是AbstractCollection,实现了Queue接口,被PriorityQueue继承。

本文分别介绍这些抽象类,包括它们提供的基础功能、如何实现、如何进行扩展等。

以AbstractCollection为例

AbstractCollection提供了Collection接口的基础实现,它实现了如下方法:

public boolean addAll(Collection<? extends E> c)
public boolean contains(Object o)
public boolean containsAll(Collection<?> c)
public boolean isEmpty()
public boolean remove(Object o)
public boolean removeAll(Collection<?> c)
public boolean retainAll(Collection<?> c)
public void clear()
public Object[] toArray()
public <T> T[] toArray(T[] a)
public String toString()

由于AbstractCollection不知道数据是怎么存储的,它依赖于如下更为基础的方法:

public boolean add(E e)
public abstract int size();
public abstract Iterator<E> iterator();

add方法的默认实现是:

public boolean add(E e) {
       throw new UnsupportedOperationException();
}

代码抛出“操作不支持”异常,如果子类集合是不可被修改的,这个默认实现就可以了,否则,必须重写add方法。addAll方法的实现就是循环调用add方法。
size方法是抽象方法,子类必须重写。isEmpty方法就是检查size方法的返回值是否为0。toArray方法依赖size方法的返回值分配数组大小。
iterator方法也是抽象方法,它返回一个实现了迭代器接口的对象,子类必须重写。迭代器
定义了三个方法:

boolean hasNext();
E next();
void remove();

如果子类集合是不可被修改的,选代器不用实现remove方法,否则,三个方法都必须实现。

除了接口中的方法,Collection接口文档建议,每个Collection接口的实现类都应该提供至少两个标准的构造方法,一个是默认构造方法,另一个接受一个Collection类型的参数。

具体如何通过继承AbstractCollection来实现自定义容器呢?下面通过一个简单的例子来说明。我们使用自己实现的动态数组容器类DynamicArray来实现一个简单的Collection。

public class DynamicArray<E> {
       //...
       public E remove(int index) {
           E oldValue = get(index);
           int numMoved = size - index - 1;
           if(numMoved > 0)
               System.arraycopy(elementData, index + 1, elementData, index,
                       numMoved);
           elementData[--size] = null;
           return oldValue;
       }
       public void add(int index, E element) {
           ensureCapacity(size + 1);
           System.arraycopy(elementData, index, elementData, index + 1,
                            size - index);
           elementData[index] = element;
           size++;
       }
}

基于DynamicArray,再实现一个简单的迭代器类DynamicArrayIterator

public class DynamicArrayIterator<E>  implements Iterator<E>{
       DynamicArray<E> darr;
       int cursor;
       int lastRet = -1;
       public DynamicArrayIterator(DynamicArray<E> darr){
           this.darr = darr;
        }
    @Override
    public boolean hasNext() {
     return cursor != darr.size();
    }
    @Override
    public E next() {
        int i = cursor;
        if(i >= darr.size())
            throw new NoSuchElementException();
        cursor = i + 1;
    lastRet = i;
        return darr.get(i);
    }
    @Override
    public void remove() {
    if(lastRet < 0)
        throw new IllegalStateException();
    darr.remove(lastRet);
    cursor = lastRet;
    lastRet = -1;
}

基于DynamicArray和DynamicArrayIterator,通过继承AbstractCollection,我们来实现一个简单的容器类MyCollection。MyCollection提供了两个构造方法,并重写了size、add和iterator方法,这些方法内部使用了DynamicArray和DynamicArrayIterator。

public class MyCollection<E> extends AbstractCollection<E> {
       DynamicArray<E> darr;
       public MyCollection(){
           darr = new DynamicArray<>();
       }
       public MyCollection(Collection<? extends E> c){
           this();
addAll(c); }
       @Override
       public Iterator<E> iterator() {
           return new DynamicArrayIterator<>(darr);
       }
       @Override
       public int size() {
           return darr.size();
       }
       @Override
       public boolean add(E e) {
           darr.add(e);
           return true;
       }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/392808.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue+SpringBoot打造电子元器件管理系统

目录 一、摘要1.1 项目简介1.2 项目录屏 二、研究内容三、界面展示3.1 登录&注册&主页3.2 元器件单位模块3.3 元器件仓库模块3.4 元器件供应商模块3.5 元器件品类模块3.6 元器件明细模块3.7 元器件类型模块3.8 元器件采购模块3.9 元器件领用模块3.10 系统基础模块 四、…

通过Linux终端搭建基于HTTP隧道的文件传输系统

嘿&#xff0c;Linux小侠们&#xff0c;准备好挑战一项酷炫的任务了吗&#xff1f;今天我们要一起通过Linux终端搭建一个基于HTTP隧道的文件传输系统&#xff0c;让我们的文件在网络的海洋中畅游无阻&#xff01; 在开始之前&#xff0c;让我们先来想象一下这个场景&#xff1…

数字化转型导师坚鹏:政府数字化思维创新之道

政府数字化思维创新之道 ——政府数字化转型必须具备的6大数字化思维 课程背景&#xff1a; 很多政府存在以下问题&#xff1a; 不知道数字化转型如何改变思维模式&#xff1f; 不清楚需要建立什么样的数字化思维&#xff1f; 不知道如何开展数字化思维创新工作&#…

c++开发基础之保障多线程编程中的原子操作InterlockedIncrement和InterlockedDecrement用法详解

一、介绍 在多线程编程中&#xff0c;确保对共享变量进行原子操作是至关重要的。当多个线程同时访问和修改同一共享资源时&#xff0c;如果没有合适的同步机制&#xff0c;可能会导致数据竞争、内存一致性问题&#xff0c;甚至造成程序崩溃。为了解决这个问题&#xff0c;C提供…

数据分析(一) 理解数据

1. 描述性统计&#xff08;summary&#xff09; 对于一个新数据集&#xff0c;首先通过观察来熟悉它&#xff0c;可以打印数据相关信息来大致观察数据的常规特点&#xff0c;比如数据规模&#xff08;行数列数&#xff09;、数据类型、类别数量&#xff08;变量数目、取值范围…

【STM32 物联网】基础AT指令与基础Wifi功能AT指令

文章目录 前言一、基础AT指令1.1 测试AT启动1.2 重启模块1.3 查看版本信息1.4 进入深度睡眠模式1.5 开关回显1.6 恢复出场设置1.7 UART配置设置临时设置&#xff0c;不保存到Flash设置串口保存到Flash 1.8 设置sleep模式查询当前sleep模式设置当前sleep模式 二、基础Wifi功能AT…

Mac录屏保存在哪?让你快速找到它们!

在日常生活和工作中&#xff0c;我们经常需要录制电脑屏幕&#xff0c;以便进行演示、教学或者保存重要信息。然而&#xff0c;对于许多苹果用户来说&#xff0c;他们可能并不清楚mac录屏文件在哪。在本文中&#xff0c;我们将详细介绍如何在mac上进行录屏&#xff0c;以及录屏…

网络原理(IP篇)

IP IPv4&#xff08;Internet Protocol&#xff09;数据报首部格式版本首部长度可变部分区分服务总长度标识、标志、片偏移生存时间协议首部检验和源IP地址和目的IP地址 NAT 机制&#xff08;**N**etwork **A**ddress **T**ranslator&#xff09;网络地址转换NAT将数据的转发由…

政安晨:【完全零基础】认知人工智能(二)【超级简单】的【机器学习神经网络】—— 底层算法

如果小伙伴第一次看到这篇文章&#xff0c;可以先浏览一下我这个系列的上一篇文章&#xff1a; 政安晨&#xff1a;【完全零基础】认知人工智能&#xff08;一&#xff09;【超级简单】的【机器学习神经网络】 —— 预测机https://blog.csdn.net/snowdenkeke/article/details/…

深度学习系列53:大模型微调概述

参考系列文章&#xff1a;https://zhuanlan.zhihu.com/p/635152813 github链接&#xff1a;https://github.com/liguodongiot/llm-action 1 训练范式 下面这种instructive learning&#xff0c;在模型参数达到80亿后&#xff0c;会发生质的提升&#xff1a; 类似的还有手写pr…

RK3568驱动指南|第一篇 驱动基础-第3章 helloworld 驱动实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

Vite 5.0 正式发布

11 月 16 日&#xff0c;Vite 5.0 正式发布&#xff0c;这是 Vite 道路上的又一个重要里程碑&#xff01;Vite 现在使用 Rollup 4&#xff0c;这已经代表了构建性能的大幅提升。此外&#xff0c;还有一些新的选项可以改善开发服务器性能。 Vite 4 发布于近一年前&#xff0c;它…

什么原因导致百度百科建立一直审核不通过?

百科词条对网络营销实在是太重要了&#xff0c;不管是个人还是企业想在网上开展业务&#xff0c;都必要建立百科词条。自己动手编辑百科词条&#xff0c;搞个几十次也审核不过的情况比比皆是。 为什么百度百科总是审核不通过&#xff1f;百度官方发表过声明表示百度百科词条是人…

骨传导耳机好用吗?如何挑选骨传导耳机?

骨传导耳机是一种非常创新的骨传导耳机&#xff0c;采用耳挂式佩戴&#xff0c;使用起来也非常舒适。 而且骨传导耳机最近几年还是比较火的&#xff0c;骨传导耳机的出现解决了传统入耳式耳机长时间佩戴不舒服、听力受损等问题。但随着骨传导耳机的品牌逐渐变多&#xff0c;很多…

Gin框架: 快速搭建起一个Web应用环境及处理不同类型的响应

Gin 框架简介 Gin是Golang应用最为广泛的框架之一Gin是轻量级http web框架&#xff0c;简易而高性能&#xff0c;专注于处理高并发场景 Gin框架环境搭建 基于已完成的Go环境, 参考 go mod 环境搭建 ↓ https://blog.csdn.net/Tyro_java/article/details/135297367 在初始化好…

【STM32 CubeMX】SPI HAL库编程

文章目录 前言一、CubeMX配置SPI Flash二、SPI HAL编程2.1 查询方式函数2.2 使用中断方式2.3 DMA方式 总结 前言 STM32 CubeMX 是一款由 STMicroelectronics 提供的图形化配置工具&#xff0c;用于生成 STM32 微控制器的初始化代码和项目框架。在 STM32 开发中&#xff0c;使用…

在Linux系统中设置HTTP隧道以实现网络穿透和端口转发

在数字化世界中&#xff0c;网络穿透和端口转发成为了许多开发者和系统管理员必备的技能。而在Linux系统中&#xff0c;通过设置HTTP隧道&#xff0c;我们可以轻松实现这一目标&#xff0c;让我们的服务即便在内网环境中也能被外部世界所访问。 那么&#xff0c;如何在Linux系…

idea 打不开项目 白屏

使用IDEA打开项目&#xff0c; 不知名原因崩溃了&#xff0c; 直接出现缩略图白屏。 解决过程&#xff1a; 尝试过重启IDEA&#xff0c;重启过电脑&#xff0c;重新引入相同项目&#xff08;使用不同路径&#xff0c;存在缓存记录&#xff0c;依然打不开&#xff09;&#xff…

磁盘删除的文件怎么恢复?4个简单方法(2024更新版)

“我有很多文件都保存在电脑磁盘里了&#xff0c;想问问电脑磁盘删除的文件有什么方法可以快速恢复吗&#xff1f;非常感谢大家&#xff01;” 在日常工作和生活中&#xff0c;我们经常会在磁盘中存储大量的文件。这些文件对我们来说或许都有特殊的意义。磁盘删除的文件怎么恢复…

C#,二进制数的按位旋转(Bits Rotate)算法与源代码

1 二进制数的按位旋转 二进制数的按位旋转&#xff08;翻转&#xff09;是编程中常见的按位运算方法。 二进制数的按位旋转分为左转、右转。 左转意味着数据变大&#xff0c;右转意味着数据变小&#xff08;有损&#xff09;。 2 源程序 using System; using System.Text; us…