我们已经学过了数组了,但我们知道一个事,数组是定长的,定长的数组显然是满足不了我们的需求的,因为我们不知道自己需要多长的数组,所以只能定义的尽可能大,这样就会造成极大的空间浪费。


那么我们可不可以想个办法去实现一个不固定长度的容器呢?


这节课我就来带大家实现一个不固定长度的容器。


Code:


/**

 * 我的数组表

 * 用数组来存储数据

 */

public class MyArrayList<E> {


    //存储数据

    private Object[] values;


    //MyArrayList中存储的元素个数

    private int size = 0;


    //接下来写构造器

    public MyArrayList()

    {

        values = new Object[10];    //我们默认初始化数组长度为10

    }


    //当然你我们也应该允许自定义容器长度

    public MyArrayList(int capital)

    {

        values = new Object[capital];

    }


    //定义一个获取MyArrayList内存储元素个数的方法

    public int size()

    {

        return size;

    }


    //核心方法,添加元素

    public void add(E e)

    {

        //再添加元素之前需要做判断

        if (size == values.length)

        {

            expandCapital();

        }

        //这个其实不难,就是往数组里添加元素

        values[size] = e;

        size++;

    }


    //扩容

    private void expandCapital()

    {

        if (size == values.length)

        {

            Object[] newValues = new Object[size * 2];  //我们将数组长度扩大一倍

            //然后拷贝数据

            for (int i = 0; i < size; i++) {

                newValues[i] = values[i];

            }

            //让values指向扩容后的数组

            values = newValues;

        }

    }


    //接下来我们需要有一个获取元素的方法

    public E get(int index)

    {

        //这里还有点小问题,没有防止数组越界,加个判断

        if (index < 0 || index >= size)

            return null;

        return (E)values[index];

    }


    //有添加就要有删除


    /**

     * 删除方法,删掉index位置的元素,并返回被删掉的元素

     * @return

     */

    public E delete(int index)

    {

        //第一步,找到要被删除的元素

        E e  = get(index);

        if (e != null)

        {

            //开始删除,想法就是让a[i] = a[i+1],然后让最后一个元素指向null,最后size--

            for (int i = index; i < size - 1; i++)

                values[index] = values[index + 1];

            values[size - 1] = null;

            size--;

        }

        //如果e为null

        return null;

    }


    //再来写一个修改

    public void set(int index, E e)

    {

        if (get(index) != null)

        {

            values[index] = e;

        }

    }


    //最后写一个insert,在任意位置插入

    public void insert(int index, E e)

    {

        //首先做判断,插入位置是否合法

        if (index < 0 || index > size())

            return;

        if (index == size)

            add(e);

        else

        {

            //和删除相反

            add(null);

            for (int i = size; i > index; i--)

            {

                values[i] = values[i-1];

            }

            values[index] = e;

            return;

        }


    }


    public boolean contains(E e)

    {

        //如果e为null就检查一下表里有没有null

        if (e == null)

        {

            for (int i = 0; i < size; i++) {

                if (values[i] == null)

                    return true;

            }

        }

        else

        {

            //如果e不为null就调用equals方法判断表里是否有元素和e相等

            for (int i = 0; i < size; i++) {

                if (e.equals(values[i]))

                    return true;

            }

        }

        return false;


    }


    //注意,这里必须new一个新的数组返回,因为我们不希望返回的数组是values引用的数组对象

    public Object[] toArray()

    {

        Object[] newValues = new Object[this.size()];

        for (int i = 0; i < size; i++) {

            newValues[i] = values[i];

        }

        return newValues;

    }


    //将数组复制到arr中,只不过这个传入的数组长度必须要足够长

    public void toArray(E[] arr)

    {

        if (arr.length < size)

        {

            System.out.println("这个数组长度小于" + this.size() + ", 请传入一个长度比" + this.size() + "更长的数组");

            return;

        }

        for (int i = 0; i < size; i++) {

            arr[i] = (E)values[i];

        }

    }


    public static void main(String[] args) {

        MyArrayList<Integer> list = new MyArrayList<>();

        list.add(1);

        list.add(2);

        System.out.println(list.size());    //2

        //可以看到我们可以动态的添加数据,但有一个问题

        for (int i = 0; i < 100; i++)

        {

            list.add(i);

        }

        //数组下标越界了,但是我们希望我们可以添加任意个元素,怎么办呢?

        //一个想法是数组扩容

        System.out.println("添加100个元素后的表的长度:" + list.size());

        //测试一下

        System.out.println("第50个元素为:" + list.get(50));

        System.out.println("第51个元素为:" + list.get(51));


        System.out.println("我要删除第50个元素啦");

        list.delete(50);

        System.out.println("现在第50个元素为:" + list.get(50));

        System.out.println("现在表的长度为:" + list.size());

        //可以很明显的看到元素被删除了


        //试试可不可以

        System.out.println("现在我要在表的第50位置插入48");

        list.insert(50,48);

        System.out.println("现在表的第50位置的元素为:" + list.get(50));

        System.out.println("现在表的长度为:" + list.size());


        //这就是动态数组表的增删改查

        //最后再加点其他功能

        System.out.println(list.contains(60));


        Object[] objects = list.toArray();

        System.out.println(objects.length);


        Integer[] arr = new Integer[30];

        list.toArray(arr);  //这样就长度不够


        Integer[] arr2 = new Integer[200];

        list.toArray(arr2);

        System.out.println(arr2[0]);    //这个就正常了

    }


}