数组的扩容

1.背景

数组是一种按照顺序存储的数据结构,通常在被创建之后,就不能被改变。若想要在原来的数组上面增加或者删除一些数据,就需要用到数组的扩容技术。通常是采用创建一个新数组,对数组进行以下增删改的操作,然后将原来数组的引用指向这个新创建的数组。

2.问题的提出、解决及思考

2.1 问题的提出

现在有一个int类型的数组arr,需要在指定的begin位置后面添加一个长度为num的数组need。通俗的说,就是需要将一个数组插入到原始数组的指定位置,获得一个新的数组。

2.2 问题的解决

作为一个初学者,在不懂调用java工具包或者使用相关函数的情况下,我先自己编写了一个小程序来实现这个简单的功能,可能网上会有更好的办法,欢迎大家一起讨论。

 public class addArray {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,8,3,5,4};
        System.out.println("原始的数组为:"+ Arrays.toString(arr));
        int[] need = new int[]{2,3,4,7};
        System.out.println("插入的数组为:"+Arrays.toString(need));
        int[] arr = add(3, 4, need, arr);
        System.out.println("插入后的数组为"+Arrays.toString(add));

    }
    public static int[] add(int begin,int num,int[] need,int[] org){
        int[] arrNew = new int[org.length+num];
        int index = begin;
        for (int i = 0; i < arrNew.length; i++) {
                if(i<=begin){
                    arrNew[i] = org[i];
                }else if(i<=begin+num){
                    arrNew[i]=need[i-begin-1];
                }else {
                    begin++;
                    arrNew[i] = org[begin];
                }
        }
        return arrNew;
        }
  }

2.3 问题的思考

对于数组扩容这个简单的问题,我查阅了网上的相关的一些比较常用的方法,总结如下:

  1. 利用数组复制的方式进行扩容(也就是上文中代码提到的方法)

  2. System.arraycopy的方法进行扩容:

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
代码解释:
   Object src : 原数组
   int srcPos : 从元数据的起始位置开始
   Object dest : 目标数组
   int destPos : 目标数组的开始起始位置
   int length : 要copy的数组的长度

  1. Arrays.copyOf()可以简便的创建数组副本

public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
代码解释:
   src:源数组
   srcPos: 从元数据的起始位置开始
   dest : 目标数组
   destPos: 目标数组的开始起始位置
   length: 要copy的数组的长度

2.4 扩展阅读

我们都知道,String类型是java中一种比较常用的引用类型,底层是用一个被final修饰的字符型数组,每一次对字符串进行增删改操作的时候都会创建一个新的字符串,这样很容易造成资源的浪费。而StrigBuffer/StringBuilder定义为字符串缓冲区,是可变长度的字符串。StringBuffer(jdk1.0): 线程安全,StringBuilder(jdk1.5):非线程安全。也就是说在单线程的情况下尽量使用StringBuilder,效率较高。当然,这里的主要问题,是想要研究一下StrigBuffer/StringBuilder是如何被定义为可变字符串的,底层的实现原理是什么?
首先StrigBuffer/StringBuilder都是继承自同一个类AbstractStringBuilder,下面对StringBuffer进行讨论:

  public StringBuffer(){
      super(16);
  }

可以看出,无参数的情况下,初始的StringBuffer的容量为16。

  public StringBuffer(String str){
      super(str.length()+16);
  }

有参数的情况下,初始的StringBuffer的容量为16+字符串的长度。也就是说,字符串在被创建的时候,就会将原始的字符串的容量扩展16。

  public AbstractStringBuilder append(String str){
      if(str==null)
          return appendNull();
      int len=str.length();
      ensureCapacityInternal(count+len);
      str.getChars(0,len,value,count);
      count+=len;
      return this;
  }

使用ensureCapacityInternal来判断,如果新增的字符串超过StringBuffer的容量(16+字符串长度),进行扩容的操作,int newCapacity = (value.length << 1) + 2。增加为自身长度的一倍然后再加2,如果还是不够大,那就直接扩容到它需要的长度newCapacity = minCapacity;

 private void ensureCapacityInternal(int minimumCapacity){
      if(minimumCapacity-value.length>0){
          value = Arrays.copyOf(value,newCapacity(minimumCapacity));
      }
  }
private int newCapacity(int minCapacity){
      int newCapacity = (value.length<<1)+2;
      if(newCapacity-minCapacity<0){
          newCapacity=minCapacity;
      }
      return (newCapacity<=0||MAX_ARRAR_SIZE-newCapacity<0)? hugeCapacity(minCapacity):newCapacity;
  }

3.总结

定义常量字符串的时候通常使用String类型,如果经常要对字符串进行修改的操作,尽量使用StringBuffer/StringBuilder来避免频繁的创建对象,从而减小开销。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值