【java集合总结】-- 数组总结+自己封装数组类

时间:2021-01-15 17:53:30

【java集合总结】-- 数组总结+自己封装数组类

一、前言

   本篇文章总结目前学习的有关数组方面的知识,首先总结一下数组相关的核心概念,然后在封装一个自己的泛型动态数组类(ava已经封装的有现成的,自己封装只是为了加深理解),最后再学习解析下ArrayList源码。

  本文应用:慕课网《玩转数据结构 从入门到进阶》课程,https://www.cnblogs.com/zhangyinhua/p/7687377.html

二、数组核心概念

  1、数组就是将数据码成一排进行存放

  【java集合总结】-- 数组总结+自己封装数组类

  2、因为数据是物理上连续排列的,那就可以给数据排序,添加索引,这样就可以通过索引快速访问数据。(如何通过索引快速访问呢?首个元素的地址+每个元素所占的地址宽度*索引值)

  3、java声明数组的方式

  int[] arr=new int[10];

  4、Java中数组中存放的类型是固定的。在另外的一些语言,数组中是可以存放不同的数据类型的。

  5、数组最大优点:快速查询。

  6、索引最好有语义。

    索引可以有语义,也可以无语义。

    数组最好应用于“索引有语义”的情况,无语义一般适合其他的数据类型。但并非所有有语义的索引都适合于数组,例如以身份证号为索引。

  7、数组一旦被定义,它的容量就不会在改变

    因此,除了结构的初始化和销毁之外,数组只有存取元素和修改元素值的操作。

  8、java中允许将一个数组变量拷贝给另一个数组变量,两个变量将引用同一个数组

  9、二维数组的两种存储方式:列序存储和行序存储(了解即可)

 三、封装一个自己的数组类

  java实际上已经为我们封装了一个Arrays类,但是为了加深了理解我们自己来封装一个数组类。

3.1、成员变量和基本方法

   private E[] data;
    private int size;

    // 构造函数,传入数组的容量capacity构造Array
    public Array(int capacity){
        data = (E[])new Object[capacity];
        size = 0;
    }

    // 无参数的构造函数,默认数组的容量capacity=10
    public Array(){
        this(10);
    }

    // 获取数组的容量
    public int getCapacity(){
        return data.length;
    }

    // 获取数组中的元素个数
    public int getSize(){
        return size;
    }

    // 返回数组是否为空
    public boolean isEmpty(){
        return size == 0;
    }

3.2、扩容方法

  为了解决数组类初始化后固定容量的局限性,我们通过本方法实现动态扩容,原理其实非常简单。

// 将数组空间的容量变成newCapacity大小
    private void resize(int newCapacity){

        E[] newData = (E[])new Object[newCapacity];
        for(int i = 0 ; i < size ; i ++)
            newData[i] = data[i];
        data = newData;
    }

3.3、add方法

  注意在add方法中使用了resize方法实现动态扩容,默认为两倍原来容量。

    // 在index索引的位置插入一个新元素e
    public void add(int index, E e){

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        if(size == data.length)
            resize(2 * data.length);

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

    // 向所有元素后添加一个新元素
    public void addLast(E e){
        add(size, e);
    }

    // 在所有元素前添加一个新元素
    public void addFirst(E e){
        add(0, e);
    }

3.4、查找方法

  很简单就不多做解释了

    // 获取index索引位置的元素
    public E get(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Get failed. Index is illegal.");
        return data[index];
    }// 查找数组中是否有元素e
    public boolean contains(E e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i].equals(e))
                return true;
        }
        return false;
    }

    // 查找数组中元素e所在的索引,如果不存在元素e,则返回-1
    public int find(E e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i].equals(e))
                return i;
        }
        return -1;
    }

3.5、删除方法

  注意remove方法中使用resize方法实现减容。

    // 从数组中删除index位置的元素, 返回删除的元素
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        E ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        data[size] = null; // 方便GC

        if(size == data.length / 4 && data.length / 2 != 0)
            resize(data.length / 2);
        return ret;
    }

    // 从数组中删除第一个元素, 返回删除的元素
    public E removeFirst(){
        return remove(0);
    }

    // 从数组中删除最后一个元素, 返回删除的元素
    public E removeLast(){
        return remove(size - 1);
    }

    // 从数组中删除元素e
    public void removeElement(E e){
        int index = find(e);
        if(index != -1)
            remove(index);
    }

四、结尾

  本文的内容还是很简单的,本来想一起把ArrayList源码解析一起写完的,但是发现这样篇幅太长了,所以放到下一篇文章:【java集合总结】-- ArrayList源码解析