day08 【Arrays类】

Arrays类

1.功能概述

  • Arrays类是一个工具类,其中包含了数组操作的很多方法,比如搜索和排序
  • Arrays类中的方法均为static修饰的,可以直接通过Arrays.xxx(xxx)的形式调用方法

2.几个重要方法

asList
由给定的数组a,返回一个固定大小的List对象。在这里,着重解释一下前面这句话的深层含义,我们可以看Arrays类的源码,来帮助我们理解

生成的List对象,是由所给的数组a来决定的,我们看一下源码实现

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

而这个ArrayList并不是java.util中的ArrayList类,而是Arrays的内部类ArrayList,源码为:

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }

        @Override
        public Object[] toArray() {
            return a.clone();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        @Override
        public int indexOf(Object o) {
            E[] a = this.a;
            if (o == null) {
                for (int i = 0; i < a.length; i++)
                    if (a[i] == null)
                        return i;
            } else {
                for (int i = 0; i < a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        @Override
        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }

        @Override
        public Spliterator<E> spliterator() {
            return Spliterators.spliterator(a, Spliterator.ORDERED);
        }

        @Override
        public void forEach(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            for (E e : a) {
                action.accept(e);
            }
        }

        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            Objects.requireNonNull(operator);
            E[] a = this.a;
            for (int i = 0; i < a.length; i++) {
                a[i] = operator.apply(a[i]);
            }
        }

        @Override
        public void sort(Comparator<? super E> c) {
            Arrays.sort(a, c);
        }
    }

具体思路

public static <T> List<T> asList(T... a) {
            //传入a这个数组,然后拿着这个数组直接构造
            return new Arrays.ArrayList<>(a);
        }
private static class ArrayList<E> extends AbstractList<E>

            //这个内部类有一个数组类型的a
            private final E[] a;

            //内部ArrayList的构造,先非空判断之后给a赋值
            ArrayList(E[] array) {
                a = Objects.requireNonNull(array);
            }

具体操作示例

@Test
    public void test1(){

        int[] arr = {1,2,3};

        List<Object> objects = Arrays.asList(arr);

        System.out.println("arr = " + arr);//arr = [I@1b0375b3

        System.out.println("objects = " + objects);//objects = [[I@1b0375b3],可以看到,又包了一层[]

    }

所以,可以看出,最后生成的List实例的元素与数组a中的元素是一样的,并且,其长度和数组a的元素一样。

现在解释一下“固定长度的意思”:

List与数组的一个区别是,List的长度是可变的,可以对List进行插入和删除元素,数组的长度是固定的,而且不能从数组中删除元素,只能修改元素的值。利用Arrays.asList(array)将返回一个List,然而这个返回的List并不支持add和remove的操作。

那为什么不支持add和remove操作呢?只能上源码了:

我们在AbstractList中找到依据,如何实现插入和删除元素:

public boolean add(E e) {
  add(size(), e);
  return true;
}
 //增加元素会直接抛异常,就是不让你添加的意思
public void add(int index, E element) {
  throw new UnsupportedOperationException();
}
 //删除元素的时候也是会这样
public E remove(int index) {
  throw new UnsupportedOperationException();
}

实验一下啊
在这里插入图片描述

小tips:当改变原数组中的元素时,会导致list对象中的相应元素发生改变;同样的,当生成的list对象中的元素做修改时,也会导致原来数组中相应的元素发生改变

fill

给定特定值val,使整个数组中或者某下标范围内的元素值为val
源码:

public static void fill(int[] a, int val) {
            //从0-a的最大长度开始遍历,然后把每个下班都赋值val(传进来的参数)
            for (int i = 0, len = a.length; i < len; i++)
                a[i] = val;
        }
//这个是有起始位置和结束位置的fill
public static void fill(int[] a, int fromIndex, int toIndex, int val) {
		//先对这个起始位置和结束位置进行一个判断,有错误的话直接抛异常
        rangeCheck(a.length, fromIndex, toIndex);
        //赋值,如果没有赋值的还是默认值(0)
        for (int i = fromIndex; i < toIndex; i++)
            a[i] = val;
    }

测试一下

@Test
    public void test2(){

        int[] arr1 = new int[7];
        int[] arr2 = new int[7];

        //把arr1里面的元素全部赋值为6
        Arrays.fill(arr1,3);

        //把arr2里面的元素从第三到第五赋值为6,其余的值还是初始值0
        Arrays.fill(arr2,3,5,6);

        for (int i : arr1) {
            System.out.print(i+" ");//3 3 3 3 3 3 3
        }

        System.out.println();

        for (int i : arr2) {
            System.out.print(i+" ");//0 0 0 6 6 0 0
        }

    }

copyOf()

将原始数组的元素,复制到新的数组中,可以设置复制的长度(即需要被复制的元素个数)
先看源码

public static int[] copyOf(int[] original, int newLength) {
		//先弄一个新的数组
        int[] copy = new int[newLength];
        //调用了System的拷贝数组的方法(native),从0把原数组拷贝到新数组
        System.arraycopy(original, 0, copy, 0,
        				//如果原数组的长度<=新数组的长度,那就用原来的
        				//如果不是,那就用新的
                         Math.min(original.length, newLength));
        return copy;
    }

copyOfRange():将某个范围内的元素复制到新的数组中

public static int[] copyOfRange(int[] original, int from, int to) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        int[] copy = new int[newLength];
        System.arraycopy(original, from, copy, 0,
                         Math.min(original.length - from, newLength));
        return copy;
    }

