編程語言 | Java - 04.流程控制和數組

流程控制一共有三種結構

1、順序結構。從上到下依次執行,中間沒有任何判斷和跳轉。
2、分支結構。根據條件來選擇性地執行某段代碼。
3、循環結構。根據循環條件重複執行某段代碼。


1.順序結構

從上到下依次執行,中間沒有任何判斷和跳轉。

  如果main方法的多行代碼之間沒有任何流程控制,則程序總是從上向下依次執行,排在前面的代碼先執行,排在後面的代碼後執行。這意味着:如果沒有流程控制,Java方法裏的語句是一個順序執行流,從上向下依次執行每條語句。


2.分支結構

if語句

  if語句使用布爾表達式或者布爾值作爲分支條件來進行分支控制。

第一種語法格式

if(返回boolean類型的表達式)
{
//要做的事情。
}

  程序代碼如下:IfTest1.java

public class IfTest1
{
    public static void main(String[] args) 
    {
        double money = 3200;
        System.out.println("我有" + money + "人民幣");

        //第一種語法格式
        if(money > 5000)
        {
            System.out.println("我有超過5000人民幣");  
        }   
    }
}

第二種語法格式

if(返回boolean類型的表達式)
{
//要做的事情。
}
else
{
//要做的事情。
}

  程序代碼如下:IfTest2.java

public class IfTest2 
{
    public static void main(String[] args) 
    {
        double money = 3200;
        System.out.println("我有" + money + "人民幣");

        //第二種語法格式
        if(money > 5000)
        {
            System.out.println("我有超過5000人民幣");  
        }   
        else
        {
            System.out.println("但是我的錢不夠5000人民幣");   
        }
    }
}

第三種語法格式

if(返回boolean類型的表達式)
{
//要做的事情。
}
else if(返回boolean類型的表達式)
{
//要做的事情。
}
…   //else if塊可以出現N次
else   //else塊可以出現0或者1次,即可省略
{
//要做的事情。
}

  程序代碼如下:IfTest3.java

public class IfTest3 
{
    public static void main(String[] args) 
    {
        double money = 3200;
        System.out.println("我有" + money + "人民幣");

        //第三種語法格式
        if(money > 5000)
        {
            System.out.println("我有超過5000人民幣");  
        }
        else if(money > 4000)
        {
            System.out.println("我有超過4000人民幣");  
        }
        else if(money > 3000)
        {
            System.out.println("我有超過3000人民幣");  
        }
        else if(money > 2000)
        {
            System.out.println("我有超過2000人民幣");  
        }
        else if(money > 1000)
        {
            System.out.println("我有超過2000人民幣");  
        }
        else
        {
            System.out.println("但是我的錢不夠5000人民幣");   
        }
    }
}

  注意點:
  1、如果條件執行體只有一行代碼,Java允許省略條件執行體的花括號。
    規則:如果省略了花括號,if條件只控制到第一個分號前面。
    建議:即使條件執行體只有一行語句,也用花括號。

    程序代碼如下:If省略花括號1.java

public class If省略花括號1 
{
    public static void main(String[] args) 
    {
        double money = 3200;
        System.out.println("我有" + money + "人民幣");
        System.out.println();

        if(money > 5000); // 這裏有分號,執行完這一句就跳出循環
            System.out.println("這裏已經不在循環裏面了");
            System.out.println("我的錢超過5000人民幣");
            System.out.println();

        if(money > 4000)
            System.out.println("我的錢超過4000人民幣"); // 這裏有分號,執行完這一句就跳出循環
            System.out.println("這裏已經不在循環裏面了,循環在上一個分號結束,因爲不滿足條件,所以不能輸出");
            System.out.println();

        if(money > 3000)
            System.out.println("我的錢超過3000人民幣");// 這裏有分號,執行完這一句就跳出循環
            System.out.println("這裏已經不在循環裏面了,循環在上一個分號結束,因爲滿足條件,所以有輸出"); 
    }
}

    程序代碼如下:If省略花括號2.java

public class If省略花括號2 
{
    public static void main(String[] args) 
    {
        double money = 3200;
        System.out.println("我有" + money + "人民幣");
        System.out.println();

        if(money > 5000)

            System.out.println("我的錢超過5000人民幣"); // 這裏有分號,執行完這一句就結束循環。
            System.out.println("這裏已經不在循環裏面了");

        else  //由於上面的if只能控制到第一個分號前面,所以此處的else是孤獨的,因此程序錯誤。

            System.out.println("我的錢不超過5000人民幣");
    }
}

  2、else本身就是條件。當我們有多個else if塊時,建議,先處理範圍小的條件。

    程序代碼如下:IfError.java

public class IfError 
{
    public static void main(String[] args) 
    {
        int age = 65;
        System.out.println("int age = 60;");
        System.out.println();

        if(age > 20)
        {
            System.out.println("歲數大於20");
        }
        else if(age > 40) // 相當於這句是else if((!(age > 20)) && (age > 40));也就是else if((age <= 20) && (age > 40));
        {
            System.out.println("歲數大於40");
        }
        else if(age > 60)
        {
            System.out.println("歲數大於60");
        }
        else 
        {
            System.out.println("歲數小於20");
        }
        System.out.println();

        //先處理範圍小的條件。
        if(age > 50)
        {
            System.out.println("歲數大於50");
        }
        else if(age > 40) 
        {
            System.out.println("歲數大於40");
        }
        else if(age > 20)
        {
            System.out.println("歲數大於20");
        }
        else 
        {
            System.out.println("歲數小於20");
        }
        System.out.println();

        //先處理範圍小的條件。
        if(age < 20)
        {
            System.out.println("歲數大於20");
        }
        else if(age < 40) 
        {
            System.out.println("歲數大於40");
        }
        else if(age < 60)
        {
            System.out.println("歲數大於60");
        }
        else 
        {
            System.out.println("歲數大於60");
        }
        System.out.println();

    }
}

switch語句
當等於某個值時,才執行一段代碼。

  switch語句後面的控制表達式的數據類型只能是byte、short、char、int四種整數類型、枚舉類型和java.lang.String類型(從Java7才允許),不能是boolean類型。

語法格式:

switch(返回值是byteshortcharintstring或枚舉的表達式)
{
case1 : 
//要做的事情
break; //可以省略
case2 : 
//要做的事情
break; //可以省略
case3 : 
//要做的事情
break; //可以省略
default : //當表達式的值與前面的case塊的值都不相等時,纔會執行
//要做的事情
break; //可以省略
}

    程序代碼如下:SwitchTest.java

public class SwitchTest 
{
    public static void main(String[] args) 
    {
        char score = 'B';

        switch (score)
        {
            case 'A':
                System.out.println("分數是A");
                break;
            case 'B':
                System.out.println("分數是B");
                break;
            case 'C':
                System.out.println("分數是C");
                break;
            case 'D':
                System.out.println("分數是D");
                break;
            default:
                System.out.println("分數不是A、B、C、D");
                break;
        }
    }
}

  注意點:
    省略break後,執行流程時,switch表達式的值,依次與每個case塊的值進行比較。
    當遇到一個相等的值之後,將繼續執行餘下所有的可執行性代碼。在直到遇到break語句之前,不會與case的值進行比較,而是直接執行代碼。
    建議:每次寫了case之後,在寫其他代碼之前,立即寫break。

    程序代碼如下:Switch省略break.java

