賦值
上節我們說了資料型別和變數,通過宣告變數,每個變數賦予一個資料型別和一個有意義的名字,我們就告訴了計算機我們要操作的資料。
有了資料,我們能做很多操作。但本文只說說對資料做的第一個操作:賦值。宣告變數之後,就在記憶體分配了一塊位置,但這個位置的內容是未知的,賦值就是把這塊位置的內容設為一個確定的值。
Java中基本型別、陣列、物件的賦值有明顯不同,本文介紹基本型別和陣列的賦值,關於物件後續文章會詳述。
我們先來說基本型別的賦值,然後再說陣列的賦值。
基本型別的賦值
整數型別
整數型別有byte, short, int和long,分別佔用1/2/4/8個位元組,取值範圍分別是:
型別名 | 取值範圍 |
byte | -2^7 ~ 2^7-1 |
short | -2^15 ~ 2^15-1 |
int | -2^31 ~ 2^31-1 |
long | -2^63 ~ 2^63-1 |
我們用^表示指數,2^7即2的7次方。這個範圍我們不需要記的那麼清楚,有個大概範圍認識就可以了,大多數日常應用,一般用int就可以了。後續文章會從二進位制的角度進一步分析表示範圍為什麼會是這樣的。
賦值形式很簡單,直接把熟悉的數字常量形式賦值給變數即可,對應的記憶體空間的值就從未知變成了確定的常量。但常量不能超過對應型別的表示範圍。例如:
1 2 3 4 |
byte b = 23; short s = 3333; int i = 9999; long l = 32323; |
但是,在給long型別賦值時,如果常量超過了int的表示範圍,需要在常量後面加大寫或小寫的L,即L或l,例如:
1 |
long a = 3232343433L; |
這個是由於數字常量預設為是int型別。
小數型別
小數型別有float和double,佔用的記憶體空間分別是4和8個位元組,有不同的取值範圍和精度,double表示的範圍更大,精度更高,具體來說:
型別名 | 取值範圍 |
float | 1.4E-45 ~ 3.4E+38
-3.4E+38 ~-1.4E-45 |
double | 4.9E-324 ~1.7E+308
-1.7E+308 ~ -4.9E-324 |
取值範圍看上去很奇怪,一般我們也不需要記住,有個大概印象就可以了。E表示以10為底的指數,E後面的+號和-號代表正指數和負指數,例如:1.4E-45表示1.4乘以10的-45次方。後續文章會進一步分析小數的二進位制表示。
對於double,直接把熟悉的小數表示賦值給變數即可,例如:
1 |
double d = 333.33; |
但對於float,需要在數字後面加大寫F或小寫f,例如:
1 |
float f = 333.33f; |
這個是由於小數常量預設為是double型別。
除了小數,也可以把整數直接賦值給float或double,例如:
1 2 |
float f = 33; double d = 3333333333333L; |
boolean型別
這個很簡單,直接使用true或false賦值,分別表示真和假,例如:
1 2 |
boolean b = true; b = false; |
字元型別
字元型別char用於表示一個字元,這個字元可以是中文字元,也可以是英文字元。在記憶體中,Java用兩個位元組表示一個字元。賦值時把常量字元用單引號括起來,不要使用雙引號,例如:
1 2 |
char c = 'A'; char z = '中'; |
關於字元型別有一些細節,後續文章會進一步深度解析。
一些說明
上面介紹的賦值都是直接給變數設定一個常量值。但也可以把變數賦給變數,例如:
1 2 |
int a = 100; int b = a; |
變數可以進行各種運算(後續文章講解),也可以將變數的運算結果賦給變數,例如:
1 2 3 |
int a = 1; int b = 2; int c = 2*a+b; //2乘以a的值再加上b的值賦給c |
上面介紹的賦值都是在宣告變數的時候就進行了賦值,但這不是必須的,可以先宣告變數,隨後再進行賦值。
陣列型別
賦值語法
基本型別的陣列有三種賦值形式,如下所示:
1 2 3 4 5 6 |
1. int[] arr = {1,2,3}; 2. int[] arr = new int[]{1,2,3}; 3. int[] arr = new int[3]; arr[0]=1; arr[1]=2; arr[2]=3; |
第一種和第二種都是預先知道陣列的內容,而第三種是先分配長度,然後再給每個元素賦值。
第三種形式中,即使沒有給每個元素賦值,每個元素也都有一個預設值,這個預設值跟陣列型別有關。數值型別的值為0,boolean為false, char為空字元。
陣列長度可以動態確定,如下所示:
1 2 |
int length = ... ;//根據一些條件動態計算 int arr = new int[length]; |
雖然可以動態確定,但定了之後就不可以變,陣列有一個length屬性,但只能讀,不能改。
一個小細節,不能在給定初始值的同時還給定長度,即如下格式是不允許的:
1 |
int[] arr = new int[3]{1,2,3} |
這是可以理解的,因為初始值已經決定了長度,再給個長度,如果還不一致,計算機將無所適從。
陣列和基本型別的區別
一個基本型別變數,記憶體中只會有一塊對應的記憶體空間。但陣列有兩塊,一塊用於儲存陣列內容本身,另一塊用於儲存內容的位置。
用一個例子來說明,有一個int變數a,和一個int陣列變數arr,其程式碼,變數對應的記憶體地址和記憶體內容如下所示:
程式碼 | 記憶體地址 | 記憶體資料 |
int a = 100; | 1000 | 100 |
int[] arr = {1,2,3}; | 2000 | 3000 |
3000 | 1 | |
3004 | 2 | |
3008 | 3 |
基本型別a的記憶體地址是1000,這個位置儲存的就是它的值100。
陣列型別arr的記憶體地址是2000,這個位置儲存的值是一個位置3000,3000開始的位置儲存的才是實際的資料1,2,3。
為什麼陣列要用兩塊空間
不能只用一塊空間嗎?我們來看下面這個程式碼:
1 2 3 4 |
int[] arrA = {1,2,3}; int[] arrB = {4,5,6,7}; arrA = arrB; |
這個程式碼中,arrA初始的長度是3,arrB的長度是4,後來將arrB的值賦給了arrA。如果arrA對應的記憶體空間是直接儲存的陣列內容,那麼它將沒有足夠的空間去容納arrB的所有元素。
用兩塊空間儲存,這個就簡單的多,arrA儲存的值就變成了和arrB的一樣,儲存的都是陣列內容{4,5,6,7}的地址,此後訪問arrA就和arrB是一樣的了,而arrA {1,2,3}的記憶體空間由於無人引用會被垃圾回收,如下所示:
arrA {1,2,3}
\
\
arrB -> {4,5,6,7}
由上,也可以看出,給陣列變數賦值和給陣列中元素賦值是兩回事。給陣列中元素賦值是改變陣列內容,而給陣列變數賦值則會讓變數指向一個不同的位置。
上面我們說陣列的長度是不可以變的,不可變指的是陣列的內容空間,一經分配,長度就不能再變了,但是可以改變陣列變數的值,讓它指向一個長度不同的空間,就像上例中arrA後來指向了arrB一樣。
小結
給變數賦值就是將變數對應的記憶體空間設定為一個明確的值,有了值之後,變數可以被載入到CPU,CPU可以對這些值進行各種運算,運算後的結果又可以被賦值給變數,儲存到記憶體中。
資料可以進行哪些運算?如何進行運算呢?