程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> java的數組初始化

java的數組初始化

編輯:關於JAVA

在C中初始化數組極易出錯,而且相當麻煩。C++通過“集合初始化”使其更安全(注釋⑥)。Java則沒有象C++那樣的“集合”概念,因為Java中的所有東西都是對象。但它確實有自己的數組,通過數組初始化來提供支持。
數組代表一系列對象或者基本數據類型,所有相同的類型都封裝到一起——采用一個統一的標識符名稱。數組的定義和使用是通過方括號索引運算符進行的([])。為定義一個數組,只需在類型名後簡單地跟隨一對空方括號即可:
int[] al;
也可以將方括號置於標識符後面,獲得完全一致的結果:
int al[];
這種格式與C和C++程序員習慣的格式是一致的。然而,最“通順”的也許還是前一種語法,因為它指出類型是“一個int數組”。本書將沿用那種格式。
編譯器不允許我們告訴它一個數組有多大。這樣便使我們回到了“句柄”的問題上。此時,我們擁有的一切就是指向數組的一個句柄,而且尚未給數組分配任何空間。為了給數組創建相應的存儲空間,必須編寫一個初始化表達式。對於數組,初始化工作可在代碼的任何地方出現,但也可以使用一種特殊的初始化表達式,它必須在數組創建的地方出現。這種特殊的初始化是一系列由花括號封閉起來的值。存儲空間的分配(等價於使用new)將由編譯器在這種情況下進行。例如:
int[] a1 = { 1, 2, 3, 4, 5 };
那麼為什麼還要定義一個沒有數組的數組句柄呢?
int[] a2;
事實上在Java中,可將一個數組分配給另一個,所以能使用下述語句:
a2 = a1;
我們真正准備做的是復制一個句柄,就象下面演示的那樣:

 

//: Arrays.java
// Arrays of primitives.

public class Arrays {
  public static void main(String[] args) {
    int[] a1 = { 1, 2, 3, 4, 5 };
    int[] a2;
    a2 = a1;
    for(int i = 0; i < a2.length; i++)
      a2[i]++;
    for(int i = 0; i < a1.length; i++)
      prt("a1[" + i + "] = " + a1[i]);
  }
  static void prt(String s) {
    System.out.println(s);
  }
} ///:~


大家看到a1獲得了一個初始值,而a2沒有;a2將在以後賦值——這種情況下是賦給另一個數組。
這裡也出現了一些新東西:所有數組都有一個本質成員(無論它們是對象數組還是基本類型數組),可對其進行查詢——但不是改變,從而獲知數組內包含了多少個元素。這個成員就是length。與C和C++類似,由於Java數組從元素0開始計數,所以能索引的最大元素編號是“length-1”。如超出邊界,C和C++會“默默”地接受,並允許我們胡亂使用自己的內存,這正是許多程序錯誤的根源。然而,Java可保留我們這受這一問題的損害,方法是一旦超過邊界,就生成一個運行期錯誤(即一個“違例”,這是第9章的主題)。當然,由於需要檢查每個數組的訪問,所以會消耗一定的時間和多余的代碼量,而且沒有辦法把它關閉。這意味著數組訪問可能成為程序效率低下的重要原因——如果它們在關鍵的場合進行。但考慮到因特網訪問的安全,以及程序員的編程效率,Java設計人員還是應該把它看作是值得的。
程序編寫期間,如果不知道在自己的數組裡需要多少元素,那麼又該怎麼辦呢?此時,只需簡單地用new在數組裡創建元素。在這裡,即使准備創建的是一個基本數據類型的數組,new也能正常地工作(new不會創建非數組的基本類型):

 

//: ArrayNew.java
// Creating arrays with new.
import java.util.*;

public class ArrayNew {
  static Random rand = new Random();
  static int pRand(int mod) {
    return Math.abs(rand.nextInt()) % mod + 1;
  }
  public static void main(String[] args) {
    int[] a;
    a = new int[pRand(20)];
    prt("length of a = " + a.length);
    for(int i = 0; i < a.length; i++)
      prt("a[" + i + "] = " + a[i]);
  }
  static void prt(String s) {
    System.out.println(s);
  }
} ///:~


