文章目錄
流程控制與數組
流程控制
順序結構
任何編程語言中最常見的程序結構就是順序結構,順序結構就是程序從上到下逐行地執行,中間沒有任何判斷和跳轉
分支結構
Java 提供了兩種常見的分支控制結構: if
語句和 switch
語句
if
語句使用布爾表達式或布爾值作爲分支條件來進行分支控制switch
語句則用於對多個整型值進行匹配,從而實現分支控制
if條件語句
if語句使用布爾表達式或布爾值作爲分支條件來進行分支控制,if語句有以下三種形式
- 第一種
if (logic expression) { statement... }
- 代碼示例
int age = 25; if (age > 23) { System.out.println("該結婚買房了!");//該結婚買房了! }
- 代碼示例
- 第二種
if (logic expression) { statement... } else { statement... }
- 代碼示例
int age = 21; if (age > 23) { System.out.println("該結婚買房了!"); } else { System.out.println("年齡還小,要好好努力學習啊!");//年齡還小,要好好努力學習啊! }
- 代碼示例
- 第三種
if (logic expression) { statement... } else if (logic expression) { statement... } ...//可以有0個或多個else if語句 else//最後的else語句也可以省略 { statement... }
- 代碼示例
int age = 30; if (age == 23) { System.out.println("該結婚買房了!"); }else if (age == 20) { System.out.println("原來你才20歲啊,太小了,不過也要好好珍惜啊!");//原來你才20歲啊,太小了,不過也要好好珍惜啊! }else if (age == 30){ ;//一個分號表示空語句,在此處的含義是如果age==30,什麼也不做。 } else { System.out.println("年齡還小,要好好努力學習啊!");//年齡還小,要好好努力學習啊! }
- 代碼示例
注意點
- 上面
if
語句的3種形式中,放在if
之後括號裏的只能是一個邏輯表達式,即這個表達式的返回值只能是true
或false
. - 在使用
if...else
語句時有一條基本規則:總是優先把包含範圍小的條件放在前面處理 - 例如
age>60
和age>20
兩個條件,明顯age>60
的範圍更小,所以應該先處理age>60
的情況
switch語句
Java
增強後的switch
分支語句
switch
語句由一個控制表達式和多個case
標籤組成- 和
if
語句不同的是,switch
語句後面的控制表達式的數據類型只能是byte
、short
、char
、int
四種整數類型,枚舉類型
和java.lang.String
類型(從Java7才允許),不能是boolean
類型。 switch
語句往往需要在case
標籤後緊跟一個代碼塊,case
標籤作爲這個代碼塊的標識
switch
語句的語法格式如下:
switch (expression)
{
case condition1:
{
statement(s)
break;
}
case condition2:
{
statement(s)
break;
}
case conditionN:
{
statement(s)
break;
}
default :
{
statement(s)
}
}
這種分支語句的執行是先對expression
求值,然後依次匹配condition1
、condition2
、conditionN
等值,遇到匹配的值即執行對應的執行體;如果所有case
標籤後的值都不與expression
表達式的值相等,則執行default
標籤後的代碼塊
代碼示例
int a = 5 * 3;
switch (a) {
case 2: {
System.out.printf("5 * 3的結果是:%d", 2);
break;
}
case 5: {
System.out.printf("5 * 3的結果是:%d", 5);
break;
}
case 15: {
System.out.printf("5 * 3的結果是:%d", 15);//5 * 3的結果是:15
break;
}
default: {
System.out.printf("5 * 3的結果是:%d", 10);
}
}
Java7
增強了switch
語句的功能,允許switch
語句的控制表達式是java.lang.String
類型的變量或表達式.- 只能是
java.lang.String
類型,不能是StringBuffer
或StringBuilder
這兩種字符串類型
代碼示例
String season = "秋天";//我也不知道現在是什麼天啊!
// String season1 = "秋";//我也不知道現在是什麼天啊!
switch (season){
case "春天":
{
System.out.println("現在是春天啊!");
break;
}
case "夏天":
{
System.out.println("現在是夏天啊!");
break;
}
case "秋天":
{
System.out.println("現在是秋天啊!");
break;//如果不加break將會連着滿足當前case的之後條件下的代碼塊一起打印
/*
不加break將會輸出:
現在是秋天啊!
現在是冬天啊!
*/
}
case "冬天":
{
System.out.println("現在是冬天啊!");
break;
}
default:{
System.out.println("我也不知道現在是什麼天啊!");
}
}
注意點
使用switch語句時,有兩個值得注意的地方 :
witch
語句後的expression
表達式的數據類型只能是byte
、short
、char
、int
四種整數類型,String (Java7才支持)
和枚舉類型
- 第二地方是如果省略了
case
後代碼塊的break
,將達不到預期效果
循環結構
- 循環語句可以在滿足循環條件的情況下,反覆執行某一段代碼,這段被重複執行的代碼被稱爲循環體。
- 當反覆執行這個循環體時,需要在合適的時候把循環條件改爲假,從而結束循環,否則循環將一直執行下去,形成死循環。
循環語句可能包含如下4個部分
- 初始化語句
(init statement)
:一條或多條語句,這些語句用於完 成一些初始化工作。初始化句在循環開始之前執行 - 循環條件
(test_expression)
:這是boolean
表達式,這個表達式能決定是否執行循環體 - 循環體
(body_statement)
:這個部分是循環的主體,如果循環條件允許,這個代碼塊將被重複執行,如果這個代碼塊只有一行語句,則這個代碼塊的花括號是可以省略的 - 迭代語句
(iteration_statement)
:這個部分在一次循環體執行結束後,對循環條件求值之前執行,通常用於控制循環條件中的變量,使得循環在合適的時候結束。
上面4個部分只是一般性的分類,並不是每個循環中都非常清晰地分出了這4個部分。
while循環語句
語法格式
[init_statement]
while(test_expression)
{
statement;
[iteration_statement]
}
解釋
while
循環每次執行循環體之前,先對test_expression
循環條件求值,如果循環條件爲true
,則行循環體部分。- 迭代語句
iteration_statement
總是位於循環體的最後,循環體能成功執行完成時,while
循環纔會執行iteration_statement
語句。 - 從這個意義上來看,
while
循環也可被當作條件語句——如果test_expression
條件一開始就爲false
,則循環體部分將永遠不會獲得執行。
代碼示例
int count = 1;
while (count <= 10) {
System.out.println(count);
// count += 1;//每次循環累加1
count++;//每次循環累加1
// ++count;//每次循環累加1
// System.out.println(count);
}
System.out.println("-----循環結束-----");//11
System.out.println(count);//11
如果while
循環的循環體部分和迭代語句合併在一起,且只有一行代碼,則可以省略while
循環後的花括號。但這種省略花括號的做法,可能降低程序的可讀性。
使用while
循環時,一定要保證循環條件有變成false
的時候,否則這個循環將成爲一個死循環,永遠無法結束這個循環。
代碼示例
int count = 5;
while (count < 6) {
System.out.println(count);
count--;
}
System.out.println("上邊代碼已造成了死循環,無法執行當前打印語句!");
簡單的死循環
while (true) {
System.out.println("死循環");
}
do while循環語句
do while
循環與while
循環的區別
while
循環是先判斷循環條件,如果條件爲真則執行循環體。do while
循環則先執行循環體,然後才判斷循環條件,如果循環條件爲真,則執行下一次循環,否則中止循環。
do while
循環的語法格式
[init_statement]
do
{
statement ;
[iteration_statement]
}while (test_expression) ;
與while
循環不同的是,do while
循環的循環條件後必須有一個分號,這個分號表明循環結束。
代碼示例
int count = 1;
do {
// count++;//2-10
// ++count;//2-10
System.out.println(count);
count++;//1-10
// ++count;//1-10
} while (count <= 10);
System.out.println("循環結束!");//循環結束!
即使test_expression
循環條件的值開始就是假。do while
循環也會執行循環體。因此,do while
循環的循環體至少執行一次。以下爲代碼驗證
int count = 5;
do {
System.out.println(count);//打印了一次 5
count++;
}while (count>10);
for循環
for
循環是更加簡潔的循環語句,大部分情況下. for
循環可以代替while
循環、 do while
循環
for
循環的基本語法格式如下:
for ([init_statement]; [test_expression); [iteration statement])
{
statement
}
- 程序執行for循環時,先執行循環的初始化語句
init_statement
。初始化語句只在循環開始前執行一次。 - 每次執行循環體之前,先計算
test_expression
循環條件的值,如果循環條件返回true
,則執行循環體,循環體執行結束後執行循環迭代語句 。
因此,對於for
循環而言,循環條件總比循環體要多執行一次。因爲最後一次執行循環條件返回false
,將不再執行循環體。
值得指出的是,for
循環的循環迭代語句並沒有與循環體放在一起,因此即使在執行循環體時遇到continue
語句結束本次循環,循環法代語句也一樣會得到執行。
for
循環和while
、do while
循環不同之處
- 由於
while
、do while
循環的循環迭代語句緊跟跟着循環休,因此如果循環體不能完全執行,如使用continue
語句來結束本次循環,則循環迭代語句不會被執行 。 - 但
for
循環的循環迭代語句並沒有與循環體放在一起,因此不管是否使用continue
語句來結束本次循環,循環迭代語句一樣會獲得執行。
代碼示例
for (int count = 1; count <= 10; count++){
System.out.printf("本次循環count的值爲%s\n", count);
}
System.out.println("循環結束!");
輸出:
本次循環count的值爲1
本次循環count的值爲2
本次循環count的值爲3
本次循環count的值爲4
本次循環count的值爲5
本次循環count的值爲6
本次循環count的值爲7
本次循環count的值爲8
本次循環count的值爲9
本次循環count的值爲10
循環結束!
for
循環允許同時指定多個初始化語句,循環條件也可以是一個包含邏輯運算符的表達式。
代碼示例
for (int a = 0, b = 0, c = 0; a < 10 && b < 6 && c < 4; a++, b++, c++) {
System.out.printf("本次循環a=%d,b=%d,c=%d\n", a, b, c);
}
System.out.println("循環結束!");
輸出:
本次循環a=0,b=0,c=0
本次循環a=1,b=1,c=1
本次循環a=2,b=2,c=2
本次循環a=3,b=3,c=3
循環結束!
上面代碼中初始化變量有3個,但是隻能有一個聲明語句,因此如果需要在初始化表達式中聲明多個變量,那麼這些變量應該具有相同的數據類型
。
建議不要在循環體內修改循環變量(也叫循環計數器)的值,否則會增加程序出錯的可能性。
萬一程序真的需要訪問、修改循環變量的值,建議重新定義一個臨時變量,先將循環變量的值賦給臨時變量,然後對臨時變量的值進行修改。
for
循環圓括號中只有兩個分號是必需的,初始化語句
、循環條件
、迭代語句部分
都是可以省略的。如果省略了循環條件,則這個循環條件默認爲true
,將會產生一個死循環。
例如下面的程序
for (; ; ) {
System.out.println("----");
}
使用for
循環時,還可以把初始化條件
定義在循環體之外
,把循環迭代語句
放在循環體內
,這種做法就非常類似於前面的while
循環了。
代碼示例
int b = 1;
for (; b <= 100; ) {
System.out.println(b);
b++;
}
System.out.println("--------------");
System.out.println(b);//101 for循環外依然可以訪問到b
- for循環的初始化語句放在循環之前定義還有一個作用,可以擴大初始化語句中所定義變量作用域。
- 在for循環裏定義的變量,其作用域僅在該循環內有效,for循環終止之後,這些變量將不可被訪問。
如果需要在for循環以外的地方使用這些變量的值,就可以採用上面的做法。
除此之外,還有一種做法也可以滿足這種要求:額外定義一個變量來保存這個循環變量的值。
代碼示例:
int tmp = 0;
for (int j = 1; j <= 10; j++) {
tmp = j;
System.out.printf("j=%d\n", j);
}
System.out.printf("tmp=%d\n", tmp);//tmp=10
- 相比前面的代碼,通常更願意選擇這種解決方案。使用一個變量
tmp
來保存循環變量的值,使得程序更加清晰,變量j
和變量tmp
的責任更加清晰。 - 反之,如果採用前一種方法,則變量
j
的作用域被擴大了,功能也被擴大了。 - 作用域擴大的後果是:如果該方法還有另一個循環也需要定義循環變量,不能再次使用
j
作爲循環變量。
幾個小例子
- 打印1-100內的所有偶數
System.out.println("--------------"); int a = 1; for (; a <= 100; a++) { if (a % 2 == 0) { System.out.println(a); } }
- 計算1-100的和
System.out.println("--------------"); int numCount = 0; for (int i = 1; i <= 100; i++) { numCount += i; } // System.out.println(i);//編譯報錯,因爲i是在for循環內定義的,所以i的作用域在for循環內有效。 System.out.printf("1-100累加的和爲%d", numCount);//1-100累加的和爲5050
嵌套循環
如果把一個循環放在另一個循環體內,那麼就可以形成嵌套循環。嵌套循環既可以是for循環嵌套while循環,也可以是while循環嵌套 do while循環…… 即各種類型的循環都可以作爲外層循環,也可以作爲內層循環。
嵌套循環流程如下圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wlZpCGvQ-1588175789845)(https://www.wenbin.org.cn/upload/2020/04/%E5%B5%8C%E5%A5%97%E5%BE%AA%E7%8E%AF-80ea66bc99624e979989b8dc02d76eca-31e643ea13d8478ab17ea5104905912e.png)]
從圖4.1來看,嵌套循環就是把內層循環當成外層循環的循環體。當只有內層循環的循環條件爲false時,纔會完全跳出內層循環,纔可以結束外層循環的當次循環,開始下一次循環。
代碼示例
//外層循環
for (int i = 1; i <= 3; i++) {
//內層循環
for (int j = 1; j <= 3; j++) {
System.out.printf("%d * %d = %d\n", i, j, i * j);
}
}
輸出
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
控制循環結構
Java語言沒有提供goto語句來控制程序的跳轉,這種做法提高了程序流程控制的可讀性,但降低了程序流程控制的靈活性。
爲了彌補這種不足Java提供了continue、break來控制循環結構,除此之外,return可以結束整個方法,當然也就結束了一次循環。
使用break結束循環
break 用於完全結束一個循環,跳出循環體。
不管是哪種循環,一旦在循環體中遇到break,系統將完全結束該循環,開始執行循環之後的代碼。
代碼示例(break實現 打印1-5中的1-4)
for (int i = 1; i <= 5; i++) {
if (i % 5 == 0) {
break;
}
System.out.println(i);
}
輸出
1
2
3
4
break語句不僅可以結束其所在的循環,還可以直接結束其外層循環。
- 此時需要在break後緊跟一個標籤,這個標籤用於標識一個外層循環。
- Java中的標籤就是一個緊跟着英文冒號(:)的標識符。
- 與其他語言不同的是, Java中的標籤只有放在循環語句之前纔有作用。
代碼示例
outer://外層循環,outer作爲標識符
for (int i = 1; i <= 3; i++) {
//內層循環
for (int j = 1; j <= 3; j++) {
if (i * j == 6) {
break outer;//跳出 outer 標籤所標識的循環
}
System.out.printf("%d * %d = %d\n", i, j, i * j);
}
}
輸出
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
2 * 2 = 4
使用continue
忽略本次循環
continue和break的區別
- continue只是忽略本次循環剩下語句,接着開始下循環,並不會終止循環。
- 而break則是完全終止循環本身。
代碼示例
for (int i = 1; i <= 10; i++) {
if (i % 2 != 0) {
continue;
}
System.out.println(i);
}
for
打印1-10中的偶數
for (int i = 1; i <= 10; i++) {
if (i % 2 != 0) {
continue;
}
System.out.println(i);
}
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
while
打印1-10中的偶數
int i = 1;
while (i <= 10) {
if (i % 2 == 0) {
System.out.println(i);
}
i++;
}
do while
打印1-10中的偶數
int i = 1;
do {
i++;
if (i % 2 == 0) {
System.out.println(i);
}
} while (i <= 10);
與break類似的是,continue後也可以緊跟一個標籤,用於直接跳過標籤所標識循環的當次循環的剩下語句,重新開始下一次循環。
代碼示例
outer:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
continue outer;
}
System.out.println("i的值是:" + i + ", j的值爲:" + j);
}
}
輸出
i的值是:1, j的值爲:1
i的值是:2, j的值爲:1
i的值是:3, j的值爲:1
每當j等於2時, continue outer;語句就結束了外層循環的當次循環,直接開始下一次循環,內層循環沒有機會執行完成。
使用return
結束方法
- return關鍵宇並不是專門用於結束循環的,return的功能是結束一個方法。
- 一個方法執行到return語句時(return關鍵宇後還可以跟變量、常量和表達式,這將在方法介紹中有更詳細的解釋),這個方法將被結束。
- Java程序中大部分循環都被放在方法中執行,例如前面介紹的所有循環示範程序(都是放在main方法中執行的)。
- 一旦在循環體執行到return語句,return語句就會結束該方法,循環自然就隨之結束。
代碼示例
for (int i = 0; i <= 3; i++) {
System.out.println("i的值爲:" + i);
if (i == 1) {
return;
}
System.out.println("本次循環結束!");
}
輸出
i的值爲:0
本次循環結束!
i的值爲:1
- 運行上面程序,循環只能執行到i等於1時,當i=1時程序將完全結束(當main方法結束時,就是Java程序結束時)。
- 從這個運行結果來看,雖然return並不是專門用於循環結構控制的關鍵字,但通過return語句確實可以結束一個循環。
- 與continue和break不同的是,return直接結束整個方法,不管這個return處於多少層循環之內。
數組
數組是編程語語中最常見的一種數據結構,可用於存儲多個數據,每個數組元素存放一個數據,通常可通過數組元素的索引來訪問數組元素,包括爲數組元素賦值和取出數組元素的值。
數組也是一種類型
Java中的數組要求所有的數組元素具有相同的數據類型。因此,一個數組中,數組元素的類型是唯一的,即一個數組裏只能存儲一種數據類型的數據,而不能存儲多種數據類型的數據。
因爲Java語言是面向對象的語言,而類與類之間可以支持繼承關係,這樣能產一個數組中可以存放多種數據類型的假象。
例如一個水果數組,要求每個數紐元素都是水果,實際上數組元素既可以是蘋果,也可以是香蕉(蘋果、香蕉都繼承了水果,都是一種特殊的和水果)。但這個數組的數組元素的類型還是唯一的,只能是水果類型。
一旦數組的初始化完 ,數組在內存中所佔的空間將被固定下來,因此數組的長度將不可改變。即使把某個數組元素的數據清空,但它所佔的空間依然被保留,依然屬於該數組,數組的長度依然不變。
Java的數組既可以存儲基本類型的數據,也可以存儲引用類型的數據,只要所有的數組元素具有相同的類型即可。
值得指出的是,數組也是一種數據類型,它本身是一種引用類型,例如int是一個基本類型,int[]
(這是定義數組的一種方式)就是一種引用類型了。
定義數組
兩種定義數組組方法
type[] arrayName
type arrayName []
推薦使用第一種格式來定義數組。第一種不僅擁有更好的語義,而且具有更好的可讀性。
Java的模仿者C#不再支持type arrayName[]
這種語法,它只支持第一種定義教組的語法。越來越多的語言不再支持type arrayName[]
這種數紐定義語法。
數組是一種引用類型的變量,因此使用它定義一個變量時,僅僅表示定義了一個引用變量(也就是定義了一個指針),這個引用變量還未指向任何有效的內存。因此定義數組時不能指定數組的長度。
而且由於定義數組只是定義了一個引用變量,並未指向任何有效的內存空間,所以還沒有內存空間來存儲數組元素,因此這個數組也不能使用,只有對數組進行初始化後纔可以使用。
數組的初始化
Java語言中數組必須先初始化,然後纔可以使用。所謂初始化,就是爲數組的數組元素分配內存空間,併爲每個數組元素賦初始值。
數組初始化方法
- 靜態初始化:初始化時由程序員顯式指定每個數組元素的初始值,由系統決定數組長度。
- 動態初始化:初始化時程序員只指定數組長度,由系統爲數組元素分配初始值。
靜態初始化語法
arrayName = new type[] {element1 , element2 , element3 , element4 .. . }
在上面的語法格式中,前面的type就是數組元素的數據類型,此處的type必須與定義數組變量時所使用的type相同,也可以是定義數組時所指定的type的子類,並使用花括號把所有的數組元素括起來,多個數組元素之間以英文逗號,
隔開,定義初始化值的花括號緊跟在[]
之後。
值得指出的是,執行靜態初始化時,顯式指定的數組元素值的類型必須與new關鍵字後的type類型相同,或者是其子類的實例。
代碼示例
System.out.println("定義數組類型");
//定義一個int數組類型的變量,變量名爲array1
int[] array1;
//靜態初始化,初始化數組時只指定數組元素的初始值,不指定數組長度。
array1 = new int[]{14, 34, 2, 6};
//打印輸出數組的長度
System.out.println(array1.length);
Object[] objArr;
//使用靜態初始化 初始化數組時數組元素的類型是定義數組時所指定的數組元素類型的子類.
//String 類型是 Object 類型的子類,即 符串是 種特殊的 Object 實例
objArr = new String[]{"哈哈哈", "啦啦啦"};
System.out.println(objArr.length);
靜態初始化數組簡化寫法(只有在定義數組的 同時執行數組初始化才支持使用簡化的靜態初始化)
type[] arrayName = {elementl , element2 , element3 , element4...}
在實際開發過程中,可能更習慣將數組定義和數組初始化同時完成,
代碼示例
//數組定義和數組初始化同時完成
///數組的定義和初始化同時完成,使用簡化的靜態初始化寫法
char [] array2 = {'中', '國', '偉', '大'};
System.out.println(array2.length);
動態初始化語法
動態初始化只指定數組的長度,由系統爲每個數組元素指定初始值。動態初始化的語法格式:arrayName = new type[length];
數組的定義和初始化同時完成,使用動態初始化語法
代碼示例
int[] array3 = new int[3];
System.out.println(array3[0]);
System.out.println(array3[1]);
System.out.println(array3[2]);
//會拋出數組下標越界異常,因爲數組array3的長度爲3,array3[3]是取得第四個元素,第四個元素不存在,就會報錯並拋出異常。
//System.out.println(array3[3]);
//數組的定義和初始化同時完成,初始 數組時元素的類型是定義數組時元素類型的子類
Object[] array4 = new String[3];
System.out.println(array4[0]);
System.out.println(array4[1]);
System.out.println(array4[2]);
輸出
0
0
0
null
null
null
執行動態初始化時,程序員只需指定數組的長度,即爲每一數組元素指定所需的內存空間,系統將負責爲這些數組元素分配初始值。
指定初始值時,系統按如下規則分配初始值:
數組元素的類型是基本類型中的整數類型(byte、short、int、long),則數組元素的值是0
數組元素的類型是基本類型中的浮點類型(float、double)數組元素的值是0.0
數組元素的類型是基本類型中的字符類型(char),則數組元素的值是'\\uOOOO'
數組元素的類型是基本類型中的布爾類型(boolean)數組元素的值是false
數組元素的類型是引用類型(類、接口和數組) ,則數組元素的值是null
不要同時使用靜態初始化和動態初始化,也就是說,不要在進行數紐初始化時,既指定數組的長度,也爲每個數組元素分配初始值。
數組初始化完成後,就可以使用數組了,包括爲數組元素賦值,訪問數組元素值和獲得數組長度等。
使用數組
數組的索引是從0開始的
數組的聲明和取值
//數組的聲明
Object[] array1 = {"阿斯蒂芬", "asdf", "國防部", "dfs45"};
//數組的賦值
array1[0] = 1.5;
//數組的取值
System.out.println(array1[0]);//1.5
System.out.println(array1[1]);//asdf
System.out.println(array1[2]);//國防部
System.out.println(array1[3]);//dfs45
//數組越界異常:java.lang.ArrayIndexOutOfBoundsException: 4
// System.out.println(array1[4]);//dfs45
System.out.println(array1.length);//4
for (int i = 0; i < array1.length; i++) {
System.out.println(array1[i]);
}
/*
輸出:
阿斯蒂芬
asdf
國防部
dfs45
*/
String[] books = new String[3];
books[0] = "瘋狂Java講義";
books[1] = "瘋狂Python講義";
for (int j = 0; j < books.length; j++) {
System.out.println(books[j]);
}
/*
輸出
瘋狂Java講義
瘋狂Python講義
null
*/
foreach循環
- 使用foreach循環遍歷數組和集合元素時,無須獲得數組和集合長度,無須根據索引來訪問數組元素和集合元素,foreach循環自動遍歷數組和集合的每個元素。
- 語法
for (type variableName : array | collection){ // variableName自動態代訪問每個元素... } type是數組元素或集合元素的類型,variableName是一個形參名,foreach循環將自動將數組元素、集合元素依次賦給該變量.
代碼示例
Object[] array1 = {"阿斯蒂芬", "asdf", "國防部", "dfs45"};
for (Object varObj : array1
) {
System.out.println(varObj);
}
/*
輸出:
阿斯蒂芬
asdf
國防部
dfs45
*/
使用foreach循環來法代輸出數組元素或集合元素時,通常不要對循環變量進行賦值,雖然這種賦值在語法上是允許的,但沒有太大的實際意義, 且極容易引起錯誤。
代碼示例
Object[] array1 = {"阿斯蒂芬", "asdf", "國防部", "dfs45"};
for (Object var : array1
) {
var = "哈哈";
System.out.println(var);
}
System.out.println(array1[0]);
/*
輸出:
哈哈
哈哈
哈哈
哈哈
阿斯蒂芬
*/
- 使用foreach循環迭代數組元素時,並不能改變數組元素的值,因此不要對foreach的循環變量進行賦值。
- 當使用foreach來迭代數組元素時,foreach中的循環變量相當於一個臨時變量。
- 系統會把數組元素依次賦給這個臨時變量,而這個臨時變量並不是數組元素。
- 它只是保存了數組元素的值。因此,如果希望改變數組元素,則不能使用這種foreach循環。
深入數組
數組是一種引用數據類型,數組引用變量只是一個引用,數組元素和數組變量在內存裏是分開存放的。
內存中的數組
數組引用變量只是一個引用,這個引用變量可以指向任何有效的內存,只有當該引用指向有效內存後,纔可通過該數組變量來訪問數組元素。
實際的數組對象被存儲在堆(heap)內存中;如果引用該數組對象的數組引用變量是一個局部變量,那麼它被存儲在棧(stack)內存中。
如果需要訪問如圖4.2所示堆內存中的數組元素,則程序中只能通過p[index]
的形式實現。也就是說,數組引用變量是訪問堆內存中數組元素的根本方式。
- 如果堆內存中數組不再有任何引用變量指向自己,則這個數組將成爲垃圾,該數組所佔的內存將會被系統的垃圾回收機制回收。
- 因此,爲了讓垃圾回收機制回收一個數組所佔的內存空間,可以將該數組變量賦爲null,也就切斷了數組引用變量和實際數組之間的引用關係,實際的數組也就成了垃圾。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uA5wblu8-1588175789850)(https://www.wenbin.org.cn/upload/2020/04/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%9C%89%E6%A0%88%E5%86%85%E5%AD%98%E5%92%8C%E5%A0%86%E5%86%85%E5%AD%98%E4%B9%8B%E5%88%86-250588b978be482b93bf31841ec79a92-26c05bea063d427596b8e04e82ea4ee9.png)]
二維數組
代碼示例
//動態初始化
Object[][] arr = new String[3][2];
System.out.println("arr.length:" + arr.length);//輸出行數 3
System.out.println(arr[0].length);//輸出列數 2
System.out.println(arr[1].length);//輸出列數 2
System.out.println(arr[2].length);//輸出列數 2
// System.out.println(arr[3].length);//輸出列數 java.lang.ArrayIndexOutOfBoundsException: 3
//靜態初始化
int[][] intA = {{1, 2, 5, 2}, {2, 3}, {3, 4, 5}};
System.out.println("intA.length:" + intA.length);//輸出行數
System.out.println(intA[0].length);//輸出列數 4
System.out.println(intA[1].length);//輸出列數 2
System.out.println(intA[2].length);//輸出列數 3
輸出:
arr.length:3
2
2
2
intA.length:3
4
2
3
*/