public class Switch省略break 
{
    public static void main(String[] args) 
    {
        char score = 'B';

        switch (score)
        {
            case 'A':
                System.out.println("分數是A");
            case 'B':
                System.out.println("分數是B");
            case 'C':
                System.out.println("分數是C");
            case 'D':
                System.out.println("分數是D");
            default:
                System.out.println("分數不是A、B、C、D");
        }
        System.out.println("---------------------");

        switch (score)
        {
            case 'A':
                System.out.println("分數是A");
            case 'B':
                System.out.println("分數是B");
            case 'C':
                System.out.println("分數是C");
            case 'D':
                System.out.println("分數是D");
                break;
            default:
                System.out.println("分數不是A、B、C、D");
        }
    }
}

    程序代碼如下:活動計劃.java

import java.util.*;
import java.text.*;

public class 活動計劃
{
    public static void main(String[] args) 
    {
        //獲取系統的當前時間
        Date date = new Date();
        System.out.println("系統當前日期是:"+ date);// 輸出英文格式的時間
        System.out.println();

        //創建一個DateFormat實例,DateFormat作用就是把日期轉換成中文格式的時間的字符串。
        DateFormat df = DateFormat.getDateInstance(DateFormat.FULL);

        String str = df.format(date);
        System.out.println("系統當前日期是:"+ str); // 輸出中文格式的時間

        int spacePos = str.indexOf(" "); //獲取" "在前面字符串中的位置。
        //spacePos代表空格的位置,spacePos + 1代表空格後面的字符
        String day = str.substring(spacePos + 1); // 輸出中文格式的時間
        System.out.println();

        switch(day)
        {
            case "星期一":
                System.out.println("今天是星期一");
                break;
            case "星期二":
                System.out.println("今天是星期二");
                break;
            case "星期三":
                System.out.println("今天是星期三");
                break;
            case "星期四":
                System.out.println("今天是星期四");
                break;
            case "星期五":
                System.out.println("今天是星期五");
                break;
            case "星期六":
                System.out.println("今天是星期六");
                break;
            case "星期日":
                System.out.println("今天是星期日");
                break;
            default:
                System.out.println("今天不知道是星期幾");
                break;

        }       
    }
}

4.循環結構

  循環語句可以在滿足循環條件的情況下,反覆執行某一段代碼,這段被重複執行的代碼被稱爲循環體。當反覆執行進行這個循環體時,需要在合適的時候把循環條件改爲假,從而結束循環,否則循環將一直執行下去,形成死循環。

  循環語句可能包含如下4個部分:
    1)初始化語句:一條或者多條語句,用於完成一些初始化工作,在循環開始前執行。
    2)循環條件:這是一個boolean表達式,決定是否執行循環體。
    3)循環體:循環的主體,條件允許則被重複執行。
    4)迭代語句:在一次循環體執行後,對循環條件求值之前執行,通常控制循環條件中的變量,使得循環在合適的時候結束。

while循環

while(返回boolean值的表達式)
{
//需要重複做的事情。
}

  程序代碼如下:WhileTest.java

public class WhileTest 
{
    public static void main(String[] args) 
    {
        int i = 0;
        while(i < 10)
        {
            System.out.println("i的值爲:"+ i);
            i ++;
        }

    }
}

  如果循環體只有一條代碼,可以省略花括號。
  規則:如果省略了花括號,while條件只控制到第一個分號前面。
  建議:即使循環體只有一行代碼,也用花括號。
  使用while循環時,一定要保證循環條件有變成false的時候,否則這個循環將成爲一個死循環,永遠無法結束這個循環。

  程序代碼如下:WhileError1.java

public class WhileError1
{
    public static void main(String[] args) 
    {
        int i = 0;
        while(i < 10)
            System.out.println("i的值爲:"+ i++);// 這裏有分號,執行完這一句就重複循環到不滿足條件就結束循環。

            System.out.println("這裏不在循環內");

    }
}

  程序代碼如下:WhileError2.java

public class WhileError2
{
    public static void main(String[] args) 
    {
        int i = 0;
//      while(i < 10);
        //前一行代碼爲死循環,永遠爲true
        while(i++ < 10);
        {
            i ++;
            System.out.println("i的值爲:"+ i);
        }

    }
}

do while循環

do
{
//代碼段
} while(返回boolean值的表達式);

  這個與while相比,把循環放在前面,無論真假都會先執行一次,如果條件爲true,執行下一次循環。對於do while來說,至少都會執行一次。與while循環不同的是,do while循環的循環條件後必須有一個分號,才表明循環結束。

  程序代碼如下:DoWhileTest.java

public class DoWhileTest 
{
    public static void main(String[] args) 
    {
        int i = 0;
        do
        {
            System.out.println("i的值爲:"+ i);
        }
        while (i < -20);
    }
}

for 循環

for( 初始化語句; 返回boolean值的表達式; 每次循環體執行完後執行的代碼)
{
//循環體
}

  程序代碼如下:ForTest1.java

public class ForTest1
{
    public static void main(String[] args) 
    {
        for( ; ; )
        {
            System.out.println("這是死循環");
        }
    }
}

  程序代碼如下:ForTest2.java

public class ForTest2 
{
    public static void main(String[] args) 
    {
        int i = 0;
        for( i = 0 ; i < 10 ; i++ )
        {
            System.out.println("此時i的值爲:"+ i);
        }
        System.out.println();
        System.out.println("結束循環後,i的值爲:"+ i);
    }
}

  程序代碼如下:ForTest3.java

public class ForTest3
{
    public static void main(String[] args) 
    {
        int i = 0;

        for(i = 0 ; i < 10 ; i++ )
        {
            //System.out.println("此時i的值爲:"+ (i *= 0.2)); 
            //死循環,i = (int)(i * 0.2) 
            //第一次循環i = (int)(0 * 0.2) = 0;
            //第二次循環i = (int)(1 * 0.2) = 0;
            //第三次循環i = (int)(0 * 0.2) = 0;
            //第四次循環i = (int)(1 * 0.2) = 0;
        }
            System.out.println("結束循環後i的值爲:"+ i);
            System.out.println(); 

        for(i = 0 ; i < 10 ; i++ )
        {
            System.out.println("此時i的值爲:"+ (i *= 1.4)); //死循環,i = (int)(i * 1.4) 
            //第一次循環i = (int)(0 * 1.4) = 0;
            //第二次循環i = (int)(1 * 1.4) = 1;
            //第三次循環i = (int)(2 * 1.4) = 2;
            //第四次循環i = (int)(3 * 1.4) = 4;
            //第五次循環i = (int)(5 * 1.4) = 7;

        }
            //結束循環後繼續運算一次 i++ = 12;
            System.out.println("結束循環後i的值爲:"+ i);
    }
}

  程序代碼如下:ForTest4.java

