Java——动态数组实现的原理与应用

        在编程中,数组是一种基本的数据结构,用于存储一系列相同类型的元素。然而,传统的数组在创建时需要指定大小,这在处理动态数据时可能会带来不便。为了解决这个问题,动态数组(Dynamic Array)应运而生。动态数组能够在运行时根据需要调整其大小,从而提供更大的灵活性。虽然Java已经有ArrayList了,但是为了打好基础还是有必要自己手动过一遍这些底层原理机制的。

动态数组代码实现

以下是一个简单的动态数组实现,用Java语言编写:

package school;


import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.stream.IntStream;

/**
 * 文件名: null.java
 * 作者: 20526
 * 创建时间: 2024/9/5 15:44
 * 描述:动态数组实现
 */
public class DynamicArray implements Iterable<Integer> {

    private int size = 0;
    private int capacity = 10;
    private int[] arr = {};

    public void addlast(int num) {
//        arr[size] = num;
//        size++;
        add(size,num);
    }


    public void add(int index, int num) {
        checkCapacity();
        if (index >= 0 && index < size) {
            System.arraycopy(arr, index, arr, index + 1, size - index);
        }
        size++;
        arr[index] = num;

    }

    private void checkCapacity() {
        //容量检查
        if (size == 0){
            arr  = new int [capacity];
        }
        else if (size == capacity) {
            //进行1.5倍扩容
            capacity +=  capacity>>1;
            int[] newArr = new int[capacity];
            System.arraycopy(arr,0,newArr,0,size);
            arr = newArr;
        }
    }

    public int get(int index) {
        return arr[index];
    }



    //排序方法
    public void sort(){
        Arrays.sort(arr,0,size);
    }

    //遍历方法

    //foreach遍历
    public void foreach(Consumer<Integer> consumer) {
        for (int i = 0; i < size; i++) {
//            System.out.println(arr[i]);
            consumer.accept(arr[i]);
        }
    }


    //迭代器遍历
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            int i = 0;

            @Override
            public boolean hasNext() {
                return i<size;
            }

            @Override
            public Integer next() {
                return arr[i++];
            }
        };
    }

    //Stream 遍历
    public IntStream stream(){
        return IntStream.of(Arrays.copyOfRange(arr,0,size));
    }

    //删除方法
    public void remove(int index){
        if (index < size-1 && index >= 0) {
            System.arraycopy(arr, index + 1, arr, index, size - index - 1);
        }
        size--;
    }
}
测试代码
package school;

import org.junit.Test;

import java.util.Arrays;
import java.util.function.Consumer;

/**
 * 文件名: null.java
 * 作者: 20526
 * 创建时间: 2024/9/5 16:06
 * 描述:
 */
public class DynamicArrayTest {

    @Test
    public void test1() {
        DynamicArray dynamicArray = new DynamicArray();
        dynamicArray.addlast(20);
        dynamicArray.addlast(10);
        dynamicArray.addlast(30);
        dynamicArray.addlast(5);

        dynamicArray.foreach(num->{
                    System.out.println(num);
        });
        dynamicArray.sort();

    }

    @Test
    public void test2() {
        DynamicArray dynamicArray = new DynamicArray();
        dynamicArray.addlast(1);
        dynamicArray.addlast(2);
        dynamicArray.addlast(3);
        dynamicArray.addlast(5);

        for(int elements: dynamicArray){
            System.out.println(elements);
        }
    }

    @Test
    public void test3() {
        DynamicArray dynamicArray = new DynamicArray();
        dynamicArray.addlast(1);
        dynamicArray.addlast(2);
        dynamicArray.addlast(3);
        dynamicArray.addlast(5);

        dynamicArray.stream().forEach(element -> System.out.println(element));

    }

    @Test
    public void test4() {
        DynamicArray dynamicArray = new DynamicArray();
        dynamicArray.addlast(1);
        dynamicArray.addlast(2);
        dynamicArray.addlast(3);
        dynamicArray.addlast(5);

        dynamicArray.remove(2);
        dynamicArray.foreach(num->{
                System.out.println(num);
        });
    }



}

通过上述测试代码,我们可以验证动态数组的插入、删除、遍历和排序功能是否正常工作。 

关键点解析

下面所有代码都出自上面的代码片段

容量检查与扩容
  • checkCapacity()方法用于检查当前数组的容量是否足够。如果不够,则进行扩容。扩容策略通常是增加当前容量的一半(即1.5倍扩容)。
  • System.arraycopy()方法用于在数组之间复制数据,这在插入和删除操作中非常有用。
插入与删除
  • add(int index, int num)方法用于在指定位置插入元素。如果插入位置在数组中间,需要将后续元素向后移动。
  • remove(int index)方法用于删除指定位置的元素。删除后,需要将后续元素向前移动。
遍历方法
  • foreach(Consumer<Integer> consumer)方法使用Java的Consumer接口实现对数组的遍历。
  • iterator()方法实现了Iterable接口,允许使用增强for循环进行遍历。
  • stream()方法返回一个IntStream,允许使用Java Stream API进行高级操作。
 匿名内部类:
@Override
public Iterator<Integer> iterator() {
    return new Iterator<Integer>() {
        int i = 0;

        @Override
        public boolean hasNext() {
            return i < size;
        }

        @Override
        public Integer next() {
            return arr[i++];
        }
    };
}

在这段代码中,iterator()方法返回一个匿名内部类实例,该实例实现了Iterator<Integer>接口。匿名内部类的特点是没有类名,直接在创建对象时定义类的实现。这里通过匿名内部类实现了Iterator接口的两个方法:

  • hasNext()方法:检查是否还有下一个元素。
  • next()方法:返回当前元素,并将指针移动到下一个元素。

匿名内部类的优点是简洁,适合用于一次性需求的场景。

System.arraycopy()方法

Arrays.copyOfRange()方法
public IntStream stream() {
    return IntStream.of(Arrays.copyOfRange(arr, 0, size));
}

 在这段代码中,Arrays.copyOfRange(arr, 0, size)方法用于生成一个包含有效元素的子数组。Arrays.copyOfRange()方法的参数如下

  • original:要复制的源数组。
  • from:要复制的范围的起始位置(包括)。
  • to:要复制的范围的结束位置(不包括)。
  • 该方法返回一个新的数组,包含源数组中从fromto位置的元素。这里用于生成一个包含动态数组有效元素的子数组,供后续的流操作使用。
Lambda表达式
@Test
public void test1() {
    DynamicArray dynamicArray = new DynamicArray();
    dynamicArray.addlast(20);
    dynamicArray.addlast(10);
    dynamicArray.addlast(30);
    dynamicArray.addlast(5);

    dynamicArray.foreach(num -> {
        System.out.println(num);
    });
    dynamicArray.sort();
}

在这段测试代码中,dynamicArray.foreach(num -> { System.out.println(num); });使用了Lambda表达式。Lambda表达式是Java 8引入的一种简洁的语法,用于表示匿名函数。这里的Lambda表达式num -> { System.out.println(num); }表示一个接受一个整数参数num并打印该参数的函数。

Lambda表达式的基本语法是(参数列表) -> { 函数体 }。它可以使代码更加简洁和易读,特别适用于函数式接口(只包含一个抽象方法的接口)的实现。

总结

        动态数组通过在运行时调整大小,提供了比传统数组更大的灵活性。通过合理使用Java的API,如System.arraycopy()Arrays.sort()IntStream,可以高效地实现动态数组的各种操作。希望这篇博客能帮助你更好地理解动态数组的实现原理及其应用。

 

 

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值