Java_简单模拟实现ArrayList_学习ArrayList

news2025/3/14 4:20:55

文章目录

  • 一、 了解线性表和顺序表区别
    • 1.线性表
    • 2.顺序表
  • 二、模拟实现
    • 1.定义接口
    • 2.定义MyArrayList
    • 3.成员变量以及构造方法
    • 4.实现打印数组
    • 5.实现add方法
    • 6.实现查找某个数是否存在contains或者某个数的下标indexOf
    • 7.获取或更改pos位置的值 get和set
    • 8.获取数组大小 size
    • 9.删除某个值 remove
    • 10.清空 clear
  • 三、ArrayList源码如何做的
    • 1.成员变量
    • 2.构造方法
      • 1、有参数的构造
      • 2、无参数的构造
      • 3、数组构造
    • 4.add
    • 5.addAll
    • 6.remove
    • 7.subList
    • 8.迭代器 iterator


一、 了解线性表和顺序表区别

1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
在这里插入图片描述
在这里插入图片描述

2.顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

二、模拟实现

1.定义接口

package mylist;

public interface IList {

    // 新增元素,默认在数组最后新增
    public void add(int data);
    // 在 pos 位置新增元素
    public void add(int pos,int data);
    //判断是否包含某个元素
    public boolean contains(int toFind);
    //查找某一元素的位置
    public int indexOf(int toFind);
    //获取pos位置的元素
    public int get (int pos);
    //给pos位置元素设为value
    public void set (int pos,int value);
    //删除第一次出现的关键字key
    public void remove(int toRemove);
    //获取顺序表的长豆
    public int size();
    //清空顺序表
    public void clear();

    //打印顺序表,注意:该方法不是顺序表的方法,为了方便测试结果给出的
    public void display();
    

}

2.定义MyArrayList

MyArrayList要继承上面的接口并实现,现在是框架。

package mylist;

public class MyArrayList implements IList{
    @Override
    public void add(int data) {

    }

    @Override
    public void add(int pos, int data) {

    }

    @Override
    public boolean contains(int toFind) {
        return false;
    }

    @Override
    public int indexOf(int toFind) {
        return 0;
    }

    @Override
    public int get(int pos) {
        return 0;
    }

    @Override
    public void set(int pos, int value) {

    }

    @Override
    public void remove(int toRemove) {

    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public void clear() {

    }

    @Override
    public void display() {

    }
}

3.成员变量以及构造方法

	//储存元素的数组
    public int [] elem;
    //当前顺序表有多少个元素
    public int usedSize;
    //默认数组大小
    public static final int DEFAULT_SIZE = 10;
    
    public MyArrayList() {
        this.elem = new int [DEFAULT_SIZE];
    }

    public MyArrayList(int capacity ) {
        this.elem = new int[capacity];
    }

4.实现打印数组

    public void display() {
        for(int i = 0;i<usedSize;i++)
        {
            System.out.print(this.elem[i]+" ");
        }
        System.out.print("\n");
    }

5.实现add方法

在添加之前需要判断是否满(单独将判断是否满方法实现方法名为isFull),如果满了对数组扩容(所以我可以实现检查容量方法,如果满了就扩容,没满就什么都不做),没满添加。
重复上面操作,对于在pos位置添加,要判断pos如果合法就把后面向后挪一位,再对于pos位置添加数据。
不合法抛出异常。


public class PosIllegality  extends  RuntimeException{
    public PosIllegality(String msg)
    {
        super(msg);
    }
}
---------------------------------------------------------------------------------------
    public boolean isFull()
    {
        if(usedSize>=elem.length){
            return  true;
        }
        return  false;
    }

    private void checkCapacity()
    {
        if(isFull()) {
            //扩容
            elem =  Arrays.copyOf(elem,elem.length*2);
        }
    }

    @Override
    public void add(int data) {
        checkCapacity();
        elem[usedSize++] = data;
    }

    private  void  checkPosOnAdd(int pos)
    {
        if(pos>usedSize||pos<0)
        {
            System.out.println("不合法!");
            throw new PosIllegality("插入元素下标异常"+pos);
        }

    }
    @Override
    public void add(int pos, int data) {
        try{
            checkPosOnAdd(pos);
        }catch (PosIllegality e)
        {
            e.printStackTrace();
            return ;
        }
        checkCapacity();

        for(int i = usedSize++;i>pos;i--)
        {
            elem[i] = elem[i-1];
        }
        elem[pos] = data;
    }


测试:

