- Java從入門到精通(第2版)
- 龍馬高新教育策劃 魔樂科技(MLDN)軟件實(shí)訓(xùn)中心編著 張玉宏主編
- 400字
- 2019-01-02 04:58:49
第4章 最常用的編程元素—常量與變量
本章視頻教學(xué)錄像:1 小時(shí)22分鐘
Java語言強(qiáng)大靈活,與C++語言語法有很多相似之處。要想熟練使用Java語言,就必須從了解Java語言基礎(chǔ)開始,“千里之行,始于足下”。本章講解Java中常量和變量的聲明與應(yīng)用、變量的命名規(guī)則以及作用范圍等。本章內(nèi)容是接下來章節(jié)的基礎(chǔ),初學(xué)者應(yīng)該認(rèn)真學(xué)習(xí)。
本章要點(diǎn)(已掌握的在方框中打鉤)
□ 掌握常量和變量的聲明方法
□ 掌握變量的命名規(guī)則
□ 掌握變量的作用范圍
□ 掌握常量和變量的應(yīng)用技巧
4.1 常量
本節(jié)視頻教學(xué)錄像:15分鐘
一般來說,所有的程序設(shè)計(jì)語言都需要定義常量(Constant)。在Java開發(fā)語言平臺(tái)中也不例外。所謂常量,就是固定不變的量,其一旦被定義并賦初值后,它的值就不能再被改變。
4.1.1 聲明常量
在Java語言中,主要是利用關(guān)鍵字final來進(jìn)行定義常量的,聲明常量的語法為:
final數(shù)據(jù)類型 常量名稱[=值];
常量名稱通常使用大寫字母,例如PI、YEAR等,但這并不是硬性要求,僅是一個(gè)習(xí)慣而已,在這里建議讀者養(yǎng)成良好的編碼習(xí)慣。值得注意的是,雖然Java中有關(guān)鍵詞const,但目前并沒有被Java正式啟用。const是C++中定義常量的關(guān)鍵字。
常量標(biāo)識(shí)符和前面講到的變量標(biāo)識(shí)符規(guī)定一樣,可由任意順序的大小寫字母、數(shù)字、下劃線(_)和美元符號(hào)($)等組成,標(biāo)識(shí)符不能以數(shù)字開頭,亦不能是Java中的保留關(guān)鍵字。
此外,在定義常量時(shí),需要注意如下兩點(diǎn)。
⑴ 必須要在常量聲明時(shí)對(duì)其進(jìn)行初始化,否則會(huì)出現(xiàn)編譯錯(cuò)誤。常量一旦初始化后,就無法再次對(duì)這個(gè)常量進(jìn)行賦值。
⑵ final關(guān)鍵字不僅可用來修飾基本數(shù)據(jù)類型的常量,還可以用來修飾后續(xù)章節(jié)講到的“對(duì)象引用”或者方法。
4.1.2 常量應(yīng)用示例
當(dāng)常量作為一個(gè)類的成員變量時(shí),需要給常量賦初值,否則編譯器會(huì)“不答應(yīng)”的。
【范例4-1】 聲明一個(gè)常量用于成員變量(TestFinal4-1.java)。
01 //@Description:Java中定義常量 02 public class TestFinal4_1 03 { 04 static final int YEAR=365; //定義一個(gè)靜態(tài)常量 05 public static void main(String[]args) 06 { 07 System.out.println("兩年是:"+2*YEAR+"天"); 08 } 09 }
【運(yùn)行結(jié)果】
保存并運(yùn)行程序,結(jié)果如下圖所示。

