Java 系列教程:
1.變量的定義
正如上一篇教程《
Java基礎教程(4)--面向對象概念》中介紹的那樣,對象將它的狀態存在域中。但是你可能仍然有一些疑問,例如:命名一個域的規則和慣例是什么?除了int還有其他的類型嗎?域在聲明的時候必須初始化嗎?如果域沒有顯示地初始化會被賦予一個默認值嗎?在本文中我們將一一討論這些問題,但是在開始之前,需要對幾個概念進行介紹。在Java中,“域”和“變量”術語都會使用,對于初學者來說這可能有一點困惑,因為它們看起來好像說的是同一個東西。
Java語言定義了以下幾種類型的變量:
-
實例變量(非靜態域):從技術層面來說,對象將它們各自的狀態存在“非靜態域”中,也就是沒有使用static關鍵字修飾的域。非靜態域也被稱為實例變量,因為對于類的每個實例(換句話說,就是每個對象)來說,它們的值都是獨立的。例如,每個自行車的當前速度相對于其他自行車來說都是獨立的。
-
類變量(靜態域):類變量是使用static關鍵字修飾的域。這告訴編譯器無論這個類有多少個實例,這個變量只有一個副本。對于一種特定的自行車來說,它的齒輪數可以被標記為static,因為這個值適用于它的每一個實例。代碼static int numGears = 6;將會創建一個靜態域。此外,可以使用關鍵字final來修飾這個域來保證它的值不會改變。
-
局部變量:類似于對象在域中存儲其狀態,方法通常會將其臨時狀態存儲在局部變量中。聲明局部變量的語法與聲明域類似(例如,int count = 0;)。沒有特殊的關鍵字將變量標記為局部變量,這完全取決于聲明變量的位置——它位于方法的兩個大括號之間。因此,局部變量只對聲明它們的方法可見,對于類的其他部分來說它們是不可見的。
-
參數:你已經在HelloWorld的main方法和Bicycle類中看到過參數的應用?;叵胍幌耺ain方法的簽名——public static void main(String[] args)。這里,args變量是方法的參數。需要記住的是參數屬于“變量”而不是“域”。這也適用于其他接受參數的結構(例如構造函數和異常處理),我們將陸續在后面的教程中見到它們。
在理解了這幾個概念后,相信你對變量和域的關系有了進一步的認識。變量分為實例變量、類變量、局部變量和參數,而只有實例變量和類變量屬于域的概念。你也可能偶爾也會看到“成員”一詞,類的域,方法和嵌套類型統稱為其成員。
2.命名
變量名是標識符的一種,它滿足標識符的規則。標識符用來給程序中需要自定義名稱的某個實體命名,例如變量、方法、類、參數等。所有的標識符都需要滿足以下的規則或慣例:
-
標識符必須是由字母、數字、下劃線(_)、美元符號($)等Java允許作為標識符中一部分的字符組成??梢允褂肅haracter.isJavaIdentifierPart()來檢測一個字符是否被允許作為Java標識符的一部分。
-
標識符不能以數字或其他不允許作為出現在標識符起始位置的字符開頭??梢允褂肅haracter.isJavaIdentifierStart()來檢測一個字符是否被允許作為Java標識符的第一個字符。
-
標識符不能是關鍵字、null、true或false。
-
標識符不限制長度。
-
標識符應該盡可能地表達出它的作用或意義以提高程序的可讀性。建議使用駝峰法(第一個單詞首字母小寫,其余單詞首字母大寫)來為設計標識符。如果是常量(使用final修飾的變量),那么規則稍有變化,將每個字母大寫并用下劃線(_)分隔每個單詞。
上面提到了關鍵字。關鍵字是編程語言中事先定義的,有特別意義的單詞。下面是Java中的關鍵字:
其中,const和goto關鍵字雖然已經不再使用,但是它們還是被保留了下來。true、false和null雖然被很多人誤認為是關鍵字,但實際上它們只是字面量而已。
二.基本數據類型
1.八種基本數據類型
Java是一門靜態語言,這意味著所有的變量在使用前必須先進行聲明??紤]以下代碼:
int gear = 6;
上面的代碼聲明了一個名為gear的變量,它是整數類型,并且有一個初始值1。變量的類型決定了它所能存儲的數據的類型。除int之外,Java編程語言還支持其他七種基本數據類型。Java中的八種原始數據類型是:
-
byte:byte數據類型是8位有符號整數。它的最小值為-128(-27),最大值為127(27-1)。
-
short:short數據類型是16位有符號整數。它的最小值為-32768(-215),最大值為32767(215-1)。
-
int:int數據類型是32位有符號整數。它的最小值為-231,最大值為231-1。
-
long:long數據類型是64位有符號整數。它的最小值為-263,最大值為263-1。
-
float:float數據類型是單精度32位IEEE754浮點數(如果對浮點數的概念不了解,可以簡單地將它理解為小數)。它的有效位數為6~7位,不要使用它去存儲對精度要求較高的數據。
-
double:double數據類型是雙精度64位IEEE754浮點數。它的有效位數為15位。在保存浮點數時,絕大部分情況下都應該使用double類型。
-
boolean:boolean數據類型只有兩個可能的值:true和false。它一般用來表示條件的真或假。在Java中,boolean數據類型不能與其他數據類型進行相互轉換。
-
char:char數據類型是單個16位Unicode字符。它的最小值為'u0000',最大值為'uffff'。
char類型擴展
要想弄清楚char類型,就必須了解Unicode編碼機制。Unicode打破了傳統字符編碼機制的限制。在Unicode出現之前,已經有許多不同的標準:美國的ASCII、西歐語言中的ISO8859-1、俄羅斯的KOI-8、我國的GB2312等。這樣就產生了下面兩個問題:一是對于任意給定的編碼值,在不同的編碼方案下有可能對應不同的字母;二是采用大字符集的語言其編碼長度可能不同。例如,有些常用的字符采用單字節編碼,而另一些字符則需要兩個或更多字節。
設計Unicode編碼的目的就是要解決這些問題。在20世紀80年代開始啟動設計工作時,人們認為兩個字節的代碼寬度足以對世界上各種語言的所有字符進行編碼,并有足夠的空間留給未來擴展。在1991年發布了Unicode 1.0,當時僅占用65536個代碼值中不到一半的部分。在設計Java時決定采用16位的字符集,這樣會比使用8位字符集的程序設計語言有很大的改進。
十分遺憾,經過一段時間,不可避免的事情發生了。由于增加了大量的漢語、日語和韓語中的文字,Unicode字符超過了65536個,16位的char類型已經不能滿足描述所有Unicode字符的需要了。
從JavaSE 5.0開始,碼點(code point)是指與一個編碼表中的某個字符對應的代碼值。在Unicode標準中,碼點采用十六進制書寫,并加上前綴U+,例如U+0041就是拉丁字母A的碼點。Unicode的碼點可以分成17個平面。第一個代碼級別稱為基本多語言平面,碼點從U+0000到U+FFFF;其余的16個平面碼點從U+10000到U+10FFFF,其中包括一些輔助字符(supplementary character)。
下面來介紹UTF-16。UTF-16是Unicode碼的一種編碼格式。也就是說,Unicode決定了每個字符所對應的編碼的值,而UTF-16是Unicode編碼的一種書寫格式,與其類似的還有UTF-8和UTF-32。雖然這些格式的表現形式不盡相同,但他們表示的編碼是一致的,那就是Unicode編碼。UTF-16采用不同長度的編碼表示所有Unicode碼點。在Unicode中,特定長度的比特序列稱為代碼單元。例如,UTF-8的一個代碼單元的長度為8。UTF-16中16位表示一個代碼單元。UTF-16編碼的規則如下:
U+0000到U+D7FF以及U+E000到U+FFFF(基本多語言平面)
這個區間稱為基本多語言平面,包含了最常見的字符。每個字符對應的碼點使用一個代碼單元就可以表示。
U+D800到U+DFFF(代理區)
因為除基本多語言平面外,其他16個平面的碼點無法用2個字節表示,所以Unicode標準規定,基本多語言平面內的U+D800到U+DFFF的碼點不對應于任何字符,稱為代理區。因此,UTF-16利用保留下來的0xD800-0xDFFF區段的碼位來對輔助平面的字符的碼位進行編碼。
U+10000到U+10FFFF(輔助平面)
輔助平面中的碼點都大于U+FFFF,無法用16位來表示,因此采用一對連續的代碼單元來進行編碼。具體步驟如下:
a.碼點減去0x10000,得到的結果范圍在0x00000到0xFFFFF,使用二進制表示為yyyy yyyy yyxx xxxx xxxx;
b.高10位的值(范圍為0x000到0x3FF),加上0xD800,得到的結果范圍在0xD800到0xDBFF,稱為高位代理,作為第一個代碼單元;
c.低10位的值(范圍也是0x000到0x3FF),加上0xDC00,得到的結果范圍在0xDC00到0xDFFF,稱為低位代理,作為第二個代碼單元;
d.最終的UTF-16編碼用二進制表示就是:1101 10yy yyyy yyyy 1101 11xx xxxx xxxx。
在Java中,char類型描述了UTF-16編碼中的一個代碼單元。建議不要在程序中使用char類型,除非確實需要處理UTF-16代碼單元。
2.默認值
在聲明一個域時,如果不對它賦值,編譯器將賦予它一個默認值。下面是這8種基本數據類型的默認值:
局部變量則略有不同,編譯器永遠不會為未初始化的局部變量分配默認值。如果沒有初始化局部變量,請保證在使用它之前為其賦值。訪問未初始化的局部變量將導致編譯時錯誤。
3.字面量
你可能已經注意到在初始化基本數據類型的變量時不使用new關鍵字?;緮祿愋褪钦Z言中內置的特殊數據類型,它們不是從類創建的對象。字面量(literal)是用于表達源代碼中一個固定值的表示方法。如下所示,可以將字面量分配給基本數據類型的變量:
boolean result = true;
char capitalC = 'C';
byte b = 100;
short s = 10000;
int i = 100000;
(1)整型字面量
整型字面量默認為int類型??梢栽谡麛岛竺婕由虾缶YL或l來表示long類型字面量??梢允褂们熬Y0x來表示十六進制,0來表示八進制,0b來表示二進制:
// The number 26, in decimal
int decVal = 26;
// The number 26, in hexadecimal
int hexVal = 0x1a;
// The number 26, in octal
int octVal = 032;
// The number 26, in binary
int binVal = 0b11010;
(2)浮點型字面量
浮點型字面量默認為double類型(也可以加上D或d,不過一般省略)??梢栽诟↑c數后面加上后綴F或f來表示float類型字面量。
可以使用科學計數法來表示浮點數字面量。例如,1.2345*104可以表示為1.2345E4,1.2345*10-4可以表示為1.2345E-4。E后面的數字表示10的指數,也可以使用小寫字母e。也可以使用十六進制表示浮點數。例如,3.875=(11.111)2=(3.e)16=(3e)16*2-4,那么3.875可以表示成0x3.ep0或0x3ep-4(因為e和十六進制的15重復,所以這里使用p表示指數)。注意,尾數采用十六進制,指數采用十進制。指數的基數是2,而不是10。
(3)字符型字面量
char類型的字面量值要用單引號括起來。例如,'B'是編碼值為66所對應的字符常量。它與"B"不同,"B"是一個包含字符B的字符串。char類型的值可以表示為十六進制值,但需要加上前綴u,其范圍從u0000~uFFFF。例如,u03C0表示圓周率符號π。
除了轉義序列u外,還有一些用于表示特殊字符的轉義序列,如下表:
所有這些轉義序列都可以出現在字符字面量或字符串中。例如'u2018'或"Hello "。轉義序列u還可以出現在字符字面量或字符串之外,而其他轉義序列就不可以。例如
public static void main(Stringu005Bu005D args)
就完全符合語法,u005B和u005D是[和]的編碼。但要注意的是,轉義序列u會在編譯代碼前得到處理。例如,"u0022+u0022"并不是一個由雙引號包圍加號組成的字符串。實際上,u0022會在編譯代碼之前替換為",這個字符串會變成""+"",也就是一個空串。更隱蔽的,一定要注意注釋中的u,注釋
// Unicode u000A is a new line
會產生一個語法錯誤,因為u000A會被替換成換行符,也就是說,上面的注釋會變成下面這樣:
// Unicode
is a new line
類似地,下面的注釋也會產生語法錯誤:
// Look inside c:users
因為u后面并沒有跟著一個十六進制數。
(4)在數字字面量中使用下劃線
在JavaSE7及之后的版本中,任意個數的下劃線(_)可以出現在數字字面量中的任意兩個數字之間。這個功能可以提高數字字面量的可讀性,類似于使用逗號或空格等標點符號將每三個數字分為一組的形式。
long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi = 3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;