官术网_书友最值得收藏!

第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ò)誤。

主站蜘蛛池模板: 易门县| 平湖市| 淮阳县| 古丈县| 祁连县| 梓潼县| 海城市| 区。| 芷江| 马边| 乐至县| 筠连县| 湘潭县| 余姚市| 高平市| 屏东县| 平南县| 日照市| 大宁县| 蒲江县| 邢台县| 天津市| 宁蒗| 广昌县| 浮山县| 阿荣旗| 县级市| 凌海市| 婺源县| 百色市| 秦安县| 永吉县| 衡阳县| 灵川县| 那曲县| 集贤县| 建昌县| 平果县| 大冶市| 广昌县| 平谷区|