数组特性

明明还有很多其他的办法来保存对象,那么是什么令数组如此特别?
将数组和其他类型的集合区分开来的原因有三:效率,类型,保存基本数据类型的能力
效率:在java中使用数组存储和随机访问对象引用序列是非常高效的,因为数组是简单想线下序列,这使得对元素的访问非常的快,然而这种高速也是有代价的,代价就是数组的大小是固定的且在其生命周期中是不能改变的

类型:
在泛型前,其他的集合类以一种宽泛的方式处理对象(就好像它们没有特定类型一样)。事实上,这些集合类把保存对象的类型默认为 Object,也就是 Java 中所有类的基类。而数组是优于 预泛型 (pre-generic)集合类的,因为你创建一个数组就可以保存特定类型的数据。这意味着你获得了一个编译时的类型检查,而这可以防止你插入错误的数据类型,或者搞错你正在提取的数据类型。

保存基本数据类型的能力: 数组可以保存基本类型数据, 而集合则不能 需要通过拆箱跟装箱

一等对象

不管你使用什么类型的数组,数组中的数据集实际上都是对堆上真正对象的引用,可以显示也可以隐式创建
对象数组和基元数组在使用上是完全相同的。唯一的不同之处就是对象数组存储的是对象的引用,而基元数组则直接存储基本数据类型的值。

数组对象的大小并不是真正存储在数组中对象的个数。然而,当你创建一个数组对象,其引用将自动初始化为 null,因此你可以通过检查特定数组元素中的引用是否为 null 来判断其中是否有对象。基元数组也有类似的机制,比如自动将数值类型初始化为 0,char 型初始化为 (char)0,布尔类型初始化为 false

垃圾收集器会清理你用完的数组,你需要的数组则会保留。

多维数组

要创建多维的基元数组,你要用大括号来界定数组中的向量:

  1. // arrays/MultidimensionalPrimitiveArray.java
  2. import java.util.*;
  3. public class MultidimensionalPrimitiveArray {
  4. public static void main(String[] args) {
  5. int[][] a = {
  6. { 1, 2, 3, },
  7. { 4, 5, 6, },
  8. };
  9. System.out.println(Arrays.deepToString(a));
  10. }
  11. }
  12. /* Output:
  13. [[1, 2, 3], [4, 5, 6]]
  14. */

也可以使用 new 分配数组。这是一个使用 new 表达式分配的三维数组

// arrays/ThreeDWithNew.java
import java.util.*;

public class ThreeDWithNew {
  public static void main(String[] args) {
    // 3-D array with fixed length:
    int[][][] a = new int[2][2][4];
    System.out.println(Arrays.deepToString(a));
  }
}
/* Output:
[[[0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0,
0]]]
*/

Arrays的fill方法

Java 标准库 Arrays 类包括一个普通的 fill() 方法,该方法将单个值复制到整个数组,或者在对象数组的情况下,将相同的引用复制到整个数组

// arrays/FillingArrays.java
// Using Arrays.fill()
import java.util.*;
import static onjava.ArrayShow.*;

public class FillingArrays {
  public static void main(String[] args) {
    int size = 6;
    boolean[] a1 = new boolean[size];
    byte[] a2 = new byte[size];
    char[] a3 = new char[size];
    short[] a4 = new short[size];
    int[] a5 = new int[size];
    long[] a6 = new long[size];
    float[] a7 = new float[size];
    double[] a8 = new double[size];
    String[] a9 = new String[size];
    Arrays.fill(a1, true);
    show("a1", a1);
    Arrays.fill(a2, (byte)11);
    show("a2", a2);
    Arrays.fill(a3, 'x');
    show("a3", a3);
    Arrays.fill(a4, (short)17);
    show("a4", a4);
    Arrays.fill(a5, 19);
    show("a5", a5);
    Arrays.fill(a6, 23);
    show("a6", a6);
    Arrays.fill(a7, 29);
    show("a7", a7);
    Arrays.fill(a8, 47);
    show("a8", a8);
    Arrays.fill(a9, "Hello");
    show("a9", a9);
    // Manipulating ranges:
    Arrays.fill(a9, 3, 5, "World");
    show("a9", a9);
  }
}gedan
/* Output:
a1: [true, true, true, true, true, true]
a2: [11, 11, 11, 11, 11, 11]
a3: [x, x, x, x, x, x]
a4: [17, 17, 17, 17, 17, 17]
a5: [19, 19, 19, 19, 19, 19]
a6: [23, 23, 23, 23, 23, 23]
a7: [29.0, 29.0, 29.0, 29.0, 29.0, 29.0]
a8: [47.0, 47.0, 47.0, 47.0, 47.0, 47.0]
a9: [Hello, Hello, Hello, Hello, Hello, Hello]
a9: [Hello, Hello, Hello, World, World, Hello]
*/

你既可以填充整个数组,也可以像最后两个语句所示,填充一系列的元素。但是由于你只能使用单个值调用 Arrays.fill() ,因此结果并非特别有用。

Arrays工具类

概述:

  • asList(): 获取任何序列或数组,并将其转换为一个 列表集合 (集合章节介绍了此方法)。
  • copyOf():以新的长度创建现有数组的新副本。
  • copyOfRange():创建现有数组的一部分的新副本。
  • equals():比较两个数组是否相等。
  • deepEquals():多维数组的相等性比较。
  • stream():生成数组元素的流。
  • hashCode():生成数组的哈希值(您将在附录中了解这意味着什么:理解equals()和hashCode())。
  • deepHashCode(): 多维数组的哈希值。
  • sort():排序数组
  • parallelSort():对数组进行并行排序,以提高速度。
  • binarySearch():在已排序的数组中查找元素。
  • parallelPrefix():使用提供的函数并行累积(以获得速度)。基本上,就是数组的reduce()。
  • spliterator():从数组中产生一个Spliterator;这是本书没有涉及到的流的高级部分。
  • toString():为数组生成一个字符串表示。你在整个章节中经常看到这种用法。
  • deepToString():为多维数组生成一个字符串。你在整个章节中经常看到这种用法。对于所有基本类型和对象,所有这些方法都是重载的。

    数组拷贝

    与使用for循环手工执行复制相比,copyOf()copyOfRange() 复制数组要快得多。这些方法被重载以处理所有类型。

数组比较

数组 提供了 equals() 来比较一维数组,以及 deepEquals() 来比较多维数组。对于所有原生类型和对象,这些方法都是重载的。
数组相等的含义:数组必须有相同数量的元素,并且每个元素必须与另一个数组中的对应元素相等,对每个元素使用 equals()(对于原生类型,使用原生类型的包装类的 equals() 方法;

Arrays.sort 的使用

注意字符串排序算法中的输出。它是字典式的,所以它把所有以大写字母开头的单词放在前面,然后是所有以小写字母开头的单词。

并行排序

如果排序性能是一个问题,那么可以使用 Java 8 parallelSort(),它为所有不可预见的情况(包括数组的排序区域或使用了比较器)提供了重载版本