java 變數(轉)

ba發表於2007-08-15
java 變數(轉)[@more@]變數是Java 程式的一個基本儲存單元。變數由一個識別符號,型別及一個可選初始值的組合定義。此外,所有的變數都有一個作用域,定義變數的可見性,生存期。接下來討論變數的這些元素。

3.8.1 宣告一個變數
在Java 中,所有的變數必須先宣告再使用。基本的變數宣告方法如下:type identifier [ = value][,identifier [= value] ...] ;

type 是Java 的基本型別之一,或類及介面型別的名字(類和介面型別在本書第1部分的後部討論)。識別符號(identifier )是變數的名字,指定一個等號和一個值來初始化變數。請記住初始化表示式必須產生與指定的變數型別一樣(或相容)的變數。宣告指定型別的多個變數時,使用逗號將各變數分開。

以下是幾個各種變數宣告的例子。注意有一些包括了初始化。

int a, b, c; // declares three ints, a, b, and c.int d = 3, e, f = 5; // declares three more ints, initializing // d and f.byte z = 22; // initializes z.
double pi = 3.14159; // declares an approximation of pi.char x = 'x'; // the variable x has the value 'x'.

你選擇的識別符號名稱沒有任何表明它們型別的東西。許多讀者記得FORTRAN 預先規定從I到N的所有識別符號都為整型,其他的識別符號為實型。Java 允許任何合法的識別符號具有任何它們宣告的型別。

3.8.2 動態初始化
儘管前面的例子僅將字面量作為其初始值,Java 也允許在變數宣告時使用任何有效的表示式來動態地初始化變數。

例如,下面的短程式在給定直角三角形兩個直角邊長度的情況下,求其斜邊長度。

// Demonstrate dynamic initialization.
class DynInit {
public static void main(String args[]) {
double a = 3.0, b = 4.0;

// c is dynamically initialized

double c = Math.sqrt(a * a + b * b);

System.out.println("Hypotenuse is " + c);
}
}

這裡,定義了3個區域性變數a,b,c。前兩個變數a和b初始化為常量。然而直角三角形的斜邊c被動態地初始化(使用勾股定理)。該程式用了Java 另外一個內建的方法sqrt(),它是Math類的一個成員,計算它的引數的平方根。這裡關鍵的一點是初始化表示式可以使用任何有效的元素,包括方法呼叫、其他變數或字面量。

3.8.3 變數的作用域和生存期
到目前為止,我們使用的所有變數都是在方法main() 的後面被宣告。然而,Java 允許變數在任何程式塊內被宣告。在第2章中已解釋過了,程式塊被包括在一對大括號中。一個程式塊定義了一個作用域(scope )。這樣,你每次開始一個新塊,你就建立了一個新的作用域。你可能從先前的程式設計經驗知道,一個作用域決定了哪些物件對程式的其他部分是可見的,它也決定了這些物件的生存期。

大多數其他計算機語言定義了兩大類作用域:全域性和區域性。然而,這些傳統型的作用域不適合Java 的嚴格的物件導向的模型。當然將一個變數定義為全域性變數是可行的,但這是例外而不是規則。在Java 中2個主要的作用域是透過類和方法定義的。儘管類的作用域和方法的作用域的區別有點人為劃定。因為類的作用域有若干獨特的特點和屬性,而且這些特點和屬性不能應用到方法定義的作用域,這些差別還是很有意義的。因為有差別,類(以及在其內定義的變數)的作用域將被推遲到第6章當討論類時再來討論。到現在為止,我們將僅僅考慮由方法或在一個方法內定義的作用域。

方法定義的作用域以它的左大括號開始。但是,如果該方法有引數,那麼它們也被包括在該方法的作用域中。本書在第5章將進一步討論引數,因此,現在可認為它們與方法中其他變數的作用域一樣。

