Java 数组最佳指南,快收藏让它吃灰

两年前,我甚至写过一篇文章,吐槽数组在 Java 中挺鸡肋的,由于有 List 谁用数组啊,如今想一想那时候的本身好幼稚,好好笑。由于我只看到了表面现象,实际上呢,List 的内部仍然是经过数组实现的,好比说 ArrayList,在它的源码里能够看到下面这些内容:java

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 * will be expanded to DEFAULT_CAPACITY when the first element is added.
 */

transient Object[] elementData; // non-private to simplify nested class access

/**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */

private int size;

数组在 Java 中,必须算是核心,神通常的存在。git

0一、什么是数组

按照 Javadoc 给出的解释,数组是一个对象,它包含了一组固定数量的元素,而且这些元素的类型是相同的。数组会按照索引的方式将元素放在指定的位置上,意味着咱们能够经过索引来访问到这些元素。在 Java 中,索引是从 0 开始的。程序员

咱们能够将数组理解为一个个整齐排列的单元格,每一个单元格里面存放着一个元素。github

数组元素的类型能够是基本数据类型(好比说 int、double),也能够是引用数据类型(好比说 String),包括自定义类型的对象。web

了解了数组的定义后,让咱们来深刻地研究一下数组的用法。面试

在 Java 中,数组的声明方式有两种。json

先来看第一种:数组

int[] anArray;

再来看第二种:微信

int anOtherArray[];

不一样之处就在于中括号的位置,是紧跟类型,仍是放在变量名的后面。前者比后者的使用频率更高一些。app

接下来就该看看怎么初始化数组了,一样有多种方式能够初始化数组,好比说最多见的是:

int[] anArray = new int[10];

使用了 new 关键字,对吧?这就意味着数组的确是一个对象。而后,在方括号中指定了数组的长度,这是必须的。

这时候,数组中的每一个元素都会被初始化为默认值,int 类型的就为 0,Object 类型的就为 null。

另外,还可使用大括号的方式,直接初始化数组中的元素:

int anOtherArray[] = new int[] {12345};

这时候,数组的元素分别是 一、二、三、四、5,索引依次是 0、一、二、三、4。

0二、访问数组

前面提到过,能够经过索引来访问数组的元素,就像下面这样:

anArray[0] = 10;
System.out.println(anArray[0]);

经过数组的变量名,加上中括号,加上元素的索引,就能够访问到数组,经过“=”操做符进行赋值。

若是索引的值超出了数组的界限,就会抛出 ArrayIndexOutOfBoundException,关于这方面的知识,我以前特地写过一篇文章,若是你感兴趣的话,能够跳转过去看看。

为何会发生ArrayIndexOutOfBoundsException

我以为缘由挺有意思的。

既然数组的索引是从 0 开始,那就是到数组的 length - 1 结束,不要使用超出这个范围内的索引访问数组,就不会抛出数组越界的异常了。

0三、遍历数组

当数组的元素很是多的时候,逐个访问数组就太辛苦了,因此须要经过遍历的方式。

第一种,使用 for 循环:

int anOtherArray[] = new int[] {12345};
for (int i = 0; i < anOtherArray.length; i++) {
    System.out.println(anOtherArray[i]);
}

经过 length 属性获取到数组的长度,而后索引从 0 开始遍历,就获得了数组的全部元素。

第二种,使用 for-each 循环:

for (int element : anOtherArray) {
    System.out.println(element);
}

若是不须要关心索引的话(意味着不须要修改数组的某个元素),使用 for-each 遍历更简洁一些。固然,也可使用 while 和 do-while 循环。

0四、可变参数

可变参数用于将任意数量的参数传递给方法:

void varargsMethod(String... varargs) {}

varargsMethod() 方法能够传递任意数量的字符串参数,能够是 0 个或者 N 个,本质上,可变参数就是经过数组实现的,为了证实这一点,咱们能够经过 jad 反编译一下字节码:

public class VarargsDemo
{