public class ForTest4 
{
    public static void main(String[] args) 
    {
        for (int i = 2,j = 3 ,k = 2; i + j > k; )
        {
            //第一次循環i = 2;j = 3;k = 4;
            //第二次循環i = 3;j = 4;k = 8;
            //第三次循環i = 4;j = 5;k = 16;
            //第三次循環i = 5;j = 6;k = 32; 此時5 + 6 < 16,循環結束
            System.out.println("i的值爲"+ i++);
            System.out.println("j的值爲"+ j++);
            System.out.println("k的值爲"+ (k *= 2));
            System.out.println();
        }   
    }
}

  “初始化語句”可以省略。如果有“初始化語句”,程序執行for循環時,先執行循環的“初始化語句”,且只在循環開始前執行一次,允許同時指定多個初始化語句;

  “返回boolean值的表達式”可以省略。即循環條件語句,每次執行循環體之前,先計算該值,如果返回true,則執行循環體,如果省略,意味着他的值永遠是true;

  “每次循環體執行完後執行的代碼”可以省略。即循環迭代語句,這裏並沒有與循環體放在一起,因此即使在執行循環體時遇到continue語句結束本次循環,循環迭代語句也一樣會得到執行,如果不省略,將在每次循環體執行完成之後,開始下一次循環體之前,執行該代碼。

  只要兩個分號中間的表達式返回true,程序將執行循環體。
  條件表達式的計算次數總是比循環體執行次數多一次。

  建議:不要在循環體內修改循環變量(也叫循環計數器)的值,否則會增加程序出錯的可能性。萬一程序真的需要訪問、修改循環變量的值,建議重新定義一個臨時變量,先將循環變量的值賦給臨時變量,然後對臨時變量的值進行修改。

for each循環

  循環嵌套:
    在循環裏面,再放置循環。把內層循環當成外層循環的一條語句即可。

  程序代碼如下:循環嵌套.java

public class 循環嵌套 
{
    public static void main(String[] args) 
    {
        int i = 0;
        while(++i < 10)
        {
            System.out.println("進入外層循環;此時i="+ i);
            for(int j = 0; j < 10; j++ )
            {
                System.out.println("i的值爲:"+ i + ",j的值爲::"+ j);
            }
            System.out.println("外層循環的最後一行;此時i="+ i);
        }
        System.out.println();
        System.out.println("一共循環 "+ (i-1)*10 +" 次");
        System.out.println("最後i="+ i);

    }
}

4.控制循環結構

break
完全結束一個循環本身

  程序代碼如下:BreakTest.java

public class BreakTest
{
    public static void main(String[] args) 
    {
        int i = 0;
        for( ; ; )
        {
            System.out.println("i的值是 "+ i++);
            if(i > 12)
            {
                break; //完全停止一個循環
            }
        }
    }
}

continue
停止當前循環體的執行(忽略continue後的語句),開始下一次循環體。

  如果continue位於循環體的最後部分,他就是多餘的。

  程序代碼如下:ContinueTest.java

public class ContinueTest
{
    public static void main(String[] args) 
    {
        int i = 0;
        for(i = 0; i < 7; i++)
        {
            System.out.println("i的值是 "+ i);
            if(i > 3)
            {
                break; //完全停止一個循環
            }
        }
        System.out.println();
        for(i = 0; i < 7; i++)
        {
            System.out.println("i的值是 "+ i);
            if(i > 3)
            {
                continue; //完全停止一個循環
            }
        }
        System.out.println();
        for(i = 0; i < 7; i++)
        {
            System.out.println("i的值是 "+ i);
            if(i > 3)
            {
                continue; //完全停止一個循環
            }
            System.out.println("----i的值是 "+ i);
        }
        System.out.println();
        for(i = 0; i < 7; i++)
        {
            System.out.println("i的值是 "+ i);
            if(i > 3)
            {
                return; //完全停止一個循環
            }
            System.out.println("----i的值是 "+ i);
        }
    }
}

return
結束整個方法。遇到return,方法就會結束執行。

  程序代碼如下:ReturnTest.java

public class ReturnTest 
{
    public static void main(String[] args) 
    {
        int i = 0;
        while(++i < 10)
        {
            System.out.println("進入外層循環");
            for (int j = 0; j < 10 ; j++ )
            {
                for (int k = 0; k < 20 ; k++)
                {
                    System.out.println("i的值爲:"+ i +",j的值爲:"+ j +",k的值爲:"+ k );
                    if (k > 3)
                    {
                        return;
                    }
                    System.out.println("---i的值爲:"+ i +",j的值爲:"+ j +",k的值爲:"+ k );
                }
            }
            System.out.println("外層循環的最後一行");
        }
    }
}

break、continue後可以緊跟標號
帶標號的break用於結束標號所標識的循環。

  帶標號的continue用於忽略標號所標識的循環後面剩下的語句。

  程序代碼如下:BreakLabelTest.java

public class BreakLabelTest
{
    public static void main(String[] args) 
    {
        outer:
        for (int i = 0; i < 10; i ++)
        {
            for (int j = 0; j < 10; j++)
            {
                System.out.println("i的值爲:"+ i +",j的值爲:"+ j);
                if (j > 3)
                {
                    break outer;//帶標號的循環用於結束標號所在的循環
                }
                System.out.println("---i的值爲:"+ i +",j的值爲:"+ j);
            }
            System.out.println();
        }
    }
}

  程序代碼如下:ContinueLabelTest1.java

public class ContinueLabelTest1 
{
    public static void main(String[] args) 
    {
        outer:
        for (int i = 0; i < 10; i ++)
        {
            System.out.println();
            for (int j = 0; j < 10; j++)
            {
                System.out.println("i的值爲:"+ i +",j的值爲:"+ j);
                if (j > 3)
                {
                    continue outer;//帶標號的循環用於結束標號所在的循環
                }
                System.out.println("---i的值爲:"+ i +",j的值爲:"+ j);
            }
        }
    }
}

  程序代碼如下:ContinueLabelTest2.java

public class ContinueLabelTest2 
{
    public static void main(String[] args) 
    {
        outer:
        for (int i = 0; i < 10; i ++)
        {       
            for (int j = 0; j < 10; j++)
            {
                System.out.println("i的值爲:"+ i +",j的值爲:"+ j);
                if (i > 3)
                {
                    continue outer;//帶標號的循環用於結束標號所在的循環
                }
                System.out.println("---i的值爲:"+ i +",j的值爲:"+ j);
            }
            System.out.println();
        }
    }
}

5.數組類型

  爲什麼要用數組?
    如果程序中需要用到多個相同類型的變量,就可以考慮把它們集中定義成一個數組。每個數組元素,就相當於一個普通的變量。藉助於數組,我們可以非常方便地去管理、訪問每個數組元素(相當於一個變量)

  數組也是一種類型,Java的數組要求所有的數組元素具有相同的數據類型。因此,在一個數組中,數組元素的類型是唯一的,即一個數組裏只能存儲一種數據類型的數據,而不能存儲多種數據類型的數據。