作為一個通用規則,在一個作用域中定義的變數對於該作用域外的程式是不可見(即訪問)的。因此,當你在一個作用域中定義一個變數時,你就將該變數區域性化並且保護它不被非授權訪問和/或修改。實際上,作用域規則為封裝提供了基礎。

作用域可以進行巢狀。例如每次當你建立一個程式塊,你就建立了一個新的巢狀的作用域。這樣,外面的作用域包含內部的作用域。這意味著外部作用域定義的物件對於內部作用域中的程式是可見的。但是,反過來就是錯誤的。內部作用域定義的物件對於外部是不可見的。

為理解巢狀作用域的效果,考慮下面的程式:

// Demonstrate block scope.
class Scope {
public static void main(String args[]) {
int x; // known to all code within main

x = 10;
if(x == 10) { // start new scope
int y = 20; // known only to this block

// x and y both known here.
System.out.println("x and y: " + x + " " + y);
x = y * 2;

}
// y = 100; // Error! y not known here

// x is still known here.
System.out.println("x is " + x);
}
}

正如註釋中說明的那樣,在方法main() 的開始定義了變數x,因此它對於main() 中的所有的隨後的程式碼都是可見的。在if程式塊中定義了變數y。因為一個塊定義一個作用域,y 僅僅對在它的塊以內的其他程式碼可見。這就是在它的塊之外的程式行y=100; 被註釋掉的原因。如果你將該行前面的註釋符號去掉,編譯程式時就會出現錯誤,因為變數y在它的程式塊之外是不可見的。在if程式塊中可以使用變數x,因為塊(即一個巢狀作用域)中的程式可以訪問被其包圍作用域中定義的變數。

變數可以在程式塊內的任何地方被宣告,但是隻有在他們被宣告以後才是合法有效的。因此,如果你在一個方法的開始定義了一個變數,那麼它對於在該方法以內的所有程式都是可用的。反之,如果你在一個程式塊的末尾宣告瞭一個變數,它就沒有任何用處,因為沒有程式會訪問它。例如,下面這個程式段就是無效的,因為變數count 在它被定義以前是不能被使用的。

// This fragment is wrong!
count = 100; // oops! cannot use count before it is declared!
int count;

另一個需要記住的重要之處是:變數在其作用域內被建立,離開其作用域時被撤消。
這意味著一個變數一旦離開它的作用域,將不再儲存它的值了。因此,在一個方法內定義的變數在幾次呼叫該方法之間將不再儲存它們的值。同樣,在塊內定義的變數在離開該塊時也將丟棄它的值。因此,一個變數的生存期就被限定在它的作用域中。

如果一個宣告定義包括一個初始化,那麼每次進入宣告它的程式塊時,該變數都要被重新初始化。例如,考慮這個程式:

// Demonstrate lifetime of a variable.
class LifeTime {
public static void main(String args[]) {
int x;

for(x = 0; x < 3; x++) {

int y = -1; // y is initialized each time block is enteredSystem.out.println("y is: " + y); // this always prints -1y = 100;System.out.println("y is now: " + y);

}
}
}

該程式執行的輸出如下:

y is: -1
y is now: 100
y is: -1
y is now: 100
y is: -1
y is now: 100

可以看到,每次進入內部的for迴圈,y都要被重新初始化為-1。即使它隨後被賦值為100,該值還是被丟棄了。

最後一點:儘管程式塊能被巢狀,你不能將內部作用域宣告的變數與其外部作用域宣告的變數重名。在這一點上,Java 不同於C和C++。下面的例子企圖為兩個獨立的變數起同樣的名字。在Java 中,這是不合法的。但在C/C++ 中,它將是合法的,而且2個變數bar將是獨立的。

// This program will not compile
class ScopeErr {

public static void main(String args[]) {
int bar = 1;
{ // creates a new scope

int bar = 2; // Compile-time error – bar already defined!
}
}
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-958149/,如需轉載,請註明出處,否則將追究法律責任。

相關文章