Java 数组

Java 数组

  1. 数组的定义
  2. 数组的初始化
  3. 数组对象
  4. 多维数组
  5. 数组的特殊性
  6. 数组与泛型

 

1.数组的定义

        数组只是相同类型的,用一个标识符名称封装到一起的一个对象序列或基本数据类型数据序列。

        数组是通过方括号下标操作符来定义和使用的。

         定义一个数组有两种格式:

//第一种
int[] a;
//第二种
int a[];

2.数组的初始化

        数组定义完成后,此时拥有的只是对数组的一个引用,并没有给数组对象本身分配任何空间。为了给数组创建相应的存储空间,必须写初始化表达式。对于数组,初始化动作可以出现在代码的任何地方,但是有一种特殊初始化表达式除外。

        数组有三种初始化表达式:     

//第一种
 int[] arr1 = {1,2,3};
//第二种
 int[] arr3 = new int[3];
 Integer[] arr2 = new Integer[3];
//第三种
int[] arr4 = new int[]{5,6,7,};//最后一个逗号是可选的(这个特性使维护长列表变得更容易?)
Integer[] arr5 = new Integer[]{new Integer(12),new Integer(23),new Integer(34)};

        第一种是由一对花括号括起来的值组成,它必须在创建数组的地方出现。此种情况,存储空间的分配将由编译器负责,等价于使用new。

        第二种在初始化时指定数组的大小。基本类型的数组,数组元素会自动初始化为空值(对于数字和字符,就是0,;对于布尔型,是false)。非基本类型数组,如:arr2,此时还只是一个引用数组,数组元素都是 null,把对象赋值给引用初始化进程才算结束。如果忘记了创建对象,并且使用数组中的空引用,就会在运行时产生异常。

        第三种在初始化时为数组元素赋值。

        所有数组都有一个固有成员——length,可以通过它获知数组大小,但不能对其修改。Java数组计数从第0个元素开始,所以能用的最大下标数是length-1。一旦下标越界,就会出现运行时异常。需要注意的是,length是数组的大小,而不是实际保存的元素个数。如arr2 ,引用数组初始化前,可以访问数组的大小,但是无法知道在此数组中确切地有多少元素。

3.数组对象

        数组标识符其实只是一个引用,指向在堆中创建的一个真实对象,这个(数组)对象用以保存指向其他对象的引用。

        “[]”语法是访问数组对象唯一的方式。

        对象数组和基本类型数组在使用上几乎是相同的,唯一的区别就是对象数组保存的是引用,基本类型数组直接保存基本类型的值。

4.多维数组

        数组中构成矩阵的每个向量的值都可以具有任意的长度,这被称为粗糙数组。

        基本类型:   

//二维数组
int[][] a = {{1,2,3},{4,5,6}};
//三维数组
int[][][] b = new int[3][2][6];
int[][][] c = new int[3][][];//在其他地方初始化二维和三维数组。
for(int i = 0; i < c.length; i++){
  c[i] = new int[4][];
  for(int j = 0; j < c[i].length; j++){
    c[i][j] = new int[5];
  }
}

        非基本类型,创建方式与基本类型差不多,就是需要给每个元素赋值,避免空引用产生运行时异常。

5.数组的特殊性

        数组与其他种类容器之间的区别有三方面:效率类型和保存基本类型的能力。   

        效率:在Java中,数组是一种效率最高的存储和随机访问对象引用序列的方式。元素访问速度快,但是代价是数组对象的大小被固定,并且在其生命周期中不可改变。ArrayList可通过创建一个新实例,然后把旧实例中所有的引用移到新的实例中,从而实现更多空间的自动分配。但是这种弹性需要开销,因此,ArrayList 的效率比数组低的多。

        类型:在泛型之前,其他容器在处理对象时,都将它们视作没有任何具体类型的容器,即都当作Java中所有类的根类Object 处理。数组之所以优于泛型之前的容器,就是因为可以创建一个数组去持有某种具体类型。这意味着你可以通过编译期检查,来防止插入错误类型和抽取不当类型,虽然运行时也会检查出错误,但是此种方式更加优雅。

        基本类型:数组可以持有基本类型,而泛型之前的容器则不可能。有了泛型后,容器就可以指定检查它们所持有对象的类型,并且有了自动包装机制,容器看起来能够持有基本类型。

6.数组与泛型

        通常,数组与泛型不能很好地结合,不能实例化具有参数化类型的数组。编译期确实不允许实例化数组对象,但是允许创建对这种数组的引用。尽管不能创建实际的持有泛型的数组对象但是可以创建非泛型的数组,然后将其转型。

List<String>[] list = new List<String>[33];//编译期检查不通过
List<String>[] list;//编译期检查通过

List[] la = new List[5];//非泛型数组
list = (List<String>[]) la;//转型
list[0] = new ArrayList<String>();
list[1] = new ArrayList<Integer>();//编译期检查不通过

        事实上,泛型容器总是比泛型数组更好的选择,了解即可。

 

参考资料:

    《Java编程思想》