提示
static final int YEAR = 365,這一句前的static是Java的關(guān)鍵字。只有加了static才能被main函數(shù)引用。有關(guān)static關(guān)鍵字使用的知識(shí)將在第14章第7節(jié)中進(jìn)行詳細(xì)介紹。
4.2 變量
本節(jié)視頻教學(xué)錄像:42分鐘
變量是利用聲明的方式,將內(nèi)存中的某個(gè)內(nèi)存塊保留下來以供程序使用,其內(nèi)的值是可變的。可聲明的變量數(shù)據(jù)類型有整型(int)、字符型(char)、浮點(diǎn)型(float或double),也可以是其他的數(shù)據(jù)類型(如用戶自定義的數(shù)據(jù)類型——類)。在英語中,數(shù)據(jù)類型的“type”和類的“class”本身就是一組同義詞,所以二者在地位上是對(duì)等的。
4.2.1 聲明變量
聲明變量有兩個(gè)作用。
⑴ 指定在內(nèi)存中分配空間大小。
變量在聲明時(shí),可以同時(shí)給予初始化(即賦予初始值)。
⑵ 規(guī)定這個(gè)變量所能接受的運(yùn)算。
例如,整數(shù)數(shù)據(jù)類型int只能接受加、減、乘、除 (+,-,*,/)等運(yùn)算符。
雖然,我們還沒有正式講到“類”的概念,其實(shí)在本質(zhì)上,“類”就是在諸如整型、浮點(diǎn)型等基本數(shù)據(jù)“不夠用”時(shí),用戶自定義的一種數(shù)據(jù)類型(User-Difined Type,UDT)。那么,如果張三是屬于“Human”這個(gè)類所定義的變量,在一般情況,他就不能使用另一個(gè)類“Cow”中的“吃草”——EatGrass()這個(gè)操作。也就是說,正是有了類型的區(qū)分,各個(gè)不同類型的變量就可以根據(jù)其類型所規(guī)定的操作范圍“各司其職”。
因此,任何一個(gè)變量在聲明時(shí)必須給予它一個(gè)類型,而在相同的作用范圍內(nèi),變量還必須有個(gè)獨(dú)一無二的名稱,如下圖所示。

下面先來看一個(gè)簡(jiǎn)單的實(shí)例,以便了解Java里變量與常量之間的關(guān)系。在下面的程序里聲明了兩種Java經(jīng)常使用到的變量,分別為整型變量num與字符變量ch。為它們賦值后,再把它們的值分別在控制臺(tái)上顯示。
【范例4-2】聲明兩個(gè)變量,一個(gè)是整型,另一個(gè)是字符型(TestJavaIntChar4 2.java)。
01 //Description:聲明整型變量和字符變量 02 public class TestJavaIntChar4_2 03 { 04 public static void main(String[]args) 05 { 06 int num=3;//聲明一整型變量num,賦值為3 07 char ch='z';//聲明一字符變量ch,賦值為z11 08 System.out.println(num+"是整數(shù)!"); //輸出num的值 09 System.out.println(ch+"是字符!"); //輸出ch的值14 10 } 11 }
【運(yùn)行結(jié)果】
保存并運(yùn)行程序,結(jié)果如下圖所示。

【范例分析】
在TestJavaIntChar4_2類中,第06和07行分別聲明了整型(int)和字符型(char)的變量num與ch,并分別將常量3與字符“z”賦值給這兩個(gè)變量,最后將它們顯示在控制臺(tái)上(第8和9行)。
聲明一個(gè)變量時(shí),編譯程序會(huì)在內(nèi)存里開辟一塊足以容納此變量的內(nèi)存空間給它。不管該變量的值如何改變,都永遠(yuǎn)使用相同的內(nèi)存空間。因此,善用變量是一種節(jié)省內(nèi)存的方式。
常量是不同于變量的一種類型,它的值是固定的,例如整數(shù)常量、字符串常量。通常給變量賦值時(shí),會(huì)將常量賦值給變量。如在類TestJavaIntChar4_2中,第06行num是整型變量,而3則是常量。此行的作用是聲明num為整型變量,并把常量3這個(gè)值賦給它。與此相同,第07行聲明了一個(gè)字符變量ch,并將字符常量“z”賦給它。
當(dāng)然,在程序編寫的過程中,可以為變量重新賦值,也可以用已聲明過的變量將其賦值,如下所示。
01 int num=3; //聲明一整型變量num,賦值為3 02 int newNum=8; //聲明一整型變量newNum,賦值為8 03 num=newNum; //將變量newNum的值賦給變量num
作為Java的初學(xué)者,對(duì)于上述三個(gè)語句容易有兩個(gè)地方犯錯(cuò)。
⑴變量num最終的值是什么?是3還是8?其實(shí)讀者只需記住一點(diǎn),變量的值永遠(yuǎn)以最后更新的值為準(zhǔn),所以num的值等于newNum的值,而newNum的值為8。
⑵第03行,初學(xué)者容易錯(cuò)誤地寫成。
03 int num=newNum;
事實(shí)上,int num = newNum;這一個(gè)語句有兩層操作,一是“int num”,它要求編譯器在內(nèi)存空間分配一塊區(qū)域來存儲(chǔ)一個(gè)整型數(shù)據(jù),為了方便用戶訪問這塊內(nèi)存區(qū)域,就給這塊內(nèi)存區(qū)域取個(gè)標(biāo)識(shí)叫num;二是為這個(gè)名叫num的內(nèi)存區(qū)域賦值——將另外一個(gè)變量newNum的值賦給num,即:num =newNum。這樣一來,在整個(gè)作用域就有兩個(gè)變量名叫num(第01行和03行)。如同一個(gè)教室里若有兩個(gè)同名同姓的學(xué)生,老師很難通過名字來區(qū)分這兩位學(xué)生。類似的,編譯器在同一個(gè)作用域范圍內(nèi)也無法區(qū)分兩個(gè)“同名同姓”的變量,于是就產(chǎn)生了二義性,這樣就會(huì)產(chǎn)生編譯錯(cuò)誤。正確的做法是,要么去掉int num = newNum語句前面的變量聲明標(biāo)志int,要么將第03行的num取個(gè)新的名稱。
4.2.2 變量的命名規(guī)則
變量也是一種標(biāo)識(shí)符,所以它也遵循標(biāo)識(shí)符的命名規(guī)則。
⑴ 變量名可由任意順序的大小寫字母、數(shù)字、下劃線(_)和美元符號(hào)($)等組成。
⑵ 變量名不能以數(shù)字開頭。
⑶ 變量名不能是Java中的保留關(guān)鍵字。
4.2.3 變量的作用范圍
變量是有作用范圍(Scope)的,作用范圍有時(shí)也稱作用域。一旦超出變量的作用范圍,就無法再使用這個(gè)變量。例如張三在A村很知名。你打聽A村的張三,人人都知道,可你到B村打聽,就沒人知道。也就是說,在B村張三是無法訪問的。就算碰巧B村也有個(gè)叫張三的,但此張三已經(jīng)非彼張三了。這里的A村和B村就是張三的“作用(活動(dòng))范圍” 。
按作用范圍進(jìn)行劃分,變量分為成員變量和局部變量。
1. 成員變量
在類體中定義的變量為成員變量。它的作用范圍為整個(gè)類,也就是說在這個(gè)類中都可以訪問到定義的這個(gè)成員變量。
【范例4-3】 探討成員變量的作用范圍(TestMemVar4 3.java)。
01 //@Description:定義類中的成員變量 02 public class TestMemVar4_3 03 { 04 static int var=1; //定義一個(gè)成員變量 05 06 public static void main(String[]args) 06 { 07 System.out.println("成員變量var的值是:"+var); 08 } 09 }
【運(yùn)行結(jié)果】
保存并運(yùn)行程序,結(jié)果如下圖所示。