數組類型

  Java數據類型可以分爲:
    基本類型 – 8個
    引用類型 – 類/接口/數組

  數組類型也是一種數據類型,它本身是一種引用類型。既可用於創建變量,也可用於進行強制類型轉換。
    int -> int[ ] -> 整型數組
    double -> double [ ] -> double型數組
    …
    string -> string[ ] -> string型數組

    int[ ] -> int[ ][ ] -> 新的數組類型。整型數組
    int[ ][ ] -> int[ ][ ][ ] -> 新的數組類型。整型數組

  int[ ]就是一種數據類型,與int類型、String類型相似,一樣可以使用該類型來定義變量,也可以使用該類型進行類型轉換等。使用int[ ]類型來定義變量、進行類型轉換時與其它普通類型沒有任何區別。int[ ]類型是一種引用類型,創建int[ ]類型的對象也就是創建數組,需要使用創建數組的語法。

  變量分爲兩種:
    1、直接在該變量中存放實際的變量值,這就是Java的基本類型的變量。
    2、在變量中存放只是內存的地址值,這就是所謂的引用變量。

  數組是一種引用類型的變量,因此使用它定義一個變量時,僅僅表示定義了一個引用變量(也就是定義了一個指針),只不過它裏面存的值是內存地址,這個引用變量還未指向任何有效的內存,因此定義數組時不能指定數組的長度。而且由於定義數組只是定義了一個引用變量,並未指向任何有效的內存空間,所以還沒有內存空間來存儲數組元素,因此這個數組也不能使用,只有對數組進行初始化後纔可以使用。

  定義數組:定義時不能指定數組的長度。

程序代碼如下:ArrayTypeTest.java

public class ArrayTypeTest 
{
    public static void main(String[] args) 
    {
        //類型 變量名
        int a[]; //不好的寫法
        //看起來好像定義了一個類型爲int的變量,變量名爲a[],與真實的含義相距勝遠。

        //類型是int[],變量名是a
        int[] a; //好的寫法
        //第二種寫法很容易理解只是定義一個變量,其中變量名是a,而變量類型是int[]。
        //實際上int[]確實是一種新類型,也符合定義變量的語法。

        System.out.println("Hello World!");
    }
}

Java數組的特徵:
  Java語言是強類型, 一個數組裏只能存儲一種數據類型的數據。
  Java語言是靜態的, Java的數組一旦被初始化後,它的長度是固定的。

數組的初始化:
  數組變量只是一個引用,必須讓它指向有效的內存之後才能使用。初始化就是爲數組的數組元素分配內存空間,併爲每個數組元素賦初始值。

  一旦爲數組的每個數組元素分配了內存空間,每個內存空間裏存儲的內容就是該數組元素的值,即使這個內存空間存儲的內容是空,這個空也是一個值(null)。不管以哪種方式來初始化數組,只要爲數組元素分配了內存空間,數組元素就具有了初始值。初始值的獲得有兩種形式:一種由系統自動分配;另一種由程序員指定。

  靜態初始化:只指定數組的元素,讓系統來決定數組的長度。

new < type > [ ] { <ele1>, <ele2>, <ele3> …} ;

  動態初始化:只指定數組的長度,讓系統來決定數組的元素的值。

new < type > [<length>] {  } ;

程序代碼如下:數組測試.java

public class 數組測試
{
    public static void main(String[] args) 
    {
        int[] iArr; //聲明瞭一個數組變量,引用類型變量,他存放的是內存地址。
        iArr = new int[]{ 20, 1, 12, 31};
        //iArr是一個引用類型的變量,也就是iArr存放了後面創建的數組的地址。

        System.out.println("int[] iArr;  iArr = new int[]{ 20, 1, 12, 31};");
        System.out.println("iArr[0] = "+ iArr[0] );
        System.out.println();

        iArr[0] = 100;
        System.out.println("當:iArr[0] = 100;");
        System.out.println("iArr[0] = "+ iArr[0] );
        System.out.println();

        iArr[0] = 'c';//'a'本來是char,但由於char可以自動轉換爲int類型
        System.out.println("當:iArr[0] = 'c';");
        System.out.println("iArr[0] = "+ iArr[0] ); 
        System.out.println();

        //動態初始化
        String[] strArr = new String[5];

        //第一個數組元素的索引是0
        //最後一個數組元素的索引是length-1
        //遍歷數組元素
        for (int i = 0; i < strArr.length; i++ )
        {
            System.out.println("strArr[" + i + "] = "+ strArr[i] ); 
        }
        System.out.println();

        //把數組的最後一個元素賦值爲"鄔森平"
        strArr[strArr.length-1] = "鄔森平";
        //遍歷數組元素
        for (int i = 0; i < strArr.length; i++ )
        {
            System.out.println("strArr[" + i + "] = "+ strArr[i] ); 
        }
        System.out.println();

        //當我們訪問數組元素的索引小於0或者大於等於length,將引發“數組索引越界”異常。
        System.out.println("strArr[" + strArr.length + "] = "+ strArr[strArr.length] ); 

    }
}

  如果數組的元素是基本類型(整數型/浮點型/布爾型/字符型),那麼所有數組元素的值都是0 / 0.0 / false / ‘\u0000’。
  如果數組的元素是引用類型(類/接口/數組),那麼所有數組元素的值都是null。
  不能同時用靜態初始化跟動態初始化
  一旦數組的初始化完成,接下來的每個數組元素就可以當成普通變量使用了。

使用數組

  每個數組元素相當於一個變量,該變量的類型,就是數組類型去掉一個方括號。
  數組有一個length屬性,用於返回該數組的長度。

程序代碼如下:數組測試.java

public class 數組測試
{
    public static void main(String[] args) 
    {
        int[] iArr; //聲明瞭一個數組變量,引用類型變量,他存放的是內存地址。
        iArr = new int[]{ 20, 1, 12, 31};
        //iArr是一個引用類型的變量,也就是iArr存放了後面創建的數組的地址。

        System.out.println("int[] iArr;  iArr = new int[]{ 20, 1, 12, 31};");
        System.out.println("iArr[0] = "+ iArr[0] );
        System.out.println();

        iArr[0] = 100;
        System.out.println("當:iArr[0] = 100;");
        System.out.println("iArr[0] = "+ iArr[0] );
        System.out.println();

        iArr[0] = 'c';//'a'本來是char,但由於char可以自動轉換爲int類型
        System.out.println("當:iArr[0] = 'c';");
        System.out.println("iArr[0] = "+ iArr[0] ); 
        System.out.println();

        //動態初始化
        String[] strArr = new String[5];

        //第一個數組元素的索引是0
        //最後一個數組元素的索引是length-1
        //遍歷數組元素
        for (int i = 0; i < strArr.length; i++ )
        {
            System.out.println("strArr[" + i + "] = "+ strArr[i] ); 
        }
        System.out.println();

        //把數組的最後一個元素賦值爲"鄔森平"
        strArr[strArr.length-1] = "鄔森平";
        //遍歷數組元素
        for (int i = 0; i < strArr.length; i++ )
        {
            System.out.println("strArr[" + i + "] = "+ strArr[i] ); 
        }
        System.out.println();

        //當我們訪問數組元素的索引小於0或者大於等於length,將引發“數組索引越界”異常。
        System.out.println("strArr[" + strArr.length + "] = "+ strArr[strArr.length] ); 

    }
}

遍歷數組

  1)可以依次根據每個數組元素的索引來進行遍歷。
  2)可以使用foreach循環來遍歷。

for(數組或者集合的數據類型 變量名:數組/集合)
{
//此處即可通過“變量名”依次訪問每個數組/集合的元素。
}

  注意:foreach循環時。不要對循環變量賦值。
    如果需要在遍歷的時候對數組元素進行賦值,那就應該根據數組元素的索引來進行遍歷。