    public static void main(String[] args) {
        MyArrayList myArrayList =  new MyArrayList();
        myArrayList.add(1);
        myArrayList.add(2);
        myArrayList.add(3);
        myArrayList.add(4);
        myArrayList.add(5);
        myArrayList.add(6);
        myArrayList.add(7);
        myArrayList.add(8);
        myArrayList.add(9);
        myArrayList.add(10);
        myArrayList.add(11);
        myArrayList.add(0,0);
        myArrayList.add(1,-1);
        myArrayList.display();
    }

在这里插入图片描述

6.实现查找某个数是否存在contains或者某个数的下标indexOf

首先得判断数组是否为空(可以单独实现是否为空的方法isEmpty),其次再寻找目标数。
注意如果是引用类型,要重写这个方法,比较不能直接比较要调用比较的方法

    public  boolean isEmpty()
    {
        if(usedSize==0)
        {
            return true;
        }
        return false;
    }
    @Override
    public boolean contains(int toFind) {
        if(isEmpty())
        {
            return false;
        }
        for(int i = 0;i<usedSize;i++)
        {
            if(elem[i]==toFind)
            {
                return  true;
            }
        }
        return true;
    }
  @Override
    public int indexOf(int toFind) {
        if(isEmpty())
        {
            return -1;
        }
        for(int i = 0;i<usedSize;i++)
        {
            if(elem[i]==toFind)
            {
                return  i;
            }
        }
        return -1;
    }

7.获取或更改pos位置的值 get和set

首先检查pos的合法性(单独写个检查pos的方法,如果不合法抛出异常),返回或修改pos位置的值。

    private  void  checkPosOnGet(int pos)
    {
        if(pos<0||pos>=usedSize)
        {
            System.out.println("不合法!");
            throw new PosIllegality("获取元素下标异常"+pos);
        }
    }

    @Override
    public int get(int pos) {
        try {
            checkPosOnGet(pos);
        }catch (PosIllegality e)
        {
            e.printStackTrace();
            return -1;
        }
        return elem[pos];
    }
private  void  checkPosOnSet(int pos)
    {

        if(pos<0||pos>=usedSize)
        {

            throw new PosIllegality("获取元素下标异常"+pos);
        }
    }
    @Override
    public void set(int pos, int value) {
//        try {
//            checkPosOnSet(pos);
//        }catch (PosIllegality e)
//        {
//            e.printStackTrace();
//            return ;
//        }
        checkPosOnSet(pos);
        elem[pos] = value;
    }

8.获取数组大小 size

    @Override
    public int size() {
        return usedSize;
    }

9.删除某个值 remove

    @Override
    public void remove(int toRemove) {
        int index = indexOf(toRemove);
        if(index==-1)
        {
            System.out.println("没有这数字");
            return;
        }

        for(int i = index;i<usedSize-1;i++)
        {
            elem[i] = elem[i+1];
        }
        usedSize--;
    }

10.清空 clear

    @Override
    public void clear() {
        usedSize = 0;
    }

思考如果存的是引用数据能不能直接将usedSize=0?
不能如果,数组里面装的是引用数据类型,就会造成内存泄漏。
JVM当中回收算法有很多
当前对象没有人引用的时候(1.elem=null 2.将每一个下标的值 elem[i]=null)

三、ArrayList源码如何做的

1.成员变量

在这里插入图片描述
elementData为存储元素的数组,是物理空间连续的内存地址。
size为数组存储元素的个数。

2.构造方法

1、有参数的构造

在这里插入图片描述

在这里插入图片描述

2、无参数的构造

在这里插入图片描述
在这里插入图片描述
发现无参数构造不给任何空间,那么add时数据放哪里?

3、数组构造

在这里插入图片描述
Collection是什么?
请看下图
在这里插入图片描述
? extends E表示:通配符的上级,?是E的子类或本身
举例:
ArrayList list = new ArrayList<>();
ArrayListlist2 = new ArrayList<>(list);
?就表示list的类型Interger,而E就是list2的类型是Number,符合子类。

4.add

在这里插入图片描述
这里可以看见add调用了ensureCapacityInternal,size为当前存储的个数当前还是没有任何插入,size为0
在这里插入图片描述
minCapacity为1
在这里插入图片描述
看上面无参数构造可以知道,if成立,此时返回了默认大小(DEFAULT_CAPACITY)也就是10,返回10。
在这里插入图片描述
在这里插入图片描述
看下面代码不难发现,grow就是扩容代码,oldCapacity>>1就是除2,ArraryList是1.5倍扩容。
在这里插入图片描述
总结:
1、 如果没有分配内存,第一次add会分配大小为10的内存
2、 ArrayList是1 .5倍扩容

5.addAll

    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 =new ArrayList<>();
        arrayList1.add(1);
        arrayList1.add(2);
        arrayList1.add(3);
        ArrayList<Integer> arrayList2 =new ArrayList<>();
        arrayList2.add(4);
        arrayList2.add(5);
        arrayList2.add(6);
        arrayList1 .addAll(arrayList2);
        arrayList2.addAll(1,arrayList1);
        System.out.println(arrayList1);
        System.out.println(arrayList2);

    }

在这里插入图片描述

6.remove

在这里插入图片描述
注意:传数字,只会删除对应下标的值,而传对象才会删对应的对象。

    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 =new ArrayList<>();
        arrayList1.add(1);
        arrayList1.add(2);
        arrayList1.add(3);

        arrayList1.remove(2);
        System.out.println(arrayList1);
        arrayList1.remove(new Integer(1));
        System.out.println(arrayList1);
    }

在这里插入图片描述

7.subList

在这里插入图片描述

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println(list);
        List<Integer> list1 = list.subList(1,3);
        System.out.println(list1);
    }

注意:
1.为左闭右开
2.返回的位List类型
3.截取不会产生新的对象(对返回的修改,被截取的也会修改)

8.迭代器 iterator

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        Iterator<Integer> it = list.iterator();
        while(it.hasNext())
        {
            System.out.print(it.next()+" ");
        }
    }

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言:文件操作详解

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; 一、为什么我们需要使用文件 我们在写程序的时候&#xff0c;输入的数据是存储在电脑内存中的&#xff0c;如果程序退出内存回收&#xff0c;相应数据也就丢失了&#xff0c;等再次运行程序&#xff0c;就看不到…

【IMAX6U移植OpenCV】

IMAX6U移植OpenCV V1.3 一 安装通用交叉编译器1.1 下载通用交叉编译器1.2 安装通用交叉编译器1.3 验证通用交叉编译器 二 搭建 OpenCV 3.4.1 的编译环境2.1 下载 OpenCV 3.4.1 源码2.2 配置 OpenCV 环境2.3 编译 OpenCV 源码 三 Qt 项目中加入OpenCV3.1 Qt 项目的 pro 文件Open…

Redis单机-主从集群-哨兵集群-分片集群 搭建教程

Redis集群 本章是基于CentOS7下的Redis集群教程&#xff0c;包括&#xff1a; 单机安装RedisRedis主从Redis分片集群 1.单机安装Redis 首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tclredis-6.2.4.tar.gz 然后将Redis安装包上传到虚拟机的任意目录&am…

2024美赛A题完整思路代码分析:建立竞争机理方程+遗传算法优化

A题是自由度比较大的场景限定下的模型构建&#xff0c;相对比较容易&#xff0c;核心是找到现有的成熟的数学模型&#xff0c;然后找到合适的数据进行证明得到结论&#xff0c;估计大部分是目标优化问题。&#xff08;不限制专业&#xff09; B题属于较为经典的物理建模&#…

Linux基础知识合集

整理了一下学习的一些关于Linux的一些基础知识&#xff0c;同学们也可以通过公众号菜单栏查看&#xff01; 一、基础知识 Linux基础知识 Linux命令行基础学习 Linux用户与组概念初识 Linux文件与目录权限基础 Linux中文件内容的查看 Linux系统之计划任务管理 二、服务器管理 Vm…

【靶场实战】Pikachu靶场XSS跨站脚本关卡详解

Nx01 系统介绍 Pikachu是一个带有漏洞的Web应用系统&#xff0c;在这里包含了常见的web安全漏洞。 如果你是一个Web渗透测试学习人员且正发愁没有合适的靶场进行练习&#xff0c;那么Pikachu可能正合你意。 Nx02 XSS跨站脚本概述 Cross-Site Scripting 简称为“CSS”&#xff…

HTTP(Java web方向补充篇)

HTTP&#xff08;Java web方向补充篇&#xff09; HTTP简介 概念&#xff1a;Hyper Text Transfer Protocol,超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则 HTTP协议特点&#xff1a; 基于TCP协议&#xff1a;面向连接&#xff0c;安全基于请求-响应模…

C语言指针学习 之 指针是什么

前言 指针是C语言中一个重要概念&#xff0c;也是C语言的一个重要特色&#xff0c;正确而灵活地运用指针可以使程序简洁、紧凑、高效。每一个学习和使用C语言的人都应当深入的学习和掌握指针&#xff0c;也可以说不掌握指针就没有掌握C语言的精华。 一、什么是指针 想弄清楚什…

基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖(十六)