2. 局部變量
在一個(gè)函數(shù)(或稱方法)或函數(shù)內(nèi)代碼塊(code block)中定義的變量稱為局部變量,局部變量在函數(shù)或代碼塊被執(zhí)行時(shí)創(chuàng)建,在函數(shù)或代碼塊結(jié)束時(shí)被銷毀。局部變量在進(jìn)行取值操作前必須被初始化或賦值操作,否則會(huì)出現(xiàn)編譯錯(cuò)誤!
Java存在塊級(jí)作用域,在程序中任意大括號(hào)包裝的代碼塊中定義的變量,它的生命僅僅存在于程序運(yùn)行該代碼塊時(shí)。比如在for(或while)循環(huán)體里、方法或方法的參數(shù)列表里等。在循環(huán)里聲明的變量只要跳出循環(huán),這個(gè)變量便不能再使用。同樣,方法或方法的參數(shù)列表里定義的局部變量,當(dāng)跳出方法體(method body)之外,該變量也不能使用了。下面用一個(gè)范例來說明局部變量的使用方法。
【范例4-4】 局部變量的使用(TestLocalVar4 4.java)。
01 //@Description:局部變量的作用域 02 03 public class TestLocalVar4_4 04 { 05 public static void main(String[]args) //main方法參數(shù)列表定義的局部變量args 06 { 07 int sum=0; //main方法體內(nèi)定義的局部變量sum 08 for(int i=1;i<=5;i++) //for循環(huán)體內(nèi)定義的局部變量i 09 { 10 sum=sum+i; 11 System.out.println("i="+i+",sum="+sum); 12 } 13 } 14 }
【運(yùn)行結(jié)果】
保存并運(yùn)行程序,結(jié)果如下圖所示。

【代碼詳解】
在范例4-4這個(gè)小例子中,就有3種定義局部變量的方式。在第05行,在靜態(tài)方法main參數(shù)列表中定義的局部變量args,它的作用范圍就是整個(gè)main方法體:以06行的左花括號(hào)“{”開始,以13行的“} ”結(jié)束。args主要用途是從命令行讀取輸入的參數(shù),后續(xù)的章節(jié)我們會(huì)講到這方面的知識(shí)點(diǎn)。
在第07行,在main方法體內(nèi),定義了局部變量sum。它的作用范圍從當(dāng)前行(07行)到以第13行的“}”為止。
在第08行,把局部變量i聲明在for循環(huán)里,它的有效范圍僅在for循環(huán)內(nèi)(09~12行),只要一離開這個(gè)循環(huán),變量i便無法使用。相對(duì)而言,變量sum的有效作用范圍從第07行開始,到第13行結(jié)束,for循環(huán)也屬于變量sum的有效范圍,因此sum在for循環(huán)內(nèi)也是可用的。
下面我們?cè)儆靡粋€(gè)案例說明局部變量在塊(block)作用范圍的應(yīng)用。
【范例4-5】 變量的綜合應(yīng)用(TestLocalVar4 5.java)。
01 //@Description:變量的綜合使用 02 public class TestLocalVar4_5 03 { 04 public static void main(String[]args) 05 { 06 int outer=1; 07 { 08 int inner=2; 09 System.out.println("inner="+inner); 10 System.out.println("outer="+outer); 11 } 12 //System.out.println("inner="+inner); 13 int inner=3; 14 System.out.println("inner="+inner); 15 System.out.println("outer="+outer); 16 17 System.out.println("In class level,x="+x); 18 } 19 static int x=10; 20 }
【運(yùn)行結(jié)果】
保存并運(yùn)行程序,結(jié)果如下圖所示。

【代碼詳解】
塊(block)作用范圍除了用for(while)循環(huán)或方法體的左右花括號(hào){}來界定外,還可以直接用花括號(hào){}來定義“塊”,如第09行至第13行,在這個(gè)塊內(nèi),inner等于2,出了第13行,就是出了它的作用范圍,也就是說出了這個(gè)塊,inner生命周期就終結(jié)了。因此,如果我們?nèi)∠?4行的注釋符號(hào)“//”,會(huì)出現(xiàn)編譯錯(cuò)誤,因?yàn)檫@行的System.out.println()方法不認(rèn)識(shí)這個(gè)“陌生”的名叫inner的變量。
第14行,我們重新定義并初始化了一個(gè)新的inner,注意這個(gè)inner和第09行~13行塊內(nèi)的inner完全沒有任何關(guān)系。因此第16行,可以正常輸出,但輸出的值為3。讀者再回顧一下本小節(jié)一開始的比喻,第09~13行中的局部變量inner,就如同我們前面的比喻,那個(gè)A村的“張三”,雖然他在A村很知名,人人都知道他,但是出了他的“勢(shì)力(作用)范圍”,就沒有人認(rèn)識(shí)他。而第14行出現(xiàn)同名變量inner,他就是B村的張三,他的“勢(shì)力(作用)范圍”是第14~20行。A村的張三和B村的張三沒有任何關(guān)系,他們不過是碰巧重名罷了。第09行和第14行定義的變量inner也是這樣,它們之間沒有任何聯(lián)系,不過是碰巧重名而已。
一般來說,所有變量都遵循“先聲明,后使用”的原則。這是因?yàn)樽兞恐挥小跋嚷暶鳌?,它才能在?nèi)存中“存在”,之后才能被其他方法所“感知”并使用,但是存在于類中成員變量(不再任何方法內(nèi)),它們的作用范圍是整個(gè)類范圍(class level),在編譯器的“內(nèi)部協(xié)調(diào)”下,變量只要作為類中的數(shù)據(jù)成員被聲明了,就可以在類內(nèi)部的任何地方使用,無需滿足“先聲明,后使用”的原則。比如類成員變量x是在第19行聲明的,由于它的作用范圍是整個(gè)TestLocalVar4_5類,所以在第19行也可以正確輸出x的值。
4.3 高手點(diǎn)撥
本節(jié)視頻教學(xué)錄像:7分鐘
1. Java中作用范圍是禁止嵌套的,而在C/C++中則是允許的
在Java中,在方法(函數(shù))內(nèi)定義的變量,其作用范圍(包括方法的參數(shù))是從它定義的地方開始,到它所作用范圍終結(jié)的位置處結(jié)束。如在方法的開始處定義了一個(gè)變量i,那么直到該方法結(jié)束處,都不能再定義另一個(gè)同名變量i。再如,如果在一個(gè)for循環(huán)體中定義了變量i,那么在這個(gè)for循環(huán)內(nèi)不能再有同名變量,但出了for循環(huán)之后,是可以再次定義的。這就是作用域不能嵌套的意思。
而在C/C++中,作用域可以嵌套,甚至無限制地嵌套下去,這里每對(duì)大括號(hào)之間就是一個(gè)獨(dú)立的作用域,內(nèi)嵌套的同名變量覆蓋外遷套的同名變量。如下表所示。