测试一下

@Test
    public void test3() {

        int[] arr_a = {1, 2, 3, 4, 5};

        int[] arr_b;
        int[] arr_c;
        int[] arr_d;

        //给定的长度大于源数组的长度,那么多的位置就用0来进行填充
        arr_b = Arrays.copyOf(arr_a, 10);

        for (int i : arr_b) {
            System.out.print(i + " ");//1 2 3 4 5 0 0 0 0 0
        }

        System.out.println();

        //给的长度比较小的话,那就小咯
        arr_c = Arrays.copyOf(arr_a, 2);
        for (int i : arr_c) {
            System.out.print(i + " ");//1 2
        }

        System.out.println();

        arr_d = Arrays.copyOfRange(arr_a, 2, 4);
        for (int i : arr_d) {
            System.out.print(i + " ");//3 4
        }
    }

equals()

判断两个数组中的元素是否一一对应相等

以int数组来分析,其他类型的数组原理一样
先看源码

public static boolean equals(int[] a, int[] a2) {
            //如果a和a2的内存引用地址相同,那么肯定相同返回true
            if (a==a2)
                return true;
            
            //如果a或者a2为null,那么肯定不行啊,返回false
            if (a==null || a2==null)
                return false;
            
            //判断两个数组的长度是否相同,不相同肯定不一样啊,返回false
            int length = a.length;
            if (a2.length != length)
                return false;

            //循环遍历两个数组,挨个比对各个元素是否相同,只要有一个不相同,直接returnfalse
            for (int i=0; i<length; i++)
                if (a[i] != a2[i])
                    return false;

            return true;
        }

测试一下

@Test
    public void test4() {

        int[] a = new int[]{1, 2, 3};

        int[] b = null;

        int[] c = new int[]{};

        int[] d = new int[]{1, 2, 3};

        System.out.println(Arrays.equals(a, b));//false
        System.out.println(Arrays.equals(a, c));//false
        System.out.println(Arrays.equals(a, d));//true
        System.out.println(Arrays.equals(b, c));//false
        System.out.println(Arrays.equals(b, d));//false
        System.out.println(Arrays.equals(c, d));//false

    }

sort

对数组进行升序排序,排序后 ,数组中存放的是排序后的结果
以int数组来分析,其他类型的数组原理一样
源码分析

public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

然后再点进去发现···