商家端订单管理模块 1. 订单搜索1.1 需求分析和设计1.2 代码实现1.2.1 admin/OrderController1.2.2 OrderService1.2.3 OrderServiceImpl 2. 各个状态的订单数量统计2.1 需求分析和设计2.2 代码实现2.2.1 admin/OrderController2.2.2 OrderService2.2.3 OrderServiceImpl2.2.4 …

python执行linux系统命令的三种方式

前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 1. 使用os.system 无法获取命令执行后的返回信息 import osos.system(ls)2. 使用os.popen 能够获取命令执行后的返回信息 impor…

红队渗透靶机:LEMONSQUEEZY: 1

目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb 目录扫描 1、dirsearch 2、gobuster WEB phpmyadmin wordpress wpscan 登录wordpress 登录phpmyadmin 命令执行 反弹shell 提权 get user.txt 信息收集 本地提权 信息收集 1、arp ┌──(root㉿ru)-[~…

Python如何运用爬虫爬取京东商品评论

寻找数据真实接口 打开京东商品网址(添加链接描述) 查看商品评价。我们点击评论翻页&#xff0c;发现网址未发生变化&#xff0c;说明该网页是动态网页。 我们在浏览器右键点击“检查”&#xff0c;&#xff0c;随后点击“Network”&#xff0c;刷新一下&#xff0c;在搜索框中…

【实战系列----消息队列 数据缓存】rabbitmq 消息队列 搭建和应用

线上运行图&#xff0c;更新不算最新版&#xff0c;但可以使用修改线程等补丁功能&#xff0c;建议使用新版本。 远程服务器配置图: 这个可以更具体情况&#xff0c;因为是缓存队列理所当然 内存越大越好&#xff0c;至于核心4核以上足够使用。4核心一样跑 这里主要是需要配置服…

Linux下gcc的使用与程序的翻译

gcc和程序的翻译过程 gcc介绍程序的翻译过程预编译编译汇编链接 命令行式宏定义 gcc介绍 gcc是一款编译C语言编译器&#xff0c;可以把我们用vim写的代码编译成可执行程序。编译C用g进行编译&#xff0c;C的文件后缀是test.cc或test.cpp或test.cxx 如果要安装g就执行以下命令 …

QPL:一种新型的Text-to-SQL任务中间表示形式

导语 本文提出了一种叫做Query Plan Language (QPL)的语言&#xff0c;用来将复杂SQL语句分解为更加简单的子语句。QPL具有以下优势&#xff1a;1&#xff09;可以转述为简单问题&#xff0c;从而创建了一个 < 复杂问题&#xff0c;分解问题 > <复杂问题&#xff0c…

在Debian11安装Proxmox VE 7及设置GPU工作环境

我们在测试大模型&#xff0c;深度学习的过程中&#xff0c;可能遇到的情况就是不断的清空系统&#xff0c;避免老系统中安装的软件对测试系统造成影响&#xff0c;导致测试结果不准确或莫名报错。今天为小伙伴们介绍使用PVE7做成一个人工智能开发和测试的平台&#xff0c;你可…

【安装记录】Chrono Engine安装记录

本文仅用于个人安装记录。 官方安装教程 https://api.projectchrono.org/8.0.0/tutorial_install_chrono.html Windows下安装 windows下安装就按照教程好了。采用cmake-gui进行配置&#xff0c;建议首次安装只安装核心模块。然后依此configure下irrlicht&#xff0c;sensor…

maven代码规范检查(checkstyle、findbugs)

maven代码规范检查 前言一、使用checkstyle插件1. maven-checkstyle-plugin 介绍2. 接入方式3. 如何排除某个类、包下面的文件不进行检查使用suppressionsLocation 4. 如何关闭 二、使用findbugs插件1.findbugs-maven-plugin介绍2. 接入方式3. 如何排除某个类、包下面的文件不进…

ENSP路由器打不开,查看virtualBox,故障机是 AR_Base

AR_Base错误代码为&#xff1a;Raw-mode is unavailable courtesy of Hyper-V. (VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT). 参考virtualBox解决不能为虚拟电脑 AR_Base 打开一个新任务. Raw-mode is unavailable courtesy of Hyper-V. win11亲测有用。_不能为虚拟电脑ar_base打…

day37WEB攻防-通用漏洞XSS跨站权限维持钓鱼捆绑浏览器漏洞

目录 XSS-后台植入 Cookie&表单劫持&#xff08;权限维持&#xff09; 案例演示 XSS-Flash 钓鱼配合 MSF 捆绑上线 1、生成后门 2、下载官方文件-保证安装正常 3、压缩捆绑文件-解压提取运行 4、MSF 配置监听状态 5、诱使受害者访问 URL-语言要适当 XSS-浏览器网马…