由於數組的大小是隨機決定的(使用早先定義的pRand()方法),所以非常明顯,數組的創建實際是在運行期間進行的。除此以外,從這個程序的輸出中,大家可看到基本數據類型的數組元素會自動初始化成“空”值(對於數值,空值就是零;對於char,它是null;而對於boolean,它卻是false)。
當然,數組可能已在相同的語句中定義和初始化了,如下所示:
int[] a = new int[pRand(20)];
若操作的是一個非基本類型對象的數組,那麼無論如何都要使用new。在這裡,我們會再一次遇到句柄問題,因為我們創建的是一個句柄數組。請大家觀察封裝器類型Integer,它是一個類,而非基本數據類型:

 

//: ArrayClassObj.java
// Creating an array of non-primitive objects.
import java.util.*;

public class ArrayClassObj {
  static Random rand = new Random();
  static int pRand(int mod) {
    return Math.abs(rand.nextInt()) % mod + 1;
  }
  public static void main(String[] args) {
    Integer[] a = new Integer[pRand(20)];
    prt("length of a = " + a.length);
    for(int i = 0; i < a.length; i++) {
      a[i] = new Integer(pRand(500));
      prt("a[" + i + "] = " + a[i]);
    }
  }
  static void prt(String s) {
    System.out.println(s);
  }
} ///:~


在這兒,甚至在new調用後才開始創建數組:
Integer[] a = new Integer[pRand(20)];
它只是一個句柄數組,而且除非通過創建一個新的Integer對象,從而初始化了對象句柄,否則初始化進程不會結束:
a[i] = new Integer(pRand(500));
但若忘記創建對象,就會在運行期試圖讀取空數組位置時獲得一個“違例”錯誤。
下面讓我們看看打印語句中String對象的構成情況。大家可看到指向Integer對象的句柄會自動轉換,從而產生一個String,它代表著位於對象內部的值。
亦可用花括號封閉列表來初始化對象數組。可采用兩種形式,第一種是Java 1.0允許的唯一形式。第二種(等價)形式自Java 1.1才開始提供支持:

 

//: ArrayInit.java
// Array initialization

public class ArrayInit {
  public static void main(String[] args) {
    Integer[] a = {
      new Integer(1),
      new Integer(2),
      new Integer(3),
    };

    // Java 1.1 only:
    Integer[] b = new Integer[] {
      new Integer(1),
      new Integer(2),
      new Integer(3),
    };
  }
} ///:~


這種做法大多數時候都很有用,但限制也是最大的,因為數組的大小是在編譯期間決定的。初始化列表的最後一個逗號是可選的(這一特性使長列表的維護變得更加容易)。
數組初始化的第二種形式(Java 1.1開始支持)提供了一種更簡便的語法,可創建和調用方法,獲得與C的“變量參數列表”(C通常把它簡稱為“變參表”)一致的效果。這些效果包括未知的參數(自變量)數量以及未知的類型(如果這樣選擇的話)。由於所有類最終都是從通用的根類Object中繼承的,所以能創建一個方法,令其獲取一個Object數組,並象下面這樣調用它:

 

//: VarArgs.java
// Using the Java 1.1 array syntax to create
// variable argument lists

class A { int i; }

public class VarArgs {
  static void f(Object[] x) {
    for(int i = 0; i < x.length; i++)
      System.out.println(x[i]);
  }
  public static void main(String[] args) {
    f(new Object[] { 
        new Integer(47), new VarArgs(), 
        new Float(3.14), new Double(11.11) });
    f(new Object[] {"one", "two", "three" });
    f(new Object[] {new A(), new A(), new A()});
  }
} ///:~


此時,我們對這些未知的對象並不能采取太多的操作,而且這個程序利用自動String轉換對每個Object做一些有用的事情。在第11章(運行期類型標識或RTTI),大家還會學習如何調查這類對象的准確類型,使自己能對它們做一些有趣的事情。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved