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

2.1 變量

我們先來看下面的示例:

   Dog dog1 = new Dog();

   // 給他們狀態
   dog1.name = "Lucy";
   dog1.color = "Black";

dog1是Dog類的實例(對象)名稱,name和color是dog1字段的名稱(字段存儲了對象的狀態),這些名稱都代表了某種類型的值,在編程語言中被稱為“變量”。通過變量,可以方便地找到內存中所存儲的值。

Java里面的變量包含如下類型:

· 實例變量/非靜態字段(Instance Variables/Non-Static Fields):從技術上講,對象存儲它們的個人狀態在“非靜態字段”,也就是沒有static關鍵字聲明的字段。非靜態字段也被稱為實例變量,因為它們的值對于類的每個實例來說是唯一的(換句話說,就是每個對象)。名字叫作Lucy的狗獨立于另一條名字叫作Lily的狗。

· 類變量/靜態字段(Class Variables/Static Fields):類變量是用static修飾符聲明的字段,也就是告訴編譯器無論類被實例化多少次,這個變量的存在只有一個副本。特定種類自行車的齒輪數目的字段可以被標記為static,因為相同的齒輪數量將適用于所有情況。代碼“static intnumGears = 6;”將創建一個這樣的靜態字段。此外,關鍵字final也可以加入,以指示齒輪的數量不會改變。

· 局部變量(Local Variables):類似于對象存儲狀態在字段里,方法通常會存放臨時狀態在局部變量里。語法與局部變量的聲明類似(例如,int count = 0;)。沒有特殊的關鍵字來指定一個變量是否是局部變量,是由該變量聲明的位置決定的。局部變量是類的方法中的變量。

· 參數(Parameters):在前文的例子中經常可以看到public static void main(String[] args),這里的args變量就是這個方法參數。需要記住的重要一點是,參數都歸類為“變量(variable)”而不是“字段(field)”。

如果我們談論的是“一般的字段”(不包括局部變量和參數),那么我們可以簡單地說“字段”。如果討論適用于上述所有情況,那么我們可以簡單地說“變量”。如果上下文要求一個區別,我們將使用特定的術語(靜態字段、局部變量等),也偶爾會使用術語“成員(member)”。類型的字段、方法和嵌套類型統稱為它的成員。

2.1.1 命名

每一個編程語言都有它自己的一套規則和慣例的各種名目,Java編程語言對于命名變量的規則和慣例可以概括如下:

· 變量名稱是區分大小寫的。變量名可以是任何合法的標識符(無限長度的Unicode字母和數字),以字母、美元符號$或下畫線_開頭,但是推薦按照慣例以字母開頭,而不是$或_。此外,按照慣例,美元符號從未使用過。在某些情況下,某些軟件自動生成的名稱會包含美元符號,但在實際編程中變量名應該始終避免使用美元符號。類似的約定還有下畫線,不鼓勵用“_”作為變量名開頭。空格是不允許的。

· 隨后的字符可以是字母、數字、美元符號或下畫線字符。慣例同樣適用于這一規則。為變量命名,盡量是完整的單詞,而不是神秘的縮寫。這樣做會使你的代碼更容易閱讀和理解,比如name和color會比縮寫n和c更直觀。同時請記住,選擇的名稱不能是關鍵字或保留字。

· 如果選擇的名稱只包含一個單詞,那么拼寫單詞全部為小寫字母。如果它由一個以上的單詞組成,那么每個后續單詞的第一個字母大寫,如gearRatio和currentGear。如果你的變量存儲一個常量,如static final int NUM_GEARS = 6,那么每個字母大寫,并用下畫線分隔后續字符。按照慣例,下畫線字符永遠不會在其他地方使用。

