数组特性
明明还有很多其他的办法来保存对象,那么是什么令数组如此特别?
将数组和其他类型的集合区分开来的原因有三:效率,类型,保存基本数据类型的能力
效率:在java中使用数组存储和随机访问对象引用序列是非常高效的,因为数组是简单想线下序列,这使得对元素的访问非常的快,然而这种高速也是有代价的,代价就是数组的大小是固定的且在其生命周期中是不能改变的
类型:
在泛型前,其他的集合类以一种宽泛的方式处理对象(就好像它们没有特定类型一样)。事实上,这些集合类把保存对象的类型默认为 Object,也就是 Java 中所有类的基类。而数组是优于 预泛型 (pre-generic)集合类的,因为你创建一个数组就可以保存特定类型的数据。这意味着你获得了一个编译时的类型检查,而这可以防止你插入错误的数据类型,或者搞错你正在提取的数据类型。
保存基本数据类型的能力: 数组可以保存基本类型数据, 而集合则不能 需要通过拆箱跟装箱
一等对象
不管你使用什么类型的数组,数组中的数据集实际上都是对堆上真正对象的引用,可以显示也可以隐式创建
对象数组和基元数组在使用上是完全相同的。唯一的不同之处就是对象数组存储的是对象的引用,而基元数组则直接存储基本数据类型的值。
数组对象的大小并不是真正存储在数组中对象的个数。然而,当你创建一个数组对象,其引用将自动初始化为 null,因此你可以通过检查特定数组元素中的引用是否为 null 来判断其中是否有对象。基元数组也有类似的机制,比如自动将数值类型初始化为 0,char 型初始化为 (char)0,布尔类型初始化为 false。
多维数组
要创建多维的基元数组,你要用大括号来界定数组中的向量:
// arrays/MultidimensionalPrimitiveArray.java
import java.util.*;
public class MultidimensionalPrimitiveArray {
public static void main(String[] args) {
int[][] a = {
{ 1, 2, 3, },
{ 4, 5, 6, },
};
System.out.println(Arrays.deepToString(a));
}
}
/* Output:
[[1, 2, 3], [4, 5, 6]]
*/。
也可以使用 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(),它为所有不可预见的情况(包括数组的排序区域或使用了比较器)提供了重载版本