2. Java中類與方法中變量作用域可以嵌套
在Java中,類與方法之間作用域是可以嵌套的,可以把整個(gè)類看做一個(gè)大的作用域,它定義的字段(或稱數(shù)據(jù)成員)可被方法中的同名字段所屏蔽,其行為類似于上表左側(cè)所示的C/C++的作用域嵌套。下面的例子說明了這個(gè)情況。
01 public class VarScope 02 { 03 public static void main(String args[]) 04 { 05 int x=1; 06 System.out.println("x="+x); 07 } 08 private int x; 09 }
本例中的第5行所定義的x,作為類VarScope的數(shù)據(jù)成員,它的作用域是整個(gè)類,即從第02行到第09行之間,這個(gè)范圍包括了第03行到第07行,而這個(gè)區(qū)域內(nèi)的main方法,其內(nèi)部也定義了一個(gè)名為x的變量,在這個(gè)范圍內(nèi),第09行定義的變量x被第05行定義的變量x所覆蓋,運(yùn)行結(jié)果如下所示。

4.4 實(shí)戰(zhàn)練習(xí)
本節(jié)視頻教學(xué)錄像:18分鐘
1. 編寫一個(gè)程序,定義局部變量sum,并求出1+2+3+…+99+100之和,賦值給sum,并輸出sum的值。
2. 糾正下面代碼的錯(cuò)誤,并給出正確的輸出結(jié)果。
01 public class Exercise4_2 02 { 03 static int x=10; 04 public static void main(String[]args) 05 { 06 int outer=1; 07 int inner=3; 08 { 09 int inner=2;
10 int x=100; 11 System.out.println("inner="+inner); 12 System.out.println("outer="+outer); 13 System.out.println("In class level,x="+x); 14 } 15 System.out.println("inner="+inner); 16 System.out.println("outer="+outer); 17 } 18 }
3. 動(dòng)手試一試,下面的代碼中在編譯時(shí)哪一行會(huì)出錯(cuò)?(Java面試題)
01 public class chap4Test 02 { 03 static void TestDemo() 04 { 05 int i,j,n; 06 i=100; 07 while(i>0) 08 { 09 System.out.println("The value is="+j); 10 n=n+1; 11 i--; 12 } 13 } 14 public static void main(String[]args) 15 { 16 TestDemo(); //調(diào)用靜態(tài)方法TestDemo() 17 } 18 }
解析:在4.2.3小節(jié)中,我們明確提到,局部變量在進(jìn)行取值操作前必須被初始化或賦值操作,否則會(huì)出現(xiàn)編譯錯(cuò)誤!本題中局部變量j和n在使用前,沒有被初始化,所以在使用它們的時(shí)候(分別在第09行和第10行)就會(huì)出錯(cuò)。如下圖所示。

而事實(shí)上,一旦出現(xiàn)了諸如“變量沒有初始化”的語法錯(cuò)誤,使用Eclipse,即使沒有編譯,也會(huì)在對(duì)應(yīng)的行首出現(xiàn)紅色的“×”,行末會(huì)對(duì)應(yīng)出現(xiàn)紅色小方塊“□”,用以提示用戶此行有語法錯(cuò)誤。
- 掌握分布式跟蹤:微服務(wù)和復(fù)雜系統(tǒng)性能分析
- 業(yè)務(wù)驅(qū)動(dòng)的推薦系統(tǒng):方法與實(shí)踐
- App草圖+流程圖+交互原型設(shè)計(jì)教程
- Apache Pulsar原理解析與應(yīng)用實(shí)踐
- 21天學(xué)通C++(第7版)
- 軟件測(cè)試從小白到高手
- BERT基礎(chǔ)教程:Transformer大模型實(shí)戰(zhàn)
- Unity AR/VR開發(fā):從新手到專家
- 深入淺出數(shù)據(jù)結(jié)構(gòu)與算法(微課視頻版)
- 軟件架構(gòu)指標(biāo):度量軟件系統(tǒng)的性能和架構(gòu)質(zhì)量
- 深入淺出Spring Boot 3.x
- 大數(shù)據(jù)實(shí)時(shí)流處理技術(shù)實(shí)戰(zhàn):基于Flink+Kafka技術(shù)
- MATLAB函數(shù)速查手冊(cè)(修訂版)
- Spring Boot+Vue 3大型前后端分離項(xiàng)目實(shí)戰(zhàn)
- 云計(jì)算工程