static void sort(int[] a, int left, int right,
                     int[] work, int workBase, int workLen) {
        // Use Quicksort on small arrays
        if (right - left < QUICKSORT_THRESHOLD) {
            sort(a, left, right, true);
            return;
        }

        /*
         * Index run[i] is the start of i-th run
         * (ascending or descending sequence).
         */
        int[] run = new int[MAX_RUN_COUNT + 1];
        int count = 0; run[0] = left;

        // Check if the array is nearly sorted
        for (int k = left; k < right; run[count] = k) {
            if (a[k] < a[k + 1]) { // ascending
                while (++k <= right && a[k - 1] <= a[k]);
            } else if (a[k] > a[k + 1]) { // descending
                while (++k <= right && a[k - 1] >= a[k]);
                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
                    int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
                }
            } else { // equal
                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
                    if (--m == 0) {
                        sort(a, left, right, true);
                        return;
                    }
                }
            }

            /*
             * The array is not highly structured,
             * use Quicksort instead of merge sort.
             */
            if (++count == MAX_RUN_COUNT) {
                sort(a, left, right, true);
                return;
            }
        }

        // Check special cases
        // Implementation note: variable "right" is increased by 1.
        if (run[count] == right++) { // The last run contains one element
            run[++count] = right;
        } else if (count == 1) { // The array is already sorted
            return;
        }

        // Determine alternation base for merge
        byte odd = 0;
        for (int n = 1; (n <<= 1) < count; odd ^= 1);

        // Use or create temporary array b for merging
        int[] b;                 // temp array; alternates with a
        int ao, bo;              // array offsets from 'left'
        int blen = right - left; // space needed for b
        if (work == null || workLen < blen || workBase + blen > work.length) {
            work = new int[blen];
            workBase = 0;
        }
        if (odd == 0) {
            System.arraycopy(a, left, work, workBase, blen);
            b = a;
            bo = 0;
            a = work;
            ao = workBase - left;
        } else {
            b = work;
            ao = 0;
            bo = workBase - left;
        }

        // Merging
        for (int last; count > 1; count = last) {
            for (int k = (last = 0) + 2; k <= count; k += 2) {
                int hi = run[k], mi = run[k - 1];
                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
                        b[i + bo] = a[p++ + ao];
                    } else {
                        b[i + bo] = a[q++ + ao];
                    }
                }
                run[++last] = hi;
            }
            if ((count & 1) != 0) {
                for (int i = right, lo = run[count - 1]; --i >= lo;
                    b[i + bo] = a[i + ao]
                );
                run[++last] = right;
            }
            int[] t = a; a = b; b = t;
            int o = ao; ao = bo; bo = o;
        }
    }

我看不懂了啊!

好吧,直接开始测试一下

@Test
    public void test5() {

        int[] a = new int[]{22, 1, 4, 65, 3, 55, 10};
        Arrays.sort(a);
        for (int i : a) {
            System.out.print(i + " ");//1 3 4 10 22 55 65
        }

    }

binarySearch

对排序好的数组,采用二分查找的方式查找某个元素,可以在整个数组中查找,也可以在某个范围内查找。
以int数组来分析,其他类型的数组原理一样
源码

private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

测试一下

@Test
    public void test6(){

        int[] a = {1,45,78,23,123,98,67,12,90,56};

        //返回索引
        int i = Arrays.binarySearch(a, 123);

        System.out.println("i = " + i);//4

        //找不到的话就返回-5
        int i1 = Arrays.binarySearch(a, 111);
        System.out.println("i1 = " + i1);//-5

        //给一个区间范围让他去找
        int i2 = Arrays.binarySearch(a, 1, 2, 222);

    }

toString

就是把数组转换成字符串输出
先看源码

public static String toString(int[] a) {
            //如果为空,直接返回空的字符串表达形式
            if (a == null)
                return "null";
            //设置一个iMax为a的长度-1
            int iMax = a.length - 1;

            //如果-1之后=负一,那么说明原来的数组长度为0,也就是啥都没得,直接返回一个[]
            if (iMax == -1)
                return "[]";

            //这里用的是StringBuilder来进行拼接操作
            StringBuilder b = new StringBuilder();

            //先拼接一个开头[
            b.append('[');

            //开始一个循环操作
            for (int i = 0; ; i++) {

                //开始往StringBuilder里面去拼接值
                b.append(a[i]);

                //如果索引=数组的长度-1,也就是说到头了
                if (i == iMax)
                    //那么就拼一个结束]
                    return b.append(']').toString();
                //如果没结束,那就拼一个,
                b.append(", ");
            }
        }

测试一下

@Test
    public void test7(){

        int[] arr = {2, 34, 35, 4, 657, 8, 69, 9};
        //输出的是地址值
        System.out.println(arr);//[I@1b0375b3

        //将int类型的数组转换成字符串表现格式
        Arrays.sort(arr);//升序排序

        String string = Arrays.toString(arr);
        System.out.println(string);//[2, 4, 8, 9, 34, 35, 69, 657]

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值