    public VarargsDemo()
    
{
    }

    transient void varargsMethod(String as[])
    
{
    }
}

因此咱们其实能够直接将数组做为参数传递给可变参数的方法:

VarargsDemo demo = new VarargsDemo();
String[] anArray = new String[] {"沉默王二""一枚有趣的程序员"};
demo.varargsMethod(anArray);

也能够直接传递多个字符串,经过逗号隔开的方式:

demo.varargsMethod("沉默王二""一枚有趣的程序员");

0五、把数组转成 List

List 封装了不少经常使用的方法,方便咱们对集合进行一些操做,而若是直接操做数组的话,多有不便,所以有时候咱们须要把数组转成 List。

最原始的方式,就是经过遍历数组的方式,一个个将数组添加到 List 中。

int[] anArray = new int[] {12345};

List<Integer> aList = new ArrayList<>();
for (int element : anArray) {
    aList.add(element);
}

更优雅的方式是经过 Arrays 类的 asList() 方法:

List<Integer> aList = Arrays.asList(anArray);

但须要注意的是,该方法返回的 ArrayList 并非 java.util.ArrayList,它实际上是 Arrays 类的一个内部类:

private static class ArrayList<Eextends AbstractList<E>
        implements RandomAccessjava.io.Serializable
{}

若是须要添加元素或者删除元素的话,最好把它转成 java.util.ArrayList

new ArrayList<>(Arrays.asList(anArray));

0六、把数组转成 Stream

Java 8 新增了 Stream 流的概念,这就意味着咱们也能够将数组转成 Stream 进行操做,而不是 List。

String[] anArray = new String[] {"沉默王二""一枚有趣的程序员""好好珍重他"};
Stream<String> aStream = Arrays.stream(anArray);

也能够直接对数组的元素进行剪辑,经过指定索引的方式:

Stream<String> anotherStream = Arrays.stream(anArray, 13);

结果包含"一枚有趣的程序员"和"好好珍重他",1 这个索引位置包括,3 这个索引位置不包括。

0七、数组排序

Arrays 类提供了一个 sort() 方法,能够对数组进行排序。

  • 基本数据类型按照升序排列
  • 实现了 Comparable 接口的对象按照 compareTo() 的排序

来看第一个例子:

int[] anArray = new int[] {52148};
Arrays.sort(anArray);

排序后的结果以下所示:

[12458]

来看第二个例子:

String[] yetAnotherArray = new String[] {"A""E""Z""B""C"};
Arrays.sort(yetAnotherArray, 13,
                Comparator.comparing(String::toString).reversed());

只对 1-3 位置上的元素进行反序,因此结果以下所示:

[A, Z, E, B, C]

0八、数组搜索

有时候,咱们须要从数组中查找某个具体的元素,最直接的方式就是经过遍历的方式:

int[] anArray = new int[] {52148};
for (int i = 0; i < anArray.length; i++) {
    if (anArray[i] == 4) {
        System.out.println("找到了 " + i);
        break;
    }
}

上例中从数组中查询元素 4,找到后经过 break 关键字退出循环。

若是数组提早进行了排序,就可使用二分查找法,这样效率就会更高一些。Arrays.binarySearch() 方法可供咱们使用,它须要传递一个数组,和要查找的元素。

int[] anArray = new int[] {12345};
int index = Arrays.binarySearch(anArray, 4);

0九、总结

除了一维数组,还有二维数组,但说实话,二维数组不太经常使用,这里就再也不介绍了,感兴趣的话,能够尝试打印如下杨辉三角。

这篇文章,咱们介绍了 Java 数组的基本用法和一些高级用法,我想小伙伴们应该已经彻底掌握了。

我是沉默王二,一枚有趣的程序员。若是以为文章对你有点帮助,请微信搜索「 沉默王二 」第一时间阅读。

本文 GitHub 已经收录,有大厂面试完整考点,欢迎 Star。

原创不易,莫要白票,请你为本文点个赞吧,这将是我写做更多优质文章的最强动力。