程序代碼如下:ForEachTest.java

public class ForEachTest 
{
    public static void main(String[] args) 
    {
        //靜態初始化
        double[] duArr = new double[]{3.2,20.0,100.1};
        //簡化寫法:double[] duArr = {3.2,20.0,100.1};

        for (double ele : duArr)
        {
            System.out.println("ForEach遍歷數組元素:"+ ele);
        }
        System.out.println();

        for (double ele : duArr)
        {
            ele = 100.0; //foreach循環中,對循環變量賦值沒有太大的意義,因此數組元素不會受到影響
            System.out.println("ForEach遍歷數組元素:"+ ele);
        }
        System.out.println();

        //遍歷數組元素
        for (int i = 0; i < duArr.length; i++ )
        {
            System.out.println("duArr[" + i + "] = "+ duArr[i] );   
        }
        System.out.println();

        //遍歷數組元素 + 賦值
        for (int i = 0; i < duArr.length; i++ )
        {
            duArr[i] = 100.0; 
            System.out.println("duArr[" + i + "] = "+ duArr[i] );   
        }
        System.out.println();
    }
}

6.深入數組

內存中的數組

  數組引用變量只是一個引用,這個引用變量可以指向任何有效的內存,只有當該引用指向有效內存後,纔可通過該數組變量來訪問數組元素。

  與所有引用變量相同的是,引用變量是訪問真實對象的根本方式。也就是說,如果希望在程序中訪問數組對象本身,則只能通過這個數組的引用變量來訪問它。

  實際的數組對象被存儲在堆內存中;如果引用該數組對象的數組引用變量是一個局部變量,那麼它被存儲在棧內存中。

數組在內存中的存儲示意圖數組在內存中的存儲示意圖

  如果需要訪問上圖所示的堆內存中的數組元素,則程序中只能通過p[index]的形式實現。也就是說,數組引用變量是訪問堆內存中數組元素的根本方式。

程序代碼如下:PriArrayTest.java

public class PriArrayTest
{
    public static void main(String[] args) 
    {
        //所有在方法裏聲明的變量,都放在相應的方法棧
        /*
         * 每個方法運行時,系統都會爲之建立一個方法棧
         * 棧內存是臨時性的內存,當方法結束時,方法棧會被立即釋放
         * 所以棧內存不適合存放長期有效的數據
         * 堆內存:每個Java虛擬機JVM只有一個。
         * 只要JVM不退出,堆內存一直存在。
         */

        double d = 23.9; //d是基本類型
        int[] iarr = null; //它只是數組變量,引用變量,此時這個iarr不能使用。

        //NullPointerException異常,空指針異常。
        //當程序訪問一個null對象的實例方法或實例屬性
        //程序就會引發NullPointerException異常
        //System.out.println("int[] iarr; iarr[0]"+ iarr[0]);

        iarr = new int[4]; //所有的對象都放在"堆"內存。每個Java虛擬機JVM只有一個"堆"內存。

        //在Java程序中,只要訪問“引用”的方法、屬性時,系統會自動切換到訪問它實際的對象。
        //堆內存中的對象,只能通過引用變量來訪問。
        iarr[2] = 34; // 34是基本類型,但實際上存在堆內存中。

        System.out.println("iarr.length = "+ iarr.length);

        //靜態初始化的簡化語法
        int[] ba = {12, 20, 103};
    }
}

  當數組對象的引用變量被銷燬之後,這個數組對象並不一定會被回收(它在堆內存),它不會隨着數組變量被回收。

  只有當沒有引用變量引用這個數組對象時,系統纔會去回收數組對象。

爲什麼有棧內存和堆內存之分?

  當一個方法執行時,每個方法都會建立自己的內存棧,在這個方法內定義的變量將會逐個放入這塊棧內存裏,隨着方法的執行結束,這個方法的內存棧也將自然銷燬。因此,所有在方法中定義的局部變量都是放在棧內存中的;在程序中創建一個對象時,這個對象將被保存到運行時數據區中,以便反覆利用(因爲對象的創建成本通常較大),這個運行時數據區就是堆內存。堆內存中的對象不會隨方法的結束而銷燬,即使方法結束後,這個對象還可能被另一個引用變量所引用(在方法的參數傳遞時很常見),則這個對象依然不會被銷燬。只有當一個對象沒有任何引用變量引用它時,系統的垃圾回收器纔會在合適的時候回收它。

  如果堆內存中數組不再有任何引用變量指向自己,則這個數組將變成垃圾,該數組所佔的內存將會被系統的垃圾回收機制回收。因此,爲了讓垃圾回收機制回收一個數組所佔的內存空間,可以將該數組變量賦爲null,也就切斷了數組引用變量和實際數組之間的引用關係,實際的數組也就成了垃圾。

  只要類型相互兼容,就可以讓一個數組變量指向另一個實際的數組,這種操作會讓人產生數組的長度可變的錯覺。

程序代碼如下:ArrayInRam.java

public class ArrayInRam
{
    public static void main(String[] args)
    {
        // 定義並初始化數組,使用靜態初始化
        int[] a = {5, 7 , 20};
        // 定義並初始化數組,使用動態初始化
        int[] b = new int[4];
        // 輸出b數組的長度
        System.out.println("b數組的長度爲:" + b.length);
        // 循環輸出a數組的元素
        for (int i = 0 ,len = a.length; i < len ; i++ )
        {
            System.out.println(a[i]);
        }
        // 循環輸出b數組的元素
        for (int i = 0 , len = b.length; i < len ; i++ )
        {
            System.out.println(b[i]);
        }
        // 因爲a是int[]類型,b也是int[]類型,所以可以將a的值賦給b。
        // 也就是讓b引用指向a引用指向的數組
        b = a;
        // 再次輸出b數組的長度
        System.out.println("b數組的長度爲:" + b.length);
    }
}

  運行上面代碼後,將可以看到先輸出b數組的長度爲4,然後依次輸出a數組和b數組的每個數組元素,接着會輸出b數組的長度爲3.看起來似乎數組的長度是可變的,但這只是一個假象。

  必須牢記:定義並初始化一個數組後,在內存中分配了兩個空間,一個用於存放數組的引用變量,另一個用於存放數組本身。下面將結合示意圖來說明上面程序的運行過程。

定義並初始化a、b兩個數組後的存儲示意圖定義並初始化a、b兩個數組後的存儲示意圖

  當程序定義並初始化了a、b兩個數組後,系統內存中實際上產生了4塊內存區,其中棧內存中有兩個兩個引用變量:a和b;對內存中也有兩塊內存區,分別存儲a和b引用所指向的數組本身。此時可以看到a引用和b引用各自所引用的數組對象,a變量所引用的數組長度爲3,b變量所引用的數組長度爲4.

讓b引用指向a引用所指向數組後的存儲示意圖讓b引用指向a引用所指向數組後的存儲示意圖

  當執行b = a時,系統將會把a的值賦給b,a和b都是引用類型變量,存儲的是地址。因此把a的值賦給b後,就是讓b指向a所指向的地址。當執行b = a後,堆內存中的第一個數組具有了兩個引用;a變量和b變量都引用了第一個數組。此時第二個數組失去了引用,變成垃圾,只有等待垃圾回收機制來回收它——但它的長度依然不會改變,知道它徹底消失。

