要点: 

1.Java数组的基本语法;
2.Java数组的静态特性;
3.Java数组的内存分配机制;
4.初始化Java数组的两种方式;
5.初始化基本类型数组的内存分配;
6.初始化应用类型数组的内存分配;
7.数组引用变量和数组对象;
8.何时是数组引用变量,何时是数组对象;
9.数组元素等同于变量;
10.多维数组的内存分配;


      其实Java数组并不是什么很难的知识,如果单从用法的角度来看,数组的用法并不难,只是很多程序员虽然一直在使用Java数组,但他们往往对Java数组的内存分配把握不太准确。下面就Java数组内存分配做一些探讨:
  1.数组初始化
  Java数组是静态的,即当数组初始化之后,该数组的长度是不可变的。Java程序中数组必须经初始化才可以使用。所谓初始化就是为数组对象的元素分配内存空间,并为每个数组元素指定初始值。
数组的初始化有以下两种方式:
①静态初始化:初始化时由程序员显示指定每个元素的初始值,有系统决定长度。
②动态初始化:初始化时程序员只指定数组长度,有系统为数组元素分配初始值。
  不管采用哪种方式初始化Java数组,一旦初始化完成,该数组的长度就不可改变,在Java中允许通过数组的length属性来访问数组的长短。
 
    
    
    
    
  1. public class ArrayTest  
  2. {  
  3.     public static void main(String[] args)   
  4.     {  
  5.         //采用静态初始化方式初始化第一个数组  
  6.         String[] books = new String[]  
  7.         {  
  8.             "Java SE",  
  9.             "Java EE",  
  10.             "Ajax",  
  11.             "XML"  
  12.         };  
  13.         //采用静态初始化的简化形式初始化第二个数组  
  14.         String[] names =   
  15.         {  
  16.             "孙悟空",  
  17.             "猪八戒",  
  18.             "白骨精"  
  19.         };  
  20.         //采用动态初始化的语法初始化第三个数组  
  21.         String[] strArr = new String[5];  
  22.         //访问3个数组的长度  
  23.         System.out.println("第一个数组的长度:" + books.length);  
  24.         System.out.println("第二个数组的长度:" + names.length);  
  25.         System.out.println("第三个数组的长度:" + strArr.length);  
  26.     }  
  27. }  
  这3个数组的长度将会始终不变,程序输出3个数组长度依次为4,3,5.
  前面已经指出,Java语言的数组变量是引用类型的变量,books,names,str这个3个变量以及各自引用的数组在内存中的分配如下图:
Java 数组与内存控制_第1张图片
   从上图可以看出,对静态初始化方式而言,我们是无需指定数组长度,指定该数组的数组元素,由子痛决定该数组的长度即可。例如books数组,为它指定了4个数组元素,那它的长度就是4,对于names数组,为它指定了3个元素,那么它的长度就是3.
   对于8种原生数据类型数组的初始值:
   整数类型(byte,short,int,long),数组元素初始值为0;
   浮点类型(float,double),数组元素初始值为0.0;
   字符类型(char),数组元素初始值为'\u0000';
   布尔类型(boolean),数组元素初始值为false。
   如果数组元素是引用类型(类,接口和数组),则数组元素的初始值为null。
 !!注意:不要同时使用静态初始化和动态初始化,也就是说,不要在进行数组初始化时,即指定数组的长度,也为每个元素分配初始值。
 
  需要指出的是,Java的数组变量是一种引用类型的变量,数组变量并不是数组本身,它只是指向堆内存的数组对象。因此,可以改变一个数组变量所引用的数组,这样可以造成数组长度可变的假象。假设,在上面的程序增加几行代码如下:
 
    
    
    
    
  1. //让books数组变量、strArr数组变量指向names所引用的数组 
  2.         books = names; 
  3.         strArr = names; 
  4.         System.out.println("--------------"); 
  5.         System.out.println("books数组的长度:" + books.length); 
  6.         System.out.println("strArr数组的长度:" + strArr.length); 
  7.         //改变books数组变量所引用的数组的第二个元素值。 
  8.         books[1] = "唐僧"
  9.         System.out.println("names数组的第二个元素是:" + books[1]); 
 上面代码片段中将books,strArr数组变量指向names数组变量所引用的数组,这样做的结果就是books,strArr,names这个3个变量引用了同一个数组对象。此时的3个引用变量和数组对象在内存中分配如下图:

