我的编程空间,编程开发者的网络收藏夹
学习永远不晚

java基础-数组扩容详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

java基础-数组扩容详解

数组与链表的比较:

  • 数组通过下标访问的话是O(1)
  • 数组一旦声明 长度就是固定的
  • 数组的数据是物理逻辑均连续的
  • 链表增删要快一些, 数组遍历快一些
  • 长度一定的话, 数组的存储空间比链表要小

ArrayList:

ArrayList是List接口的实现类,它是支持根据需要而动态增长的数组;java中标准数组是定长的,在数组被创建之后,它们不能被加长或缩短。这就意味着在创建数组时需要知道数组的所需长度,但有时我们需要动态程序中获取数组长度。ArrayList就是为此而生的。

扩容机制发生在add()方法调用的时候;


  public boolean add(E e) {
       //扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

该行代码ensureCapacityInternal()是用来扩用的,形参是最小扩容量,进入该方法后:


    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

通过方法calculateCapacity(elementData, minCapacity)获取:


   private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //如果传入的是个空数组则最小容量取默认容量与minCapacity之间的最大值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

使用 ensureExplicitCapacity方法可以判断是否需要扩容:


 private void ensureExplicitCapacity(int minCapacity) {
          modCount++;
          // 如果最小需要空间比elementData的内存空间要大,则需要扩容
          if (minCapacity - elementData.length > 0)
              //扩容
              grow(minCapacity);
      }

需要扩容,进入ArrayList扩容的关键方法grow():扩大为原来的1.5倍;


 private void grow(int minCapacity) {
          // 获取到ArrayList中elementData数组的内存空间长度
          int oldCapacity = elementData.length;
         // 扩容至原来的1.5倍
         int newCapacity = oldCapacity + (oldCapacity >> 1);
         // 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,
          // 不够就将数组长度设置为需要的长度
         if (newCapacity - minCapacity < 0)
             newCapacity = minCapacity;
         //若预设值大于默认的最大值检查是否溢出
         if (newCapacity - MAX_ARRAY_SIZE > 0)
             newCapacity = hugeCapacity(minCapacity);
         // 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间
         // 并将elementData的数据复制到新的内存空间
         elementData = Arrays.copyOf(elementData, newCapacity);
     }
复制代码

至此得出ArrayList扩容的本质是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去。

LinkedList:

链表实现扩容,直接在尾指针后面加入新的元素即可。

实现LinkedList:LinkedList的底层实现是链表。更深理解是一个双向链表。

节点代码:


//节点
public class Node {
	Node previous;//前继,指向前一个Node
	Object data;//节点数据
	Node next;//后继,指向后一个Node
	public Node() {
	}
	public Node(Node previous, Object data, Node next) {
		super();
		this.previous = previous;
		this.data = data;
		this.next = next;
	} 
}

初始化MyLinkedList:


public class MyLinkedList {
	private Node first;//首节点
	private Node last;//尾节点
	private int size;//链表大小
	public MyLinkedList() {
		first = null;
		last = null;
		size = 0;
	}
}

尾部添加,实现add(Object obj)方法:


public void add(Object obj){
		Node node = new Node(null,null,null);
		if(first==null){//first=null,说明LinkedList中没有一个节点
			node.data = obj;
			first = node;
			last = node;//第一个节点和最后一个节点都是node
			size++;
		}else{
			node.data = obj;
			last.next = node;//和最后一个连接起来
			node.previous = last;
			last = node;//当前节点变为末尾节点
			size++;
		}

现get(int index)方法,获取index处的节点并返回Node:

使用循环,遍历链表:


public Node get(int index) {
		RangeCheck(index);
		Node temp = null;
		if(index < (size>>1)){//改进的遍历方法,右移运算符的巧用
			temp = first;
			for(int i=0;i<index;i++){
				temp = temp.next;
			}
		}else {
			temp = last;
			for(int i=size-1;i>index;i--){
				temp = temp.previous;
			}
		}
		return temp;
	}

任意位置插入,实现add(int index,Object obj)方法:插入的步骤注意顺序,不要产生断链。


public void add(int index,Object obj) {
		RangeCheck(index);//对传入的索引必须进行检查,判断是否越界
		Node node = new Node(null,null,null);
		node.data = obj;
		Node node2=first;
		for(int i=0;i<index-1;i++){
			node2 = node2.next;
		}
		node.next = node2.next;
		node2.next.previous=node;
		node2.next = node;
		node.previous=node2;
		size++;
	}

RangeCheck():


private void RangeCheck(int index) {
		if(index<0||index >= size){
			throw new IndexOutOfBoundsException("IndexOutOfBounds"+index);//不合法则抛出异常
		}
	}

实现remove(Object obj)方法:


public boolean remove(Object obj) {
		Node node = first;
		if(obj==null){
			while(node!=null){
				if(node.data==null){
					removefast(node);
					return true;
				}
				node = node.next;
			}
		}else {
			while(node!=null){
				if(obj.equals(node.data)){
					removefast(node);
					return true;
				}
				node = node.next;
			}
		}
		return false;
	}
	private void removefast(Node node){
		node.previous.next=node.next;
		size--;
		node.data=null;
		node.previous = node.next = null;
	}

实现set(int index,Object obj)方法:


public Object set(int index,Object obj) {
		Node node = get(index);
		Object oldObject=node.data;
		node.data = obj;
		return oldObject;
	}

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注编程网的更多内容!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

java基础-数组扩容详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java数组扩容实例代码

在写程序的过程中,我们常常会碰见数组空间不够用的情况,比如我已经初始化了一个数组int []a = {1,2,3,4,5,6,7,8,9,10} ;这时,我想往数组下标3的位置插入一个元素,该怎么做?用C语言实现太难了吧,需要调用memcp
2023-05-30

怎么在java中扩容数组

这期内容当中小编将会给大家带来有关怎么在java中扩容数组,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户端开
2023-06-14

【Java 基础篇】Java Map 详解

文章目录 导言一、Map 概述二、HashMap三、TreeMap四、LinkedHashMap总结 导言 在Java的集合框架中,Map接口用于存储键值对,提供了一种基于键进行查找和操作的数据结构。Map接口的实现类提供了
2023-08-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录