基本類型數組的初始化

  對於基本類型數組而言,數組元素的值直接存儲在對應的數組元素中,因此,初始化數組時,先爲該數組分配內存空間,然後直接將數組元素的值存入對應數組元素中。

  下面程序定義了一個int[ ]類型的數組變量,採用動態初始化的方式初始化了該數組,並顯式爲每個數組元素賦值。

程序代碼如下:PrimitiveArrayTest.java

public class PrimitiveArrayTest
{
    public static void main(String[] args)
    {
        // 定義一個int[]類型的數組變量
        int[] iArr;
        // 動態初始化數組,數組長度爲5
        iArr = new int[5];
        // 採用循環方式爲每個數組元素賦值。
        for (int i = 0; i <iArr.length ; i++ )
        {
            iArr[i] = i + 10;
        }
    }
}

定義iArr數組變量後的存儲示意圖定義iArr數組變量後的存儲示意圖

  執行第一行代碼int[ ] iArr;時,僅定義了一個數組變量。

  執行int[ ] iArr;後,僅在棧內存中定義了一個空引用(就是iArr數組變量),這個引用並未指向任何有效的內存,當然無法指定數組的長度。

動態初始化iArr數組後的存儲示意圖動態初始化iArr數組後的存儲示意圖

  當執行iArr = new int[5];動態初始化後,系統將負責爲該數組分配內存空間,並分配默認的初始值:所有數組元素都被賦爲值0,。

顯式指定每個數組元素值後的存儲示意圖顯式指定每個數組元素值後的存儲示意圖

  此時iArr數組的每個數組元素的值都是0,當循環爲該數組的每個數組元素依次賦值後,此時每個數組元素的值都變成程序顯式指定的值。每個數組元素的值直接存儲在對應的內存中。操作基本類型數組的數組元素時,實際上相當於操作基本類型的變量。

引用類型數組的初始化
. 程序代碼如下:ReferenceArrayTest.java

class Person
{
    public int age; // 年齡
    public double height; // 身高
    // 定義一個info方法
    public void info()
    {
        System.out.println("我的年齡是:" + age
            + ",我的身高是:" + height);
    }
}
public class ReferenceArrayTest
{
    public static void main(String[] args)
    {
        // 定義一個students數組變量,其類型是Person[]
        Person[] students;
        // 執行動態初始化
        students = new Person[2];
        // 創建一個Person實例,並將這個Person實例賦給zhang變量
        Person zhang = new Person();
        // 爲zhang所引用的Person對象的age、height賦值
        zhang.age = 15;
        zhang.height = 158;
        // 創建一個Person實例,並將這個Person實例賦給lee變量
        Person lee = new Person();
        // 爲lee所引用的Person對象的age、height賦值
        lee.age = 16;
        lee.height = 161;
        // 將zhang變量的值賦給第一個數組元素
        students[0] = zhang;
        // 將lee變量的值賦給第二個數組元素
        students[1] = lee;
        // 下面兩行代碼的結果完全一樣,因爲lee
        // 和students[1]指向的是同一個Person實例。
        lee.info();
        students[1].info();
    }
}

定義一個students數組變量後的存儲示意圖定義一個students數組變量後的存儲示意圖

  執行Person[ ] student;時,僅僅在棧內存定義了一個引用變量,也就是一個指針,這指針並未指向任何有效的內存區。即在棧內存中定義了一個student變量,它僅僅是一個引用,並未指向任何有效的內存。

動態初始化students數組後的存儲示意圖 動態初始化students數組後的存儲示意圖

  直到執行初始化,本程序對student數組執行動態初始化,動態初始化由系統爲數組元素分配默認的初始值:null,即每個數組元素的值都是null。

  student數組的兩個數組元素都是引用,而且引用並未指向任何有效的內存,因此每個數組元素的值都是null。這意味着依然不能直接使用student數組元素,因爲每個數組元素都是null,這相當於定義了兩個連續的Person變量,但這個變量還未指向任何有效的內存區,所以這兩個連續的Person變量(student數組的數組元素)還不能使用。

創建兩個Person實例後的存儲示例圖創建兩個Person實例後的存儲示例圖

  接着的代碼定義了zhang和lee兩個person實例,定義這兩個實例實際上分配了4塊內存,在棧內存中存儲了zhang和lee兩個引用變量,還在堆內存中存儲了兩個Person實例。

爲數組元素賦值後的存儲示意圖爲數組元素賦值後的存儲示意圖

  此時student數組的兩個數組元素依然是null,知道程序依次將zhang賦給student數組的第一個元素,把lee賦給student數組的第二個元素,student數組的兩個數組元素將會指向有效的內存區。

  此時,zhang和student[0]指向同一個內存區,而且它們都是引用類型變量,因此通過zhang和student[0]來訪問Person實例的實例變量和方法的效果完全一樣,不論修改student[0]所指向的Person實例的實例變量,還是修改zhang變量所指向的Person實例的實例變量,所修改的其實是用一個內存區,所以必然互相影響。同理,lee和student[1]也是引用同一個Person對象,也具有相同的效果。

多維數組

  所謂的“二維”數組:
    int[ ] – > int[ ][ ]
    int[ ][ ] – > int[ ][ ][ ]

  三維數組的元素是二維數組。
  二維數組的元素是一維數組
  N維數組的元素是N-1維數組
.
程序代碼如下:多維數組.java

public class 多維數組
{
    public static void main(String[] args) 
    {
        int[][] a = new int[2][3];  
        System.out.println("a的長度:"+ a.length);
        System.out.println();

        //a的length是2
        for (int i = 0; i < a.length; i++)
        {
            for (int j = 0; j < a[i].length; j++)
            {
                System.out.print(a[i][j] +"\t");
            }
            System.out.println();
        }
        System.out.println();

        a[1] = new int[]{ 13, 23, 10, 24};
        //a的length是2
        for (int i = 0; i < a.length; i++)
        {
            for (int j = 0; j < a[i].length; j++)
            {
                System.out.print(a[i][j] +"\t");
            }
            System.out.println();
        }
    }
}

程序代碼如下:MultiDimenTest.java

public class MultiDimenTest 
{
    public static void main(String[] args) 
    {
        int[][] arr; //只是一個引用變量

        //動態初始化,由系統爲數組元素賦值
        arr = new int[4][]; //Java允許初始化數組時只初始化左邊的維數

        System.out.println("arr[1] = " + arr[1]);//arr[1]相當於一個int[]變量
        System.out.println();

        arr[1] = new int[]{12,15};
        System.out.println("arr[1] = " + arr[1]);
        System.out.println();

//      arr[1][2] = 30; //引發數組索引越界異常

//      arr[2][0] = 13; //由於arr[2]相當於int[]類型的變量(即引用變量),此時它還未指向有效的內存。因此會引發NullPointerException

        int[] a = new int[3];  //動態初始化

        arr[2] = a; //把a變量存放的地址賦給arr[2]

        a[2] = 102;

        for (int i = 0; i < arr[2].length; i++)
        {
            System.out.println("arr[2]["+ i +"] = " + arr[2][i]);
        }
        System.out.println();

        for (int i = 0; i < arr[2].length; i++)
        {
            System.out.println("arr[2]["+ i +"] = " + arr[2][i]);
            if (i == 1)
            {
                arr[2][i] = 23;
            }
            System.out.println("----arr[2]["+ i +"] = " + arr[2][i]);
        }
        System.out.println();

        for (int i = 0; i < a.length; i++)
        {
            System.out.println("a["+ i +"] = " + a[i]);
        }
    }
}