詳細的命名規范,可以參考筆者所著的《Java編碼規范》(https://github.com/waylau/java-code-conventions)。

2.1.2 基本數據類型

Java是靜態類型的語言,必須先聲明再使用。基本數據類型之間不會共享。主要有8種基本數據類型:byte、short、int、long、char、float、double、boolean。其中,byte、short、int、long是整數類型,float、double是浮點數類型。

1.byte

byte由1個字節8位表示,是最小的整數類型。當操作來自網絡、文件或者其他I/O的數據流時,byte類型特別有用。byte取值范圍是[-128, 127],默認值為(byte)0。如果我們試圖將取值范圍外的值賦給byte類型的變量,則會出現編譯錯誤,例如:

   byte b = 128; // 編譯錯誤

上面這個語句是無法通過編譯的。

還有一個有趣的問題,如果有這樣一個方法:

試圖通過test(0)來調用這個方法是錯誤的,編譯器會報錯,因為類型不兼容!但是像下面這樣賦值就完全沒有問題:

   byte b = 0; // 正常

這里涉及一個叫字面值(literal)的問題。字面值就是表面上的值,例如整型字面值在源代碼中就是諸如5、0、-200這樣的。如果整型字面值后面加上L或者l,那么這個字面值就是long類型,比如1000L代表一個long類型的值。

注意

l和1長得很像,所以表示一個long型時,以免肉眼看錯,建議以L結尾。

若不加L或者l,則為int類型。基本類型當中的byte、short、int、long都可以通過不加L的整型字面值來創建,例如:

   byte b = 100;
   short s = 5;

對于long類型,如果大小超出int所能表示的范圍(32 bits),則必須使用L結尾來表示。整型字面值可以有不同的表示方式:十六進制(0X或者0x)、十進制、八進制(0)、二進制(0B或者0b)等。二進制字面值是JDK 7以后才有的功能。在賦值操作中,int字面值可以賦給byte、short、int、long等,Java語言會自動處理好這個過程。如果方法調用時不一樣,比如調用test(0)的時候,它能匹配的方法是test(int),當然不能匹配test(byte)方法。

注意區別包裝器與原始類型的自動轉換,比如下面的賦值是允許的:

   byte d = 'A'; // 正常

上面例子中的字符字面值可以自動轉換成16位的整數。

對byte類型進行數學運算時,會自動提升為int類型。如果表達式中有double或者float等類型,也是會自動提升的。所以下面的代碼是錯誤的:

   byte t s1 = 100;
   byte s2 = 'a';
   byte sum = s1 + s2; // 錯誤!不能將int轉為byte
2.short

short用16位表示,取值范圍為[- 2^15, 2^15 - 1]。short可能是最不常用的類型,可以通過整型字面值或者字符字面值賦值,前提是不超出范圍。short類型參與運算的時候,一樣會被提升為int或者更高的類型。

3.int

int用32位表示,取值范圍為[- 2^31, 2^31 - 1]。Java 8以后,可以使用int類型表示無符號32位整數,數據范圍為[0, 2^31 - 1]。

4.long

long用64位表示,取值范圍為[- 2^63, 2^63 - 1],默認值為0L。當需要計算非常大的數時,如果int不足以容納大小,可以使用long類型。如果long也不夠,可以使用BigInteger類。

5.char

char用16位表示,其取值范圍可以是[0, 65535]、[0, 2^16 -1]或者是從\u0000到\uffff。Java使用Unicode字符集表示字符,Unicode是完全國際化的字符集,可以表示全部人類語言中的字符。Unicode需要16位寬,所以Java中的char類型也使用16位表示。賦值可能是這樣的:

   char ch1 = 88;
   char ch2 = 'A';

ASCII字符集占用了Unicode的前127個值。之所以把char歸入整型,是因為Java為char提供算術運算支持,例如運行“ch2++;”之后ch2就變成Y。當char進行加減乘除運算的時候,會被轉換成int類型,必須顯式轉化回來。

6.float

float使用32位表示,對應單精度浮點數,遵循IEEE 754規范。運行速度相比double更快,占內存更小,但是當數值非常大或者非常小的時候會變得不精確。精度要求不高的時候可以使用float類型,聲明賦值示例:

   float f1 =10;
   f1 = 10L;
   f1 = 10.0f;

可以將byte、short、int、long、char賦給float類型,Java自動完成轉換。

7.double

double使用64位表示,將浮點字面值賦給某個變量時,如果不顯示在字面值后面加f或者F,則默認為double類型。比如下面的例子:

   float f1 =10;
   f1 = 10.0;  //為double類型

java.lang.Math中的函數都采用double類型。如果double和float都無法達到想要的精度,可以使用BigDecimal類。

8.boolean

boolean類型只有兩個值true和false,默認為false。boolean與是否為0沒有任何關系,但是可以根據想要的邏輯進行轉換。許多地方都需要用到boolean類型。

除了上面列出的8種原始數據類型,Java編程語言還提供了java.lang.String,用于字符串的特殊支持。雙引號包圍的字符串會自動創建一個新的String對象,例如:

   String s = "this is a string";

String對象是不可變的,這意味著一旦創建,它們的值不能改變。String類型不是技術上的原始數據類型,但考慮到語言所賦予的特殊支持,你可能會錯誤地傾向于認為它是這樣的。

2.1.3 基本數據類型的默認值

在字段聲明時,有時并不必要分配一個值。字段被聲明但尚未初始化時,將會由編譯器設置一個合理的默認值。一般而言,根據數據類型的不同,默認將為零或為null。良好的編程風格不應該依賴于這樣的默認值。表2-1總結了上述數據類型的默認值。

表2-1 基本數據類型的默認值

局部變量(Local Variable)略有不同,編譯器不會指定一個默認值未初始化的局部變量。如果你不能初始化你聲明的局部變量,那么請確保使用之前給它分配一個值。訪問一個未初始化的局部變量會導致編譯時錯誤。

2.1.4 字面值

在Java源代碼中,字面值(Literal)用于表示固定的值,直接展示在代碼里,而不需要計算。數值型的字面值是最常見的,字符串字面值可以算是一種,當然也可以把特殊的null當作字面值。字面值大體上可以分為整型字面值、浮點字面值、字符和字符串字面值、特殊字面值。

1.整型字面值

從形式上看是整數的字面值歸類為整型字面值。例如,10、100000L、'B'、0XFF這些都可以稱為字面值。整型字面值可以用十進制、十六進制、八進制、二進制來表示。十進制很簡單,二進制、八進制、十六進制的表示分別在最前面加上0B(0b)、0、0X(0x)即可。

當然基數不能超出進制的范圍,比如在八進制里面09是不合法的,八進制的基數只能到7。一般情況下,字面值創建的是int類型,但是int字面值可以賦值給byte、short、int、long、char,只要字面值在目標范圍以內,Java就會自動完成轉換。如果試圖將超出范圍的字面值賦給某一類型(比如把128賦給byte類型),編譯會通不過。如果想創建一個int類型無法表示的long類型,則需要在字面值最后面加上L或者l,通常建議使用容易區分的L。所以整型字面值包括int字面值和long字面值兩種。

· 十進制:其位數由數字0~9組成,這是你每天使用的數字系統。

· 十六進制:其位數由數字0到9和字母A至F組成。

· 二進制:其位數由數字0和1組成。

下面是使用的語法:

   // 十進制
   int decVal = 26;

   //  十六進制
   int hexVal = 0x1a;

   // 二進制
   int binVal = 0b11010;
2.浮點字面值

浮點字面值可以簡單理解為小數,分為float字面值和double字面值兩種。如果在小數后面加上F或者f,就表示這是一個float字面值,如11.8F。如果小數后面不加F(f),如10.4,或者小數后面加上D(d),則表示這是一個double字面值。另外,浮點字面值支持科學記數法(E或e)表示。下面是一些例子:

   double d1 = 123.4;

   // 科學記數法
   double d2 = 1.234e2;

   float f1  = 123.4f;
3.字符和字符串字面值

在Java中,字符字面值用單引號括起來,如'@'、'1'。所有的UTF-16字符集都包含在字符字面值中。不能直接輸入的字符可以使用轉義字符,如\n為換行字符。也可以使用八進制或者十六進制表示字符,八進制使用反斜杠加3位數字表示,例如'\141'表示字母a。十六進制使用'\u'加上4為十六進制的數表示,如'\u0061'表示字符a。也就是說,通過使用轉義字符,可以表示鍵盤上有的或者沒有的所有字符。常見的轉義字符序列有:

· \ddd(八進制)

· \uxxxx(十六進制Unicode字符)

· \'(單引號)

· \"(雙引號)

· \\(反斜杠)

· \r(回車符)

· \n(換行符)

· \f(換頁符)

· \t(制表符)

· \b(回格符)

字符串字面值使用雙引號。字符串字面值中同樣可以包含字符字面值中的轉義字符序列。字符串必須位于同一行或者使用+運算符,因為Java沒有續行轉義序列。

4.特殊字面值

從Java SE 7開始,可以在數值型字面值中使用下畫線,但是下畫線只能用于分隔數字,不能分隔字符與字符,也不能分隔字符與數字。例如:

   int x = 123_456_789;

在編譯上面的代碼時,下畫線會自動去掉。

可以連續使用下畫線,比如:

   float f = 1.22___33__44

二進制或者十六進制的字面值也可以使用下畫線。

切記,下畫線只能用于數字與數字之間,除此以外都是非法的。例如,1._23是非法的,_123、11000_L都是非法的。

下面列出一些正確的用法:

   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;

下面列出一些非法的用法:

   float pi1 = 3_.1415F;
   float pi2 = 3._1415F;
   long socialSecurityNumber1 = 999_99_9999_L;
   int x2 = 52_;
   int x4 = 0_x52;
   int x5 = 0x_52;
   int x7 = 0x52_;

2.1.5 基本數據類型之間的轉換

在Java中,將一種類型的值賦給另一種類型是很常見的。同時要注意,boolean類型與其他7種類型不能進行轉換,這一點很明確。對于其他7種數據類型,它們之間都可以進行轉換,但是可能會存在精度損失或者其他一些變化。

轉換分為自動轉換和強制轉換。對于自動轉換(隱式),無須任何操作;而強制類型轉換需要顯式轉換,即使用轉換操作符“(類型)”。以下是一個示例:

   int  i =97;

   char  c = (char)i; // int強制轉換為char

首先將7種類型按下面的順序排列一下:

   byte <(short=char)< int < long < float < double

從小轉換到大,可以自動完成;而從大到小,則必須強制轉換。即使short和char類型相同,也必須強制轉換。

圖2-1形象地展示了類型轉換之間的關系。小杯子的物品可以順利倒入大杯子中(自動轉換),但大杯子里面的物品則不能簡單地倒入小杯子中(強制轉化,可能會導致物品丟失)。

圖2-1 基本數據類型之間的轉換

1.自動轉換

自動轉換時發生擴寬轉換(widening conversion)。因為較大的類型(如int)要保存較小的類型(如byte),內存總是足夠的,不需要強制轉換。將字面值保存到byte、short、char、long的時候,也會自動進行類型轉換。注意,此時從int(沒有帶L的整型字面值為int)到byte、short、char也是自動完成的,雖然它們都比int小。在自動類型轉化中,除了以下幾種情況可能會導致精度損失以外,其他的轉換都不能出現精度損失。

· int–> float

· long–> float

· long–> double

· float –>無符號double

除了可能的精度損失外,自動轉換不會出現任何運行時異常。

2.強制類型轉換

如果要把大的轉成小的,或者在short與char之間進行轉換,就必須強制轉換,也被稱作縮小轉換(narrowing conversion),因為必須顯式地使數值更小以適應目標類型。嚴格地說,將byte轉為char不屬于縮小轉換,因為從byte到char的過程其實是byte→int→char,所以擴寬轉換和縮小轉換都有。

強制轉換除了可能的精度損失外,還可能使模(overall magnitude)發生變化。強制轉換示例如下:

   int a = 257;
   byte b;
   b = (byte)a; // 1

如果整數的值超出了byte所能表示的范圍,結果將對byte類型的范圍取余數。例如,a=257超出了byte [-128,127]的范圍,所以將257除以byte的范圍(256)取余數得到b=1。需要注意的是,當a=200時,除以256取余數應該為-56,而不是200。

將浮點類型賦給整數類型的時候會發生截尾(truncation),也就是把小數的部分去掉,只留下整數部分。此時如果整數超出目標類型范圍,一樣將對目標類型的范圍取余數。

7種基本類型轉換總結如圖2-2所示。

圖2-2 7種基本類型轉換總結

3.字面值賦值

在使用字面值對整數賦值的過程中,可以將int字面值賦給byte、short、char、int,只要不超出范圍即可。這個過程中的類型轉換是自動完成的,但是如果你試圖將long字面值賦給byte,即使沒有超出范圍,也必須進行強制類型轉換。例如,下面的例子是非法的:

   byte b = 10L; // 錯誤!

如果想將long型轉為byte,則需要進行強制轉換。

4.表達式中的自動類型提升

除了賦值以外,表達式計算過程中也可能發生一些類型轉換。在表達式中,類型提升規則如下:

· 所有byte、short、char都被提升為int。

· 如果有一個操作數為long,整個表達式提升為long。float和double情況也一樣。

2.1.6 數組

數組(Array)是一個容器對象,保存一個固定數量的單一類型的值。當數組創建時,數組的長度就確定了。創建后,其長度是固定的。數據里面的每個項稱為元素(element),每個元素都用一個數組下標(index)關聯。下標從0開始,如圖2-3所示,第9個元素的下標是8。

圖2-3 數組示例

以下是一個數組的示例:

輸出為:

   Element at index 0: 100
   Element at index 1: 200
   Element at index 2: 300
   Element at index 3: 400
   Element at index 4: 500
   Element at index 5: 600
   Element at index 6: 700
   Element at index 7: 800
   Element at index 8: 900
   Element at index 9: 1000
1.聲明引用數組的變量

聲明數組的類型:

   byte[] anArrayOfBytes;
   short[] anArrayOfShorts;
   long[] anArrayOfLongs;
   float[] anArrayOfFloats;
   double[] anArrayOfDoubles;
   boolean[] anArrayOfBooleans;
   char[] anArrayOfChars;
   String[] anArrayOfStrings;

也可以將中括號放在數組名稱后面(但不推薦):

   // 合法,但不推薦使用
   float anArrayOfFloats[];
2.創建、初始化和訪問數組

ArrayDemo的示例說明了創建、初始化和訪問數組的過程。可以用下面的方式簡化創建、初始化數組:

   int[] anArray = {
      100, 200, 300,
      400, 500, 600,
      700, 800, 900, 1000
   };

數組里面可以聲明數組,即多維數組(multidimensional array)。如下面的例子就是一個多維數組MultiDimArrayDemo:

輸出為:

   Mr. Way
   Ms. Lau

最后,可以通過內建的length屬性來確認數組的大小:

   System.out.println(anArray.length);
3.復制數組

System類有一個arraycopy方法,用于數組的有效復制:

下面是一個例子(ArrayCopyDemo):

程序輸出為:

   way
4.數組操作

Java提供了一些數組有用的操作。觀察下面的例子ArrayCopyOfDemo:

可以看到,相比于ArrayCopyDemo的例子,使用java.util.Arrays.copyOfRange方法,代碼量減少了很多。

其他常用操作還包括:

· binarySearch:用于搜索。

· equals:比較兩個數組是否相等。

· fill:填充數組。

· sort:數組排序,在Java 8以后,可以使用parallelSort方法,在多處理器系統的大數組并行排序比連續數組排序更快。

主站蜘蛛池模板: 抚顺县| 全南县| 石景山区| 翁源县| 济宁市| 永嘉县| 收藏| 吉隆县| 扶沟县| 梁山县| 沙雅县| 习水县| 驻马店市| 宝丰县| 准格尔旗| 汽车| 即墨市| 绥中县| 称多县| 双峰县| 象山县| 兴仁县| 闵行区| 资源县| 西宁市| 蚌埠市| 苍山县| 勃利县| 淮滨县| 吴旗县| 青冈县| 哈尔滨市| 南昌市| 茶陵县| 牟定县| 富平县| 罗江县| 梧州市| 龙川县| 华池县| 元阳县|