Java 数组与内存控制_第2张图片

   从上图可以看出,此时strArr,names和books数组变量实际上指向了同一个数组对象,而且books数组,strArr数组的长度也变成3了,这样就会造成一种假象:books数组的长度从4变成了3.其实不然,数组对象本身的长度并没有发生改变,改变的是数组变量。 
原来books变量所引用的数组长度依然是4,但不再有任何引用变量指向该数组了,它将会变成垃圾等待GC回收。此时,程序使用books,names和strArr这3个变量将会访问同一个数组对象,所以把books数组的第2个元素赋值为"唐僧"是,names数组的第2个元素的值也会随之改变。 与Java这种静态语言不同的是,JavaScript这种动态语言的数组长度是可以动态改变的,如以下代码:
  1. "text/javascript"
  2.     var arr = []; 
  3.     document.writeln("arr的长度是:" + arr.length+"
    "
    ); 
  4.     //为arr数组的两个元素赋初值 
  5.     arr[2] = 6; 
  6.     arr[4]="李四"
  7.     //再次访问arr数组的长度 
  8.     document.writeln("arr的长度是:" + arr.length+"
    "
    ); 
  9.  
  10.  
2.Java数组一定要初始化吗? 我想对于这个问题,很多人都会拿捏不准吧,我们在很多地方都会看到,在使用Java数组之前必须先初始化数组,也就是为数组元素分配内存空间,并指定初始值。实际上,如果真正掌握了Java数组在内存中的分配机制,那么完全可以换一种方式来初始化数组,或者说数组无需初始化。但是始终要记住:Java的数组变量是引用类型的变量,它并不是数组对象本身,只要让数组变量指向有效的数组对象,在程序中即可使用该数组变量。如下列代码所示:
    
    
    
    
  1. public class ArrayTest3 
  2.     public static void main(String[] args)  
  3.     { 
  4.         //定义、并初始化nums数组 
  5.         int[] nums = new int[]{352012}; 
  6.         //定义一个prices数组变量 
  7.         int[] prices; 
  8.         //让prices数组指向nums所引用的数组 
  9.         prices = nums; 
  10.         for (int i = 0 ; i < prices.length ; i++ ) 
  11.         { 
  12.             System.out.println(prices[i]); 
  13.         } 
  14.         //将prices数组的第3个元素赋值为34 
  15.         prices[2] = 34
  16.         //访问nums数组的第3个元素,将看到输出34. 
  17.         System.out.println("nums数组的第3个元素的值是:" + nums[2]); 
  18.     } 
以上程序定义了prices数组之后,并为对其初始化。当执行int[] prices之后,程序在内存中分配如下图:
Java 数组与内存控制_第3张图片

现在程序中prices数组变量可以正常使用了,因为它指向了有效的数组对象。
!!注意:大部分的时候我们把数组变量和数组对象搞混淆了,数组变量只是一个引用变量(有点类似于C语言里面的指针),通常存放在栈内存中(也可放在堆内存中);而数组对象就是保存在堆内存中的连续内存空间,对数组执行初始化,其实并不是对数组变量执行初始化,而是要对数组对象执行初始化--也就是为该数组对象分配一块连续的内存空间,这块连续内存空间的长度就是数组的长度。虽然上面程序中的prices变量看似没有经过初始化,但执行prices=nums;就会让prices变量指向一个已经执行初始化的数组。
对于Java程序中所有的引用变量,他们都不需要经过所谓的初始化操作,需要进行初始化操作的是该引用变量所引用的对象。