程序代碼如下:TwoDimensionTest.java

public class TwoDimensionTest
{
    public static void main(String[] args)
    {
        // 定義一個二維數組
        int[][] a;
        // 把a當成一維數組進行初始化,初始化a是一個長度爲4的數組
        // a數組的數組元素又是引用類型
        a = new int[4][];
        // 把a數組當成一維數組,遍歷a數組的每個數組元素
        for (int i = 0 , len = a.length; i < len ; i++ )
        {
            System.out.println(a[i]);
        }
        // 初始化a數組的第一個元素
        a[0] = new int[2];
        // 訪問a數組的第一個元素所指數組的第二個元素
        a[0][1] = 6;
        // a數組的第一個元素是一個一維數組,遍歷這個一維數組
        for (int i = 0 , len = a[0].length ; i < len ; i ++ )
        {
            System.out.println(a[0][i]);
        }

        // 同時初始化二維數組的2個維數
        int[][] b = new int[3][4];

        // 使用靜態初始化的語法來初始化一個二維數組
        String[][] str1 = new String[][]{new String[3]
            , new String[]{"hello"}};
        // 使用簡化的靜態初始化語法來初始化二維數組
        String[][] str2 = {new String[3]
            , new String[]{"hello"}};
        System.out.println(str1[1][0]);
        System.out.println(str2[1][0]);
    }
}

  程序的第一行int[ ][ ] a;將在棧內存中定義一個引用變量,這個變量並未指向任何有效的內存空間,此時的堆內存還未爲這行代碼分配任何存儲區。

  程序對a數組執行初始化:a = new int[4][ ];這行代碼讓a變量指向一塊長度爲4的數組內存,這個長度爲4的數組裏每個數組元素都是引用類型(數組類型),系統爲這些數組元素分配默認的初始值:null。

將二維數組當成一維數組初始化的存儲示意圖將二維數組當成一維數組初始化的存儲示意圖

  雖然聲明a是一個二維數組,但這裏絲毫看不出它是一個二維數組的樣子,完全是一維數組的樣子。這個一維數組的長度是4,只是這4個數組元素都是引用類型,它們的默認值是null。所以程序中可以把a數組當成一維數組處理,依次遍歷a數組的每個元素,將看到數組元素的值都是null。

  由於a數組的元素必須是int[ ]數組,所以接下來的程序對a[0]元素執行初始化,也就是讓上圖右邊堆內存中的第一個數組元素指向一個有效的數組內存,指向一個長度爲2的int數組。因爲程序採用動態初始化a[0]數組,因此係統將爲a[0]所引用數組的每個元素分配默認的初始值:0,然後程序顯式爲a[0]數組的第二個元素賦值爲6.如下圖,接着迭代輸出a[0]數組的每個數組元素,將看到輸出0和6.

初始化a[0]後的存儲示意圖初始化a[0]後的存儲示意圖

// 同時初始化二維數組的2個維數
int[][] b = new int[3][4];

  定義一個b數組變量,這個數組變量指向一個長度爲3的數組,這個數組的每個數組元素又是一個數組類型,它們各指向對應的長度爲4的int[]數組,每個數組元素的值爲0.如下圖:

同時初始化二維數組的兩個維數後的存儲示意圖同時初始化二維數組的兩個維數後的存儲示意圖

// 使用靜態初始化的語法來初始化一個二維數組
String[][] str1 = new String[][]{new String[3],new String[]{"hello"}};
// 使用簡化的靜態初始化語法來初始化二維數組
String[][] str2 = {new String[3],new String[]{"hello"}};
System.out.println(str1[1][0]);
System.out.println(str2[1][0]);

  還可以使用靜態初始化方式來初始化二維數組。使用靜態初始化方式來初始化二維數組時,二維數組的每個數組元素都是一維數組,因此必須指定多個一維數組作爲二維數組的初始化值。如下圖:

採用靜態初始化語法初始化二維數組的存儲示意圖採用靜態初始化語法初始化二維數組的存儲示意圖

Array工具類

  Arrays類處於java.util包下,爲了在程序中使用Arrays類,必須在程序中導入java.util.Arrays類。

程序代碼如下:Arrays工具類.java

import java.util.*;

public class     
{
    public static void main(String[] args) 
    {
        int[] a = new int[]
            { 12, 23, 34, 37, 41, 46, 54, 67};
        int index1 = Arrays.binarySearch( a, 46);
        System.out.println("index1 = "+ index1);
        System.out.println();

        int[] b = new int[]
            { 12, 23, 34, 37, 41, 54, 67};
        int index2 = Arrays.binarySearch( b, 46);
        System.out.println("index2 = "+ index2); 
        System.out.println();

        //將b數組的從索引爲1的元素~索引爲5(不包括5)的元素,都填充成20
        Arrays.fill( b, 1, 5, 20);
        System.out.println("b = "+ b); //直接打印數組,看到 [ 數組類型的首字母大寫 @ 地址值
        System.out.println();

        //Arrays的toString可以直接看到數組元素的值
        System.out.println("Arrays.toString(b) = "+ Arrays.toString(b)); 
        System.out.println();
    }
}

程序代碼如下:ArraysTest.java

import java.util.Arrays;

public class ArraysTest
{
    public static void main(String[] args)
    {
        // 定義一個a數組
        int[] a = new int[]{3, 4 , 5, 6};
        // 定義一個a2數組
        int[] a2 = new int[]{3, 4 , 5, 6};
        // a數組和a2數組的長度相等,每個元素依次相等,將輸出true
        System.out.println("a數組和a2數組是否相等:"
            + Arrays.equals(a , a2));
        // 通過複製a數組,生成一個新的b數組
        int[] b = Arrays.copyOf(a, 6);
        System.out.println("a數組和b數組是否相等:"
            + Arrays.equals(a , b));
        // 輸出b數組的元素,將輸出[3, 4, 5, 6, 0, 0]
        System.out.println("b數組的元素爲:"
            + Arrays.toString(b));
        // 將b數組的第3個元素(包括)到第5個元素(不包括)賦爲1
        Arrays.fill(b , 2, 4 , 1);
        // 輸出b數組的元素,將輸出[3, 4, 1, 1, 0, 0]
        System.out.println("b數組的元素爲:"
            + Arrays.toString(b));
        // 對b數組進行排序
        Arrays.sort(b);
        // 輸出b數組的元素,將輸出[0, 0, 1, 1, 3, 4]
        System.out.println("b數組的元素爲:"
            + Arrays.toString(b));
    }
}

程序代碼如下:ArraysTest2.java

import java.util.Arrays;
import java.util.function.*;

public class ArraysTest2
{
    public static void main(String[] args)
    {
        int[] arr1 = new int[]{3, -4 , 25, 16, 30, 18};
        // 對數組arr1進行併發排序
        Arrays.parallelSort(arr1);
        System.out.println(Arrays.toString(arr1));
        int[] arr2 = new int[]{3, -4 , 25, 16, 30, 18};
        Arrays.parallelPrefix(arr2, new IntBinaryOperator()
        {
            // left代表數組中前一個所索引處的元素,計算第一個元素時,left爲1
            // right代表數組中當前索引處的元素
            public int applyAsInt(int left, int right)
            {
                return left * right;
            }
        });
        System.out.println(Arrays.toString(arr2));
        int[] arr3 = new int[5];
        Arrays.parallelSetAll(arr3 , new IntUnaryOperator()
        {
            // operand代表正在計算的元素索引
            public int applyAsInt(int operand)
            {
                return operand * 5;
            }
        });
        System.out.println(Arrays.toString(arr3));
    }
}

數組的應用舉例

程序代碼如下:數字轉中文.java

//未完成

public class 數字轉中文
{
    public static void main(String[] args) 
    {
        String[] cnChars = { "零", "壹", "貳", "叄", "肆", "伍", "陸", "柒", "捌", "玖"};

        String[] cnUnits = { " ","十","百","千","萬"};
        int a = 0103;

        String str = a + ""; // 數值轉換爲字符串最簡單的方法
                             // 直接加一個空字符串即可

        String result = "";

        //str.length()返回str的字符的個數
        //循環就從str的字符的個數-1 ~ 0
        for (int i = str.length() - 1 , j = 0; i > -1 ; i-- )
        {
            char numChar = str.charAt(i); // 返回str字符串中第i個位置的字符

            /*
             *  '0' 當成int用,相當於48
             *  ...
             *  '9' 當成int用,相當於57
             */

             //如果當前數字爲0時,無需添加單位
             if (numChar == '0')
             {
                result = cnChars[numChar - 48] + result;
             }
             else
            {
                 result = (cnChars[numChar - 48] + cnUnits[j]) + result;
             }  
             j++;
        }
        System.out.println("轉換後爲:"+ result);
    }
}

程序代碼如下:Gobang.java

//當前只能判斷列方向的輸贏
//需要補充完整橫向以及斜對角方向

import java.io.*;
import java.util.*;

public class Gobang 
{
        //定義了一個常亮
        static final int GOBANG_SIZE = 11;

        static final String NO_CHESS = "口";
        static final String BLACK_CHESS = "●";
        static final String WHILE_CHESS = "○";

        //定義一個二維數組
        //此時所有的數組元素,由系統執行默認初始化,默認爲null
        static String[][] status = new String[GOBANG_SIZE][GOBANG_SIZE];


    public static void main(String[] args) 
        throws Exception
    {
        //程序從這裏開始
        System.out.println("五子棋!");

        //該方法把二維數組的每個元素都賦值爲[]
        init();

        //輸出棋盤
        printStatus();
        //System.in代表鍵盤,把System.in做了一個包裝
        //br可以理解成包裝後的鍵盤
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        //定義了一個字符串
        String line = null;

        //讀取用戶輸入的一行,並將這行字符串賦給line變量
        //而且如果所讀取的用戶輸入的一行不爲null,執行循環
        while ( (line = br.readLine()) != null )
        {
            //line就是用戶輸入一行字符串
            //這行字符串應該包含X,Y座標,而且要滿足X,Y的格式
            //如果用戶輸入不滿足X,Y的格式,退出遊戲。
            //此時需要將line字符串用逗號分割成前後兩個部分
            String[] xyStr = line.split(",");

            //獲取x,y字符串位於逗號之前的部分
            String xStr = xyStr[0];

            //獲取x,y字符串位於逗號之後的部分
            String yStr = xyStr[1];

            //Integer.parseInt(xStr)負責把String轉換int值
            int xPos = Integer.parseInt(xStr);

            //Integer.parseInt(yStr)負責把String轉換int值
            int yPos = Integer.parseInt(yStr);

            //如果用戶希望下棋的座標不爲“口”,表明該下棋位置已經有棋子了
            if (!status[xPos][yPos].equals(NO_CHESS))
            {
                System.out.println("該位置已經有棋子了,請重新下棋");
                continue;
            }

            //所謂的用戶下棋,本質就是把該下棋的字符串重新賦值
            status[xPos][yPos] = BLACK_CHESS;

            //此時先做一個“白癡”電腦,下棋是隨機的
            //所謂的隨機下棋,生成兩個0(包括)~GOBANG_SIZE(不包括)的隨機數
            //Random對象是一個隨機數生成器
            while (true)
            {
                //生成兩個0(包括)~GOBANG_SIZE(不包括)的隨機數
                int pcX = new Random().nextInt(GOBANG_SIZE);
                int pcY = new Random().nextInt(GOBANG_SIZE);

                //如果電腦試圖下棋的位置,沒有棋子,電腦正常下棋
                if (!status[xPos][yPos].equals(NO_CHESS))
                {
                    //所謂的用戶下棋,本質就是把該下棋的字符串重新賦值
                    status[pcX][pcY] = WHILE_CHESS;
                    break;
                }
                //如果到了下面,電腦下棋的位置,有棋子
                //程序開始下一次循環,重新生成電腦下棋的座標
            }
            printStatus(); // 輸出棋盤

            //每次用戶、電腦下棋之後,判斷一次輸贏
            if (judge() > 0 ) //用戶贏了
            {
                System.out.println("你贏了!");
                return; //退出main方法,遊戲結束
            }
            if (judge() < 0 ) //電腦贏了
            {
                System.out.println("你輸了!");
                return; //退出main方法,遊戲結束
            }
            //代碼能執行到這裏,表明還沒有輸贏

        }
    }

    //依次輸出每個數組元素(相當於繪製棋盤,由於經常需要繪製棋盤,所以此處就執行輸出)
    public static void printStatus() 
    {
        for (int i = 0; i < GOBANG_SIZE; i++)
        {
            // 每循環完,輸出GOBANG_SIZE個口 ,沒有換行
            for (int j = 0; j < GOBANG_SIZE; j++)
            {
                System.out.print(status[i][j]);
            }
            System.out.println();
        }
    }

    //定義成一個判斷輸贏的方法
    //讓用戶每次下棋後,或者電腦每次下棋,進行一次判斷。
    public static int judge()
    {
        //一共有4種方向出現5個連着
        //橫、豎、對斜線
        for (int i = 0; i < GOBANG_SIZE; i++)
        {
            String line = "";
            //當i爲0時,代表第1列;當i爲1時,代表第2列
            //循環完成時,將會返回字符串
            for (int j = 0; j < GOBANG_SIZE; j++)
            {
                line += status[j][i];
            }

            //判斷字符串內是否包含某個子串
            if (line.contains("●●●●●")) //用戶贏了
            {
                return 1 ;
            }
            if (line.contains("○○○○○")) //電腦贏了
            {
                return -1 ;
            }   
        }
        return 0; //沒有輸贏
    }


    //初始化了一個棋盤
    public static void init() 
    {
        for (int i = 0; i < GOBANG_SIZE; i++)
        {
            // 依次把二維數組的每個元素都賦值爲口
            for (int j = 0; j < GOBANG_SIZE; j++)
            {
                status[i][j] = NO_CHESS;
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章