2018年7月26日 星期四

JAVA基礎必修課學習筆記 (2)

  因工作的緣故,閱讀蔡文龍、張志成編著的《JAVA SE 8基礎必修課》以學習Java程式基礎,目前最新的Java程式版本為Java SE 10,筆記中的程式撰寫習慣盡量仿照Python以增加可讀性。

一、繼承、介面與多型

繼承(Inheritance)的語法
l   語法:
class
子類別名稱 extends 父類別名稱{
   
敘述區段
}
l   一個子類別(Subclass)只能繼承一個父類別(Superclass),子類別除擁有父類別的功能,還具有父類別所沒有的功能。
l   子類別不能繼承父類別用private修飾子所宣告的成員。
l   子類別可以繼承父類別用protected修飾子宣告的成員,而該成員可在同一套件內的類別所建立之物件使用。
l   子類別可以繼承父類別用public修飾子宣告的成員,而該成員可在同一套件或不同套件內的類別所建立之物件使用。

繼承與方法覆寫(Override)
l   如果子類別和父類別有相同的方法時,若使用子類別產生物件,當使用到這個方法時,子類別的方法會覆蓋父類別同名稱的方法;但如果傳入引數的資料型別不同、個數不同或順序不同,就會變成方法多載。
l   範例:
package testPackage;
class test2{
    public void getMax(int a, int b){
        int c;
        if (a > b){
            c = a;}
        else{
            c = b;}
        System.out.println(a + " and " + b + ", Get Max: " + c);
    }
    public void add(int a, int b){
        System.out.println(a + " + " + b + " = " + (a + b));
    }
}
class sonTest2 extends test2{
    public void getMax(int a, int b){
        if (a > b){
            System.out.println(a + " and " + b + ", Get Max: " + a);}
        else if (a < b){
            System.out.println(a + " and " + b + ", Get Max: " + b);}
        else{
            System.out.println(a + " and " + b + " Are the Same");}
    }
    public void minus(int a, int b){
        System.out.println(a + " - " + b + " = " + (a - b));
    }
}
public class test{
    public static void main(String[] args){
        test2 obj = new test2();
        //
使用父類別自己的方法
        obj.getMax(20, 20);
        sonTest2 sonObj = new sonTest2();
        //
使用子類別覆寫自父類別的方法
        sonObj.getMax(20, 20);
        //
使用子類別繼承自父類別的方法
        sonObj.add(10, 20);
        //
使用子類別自己的方法
        sonObj.minus(20, 30);
    }
}

繼承與建構式
l   若使用子類別產生物件,子類別的父類別及其以上層級的預設建構式都會執行,由最上層類別預設建構式先執行,依序往下層執行至該層的預設建構式。
l   範例:
package testPackage;
class test2{
    test2(){
        System.out.println("Execute test2 Constructor");
    }
}
class sonTest2 extends test2{
    sonTest2(){
        System.out.println("Execute sonTest2 Constructor");
    }
}
class grandsonTest2 extends sonTest2{
    grandsonTest2(){
        System.out.println("Execute grandsonTest2 Constructor");
    }
}
public class test{
    public static void main(String[] args){
        //
採匿名物件的方式來建立物件實體
        new grandsonTest2();
    }
}

繼承與使用super呼叫父類別
l   範例:
package testPackage;
class test2{
    private int height;
    public int weight;
    test2(int height, int weight){
        this.height = height;
        this.weight = weight;
    }
    public void showData(){
        System.out.println("Height: " + this.height);
    }
}
class sonTest2 extends test2{
    private int age;
    sonTest2(int height, int weight, int age){
        //
使用super呼叫父類別test2(int height, int weight)建構式
        super(height, weight);
        this.age = age;
    }
    public void showData(){
        //
使用super呼叫父類別showData()方法成員
        super.showData();
        //
使用super呼叫父類別weight資料成員
        System.out.println("Weight: " + super.weight);
        System.out.println("Age: " + this.age);
    }
}
public class test{
    public static void main(String[] args){
        sonTest2 obj = new sonTest2(65, 171, 26);
        obj.showData();
    }
}

繼承與使用final禁止被覆寫
l   如果在類別加上final,表示無法被子類別繼承。
如果在資料成員加上final,表示無法被變更且一定要有常數初值。
如果在方法成員加上final,表示無法被子類別覆寫;但如果傳入引數的資料型別不同、個數不同或順序不同,就會變成方法多載。
l   範例:
package testPackage;
//
在類別加上final
final class test2{
    int hpBaseStat;
}
class test3{
    //
在資料成員加上final
    private final int speedBaseStat = 110;
    //
在方法成員加上final
    public final void showData(String pokemon){
        System.out.println(pokemon + "'s Speed Base Stat: " + speedBaseStat);
    }
}
public class test{
    public static void main(String[] args){
        test3 obj = new test3();
        obj.showData("Gengar");
    }
}

繼承與使用static禁止被覆寫
l   如果在方法成員加上static,表示無法被子類別覆寫;但如果傳入引數的資料型別不同、個數不同或順序不同,就會變成方法多載。
l   範例:
package testPackage;
class test2{
    public static int a = 10, b = 20;
    public static void add(){
        System.out.println(a + " + " + b + " = " + (a + b));
    }
}
public class test{
    public static void main(String[] args){
        test2.add();
    }
}

抽象類別與抽象方法
l   語法:
abstract class
類別名稱{
   
修飾子 abstract 傳回值型別 抽象方法名稱(引數串列);
}
l   抽象類別:
抽象類別是範本作用的父類別,不能使用new產生物件實體,只能被繼承,繼承它的子類別必須依照它的格式來定義。
l   一般方法與抽象方法:
抽象類別內的方法成員,可以是一般方法成員或抽象方法成員;一般方法成員內有敘述區段,而抽象方法成員只有一行宣告敘述。
l   抽象方法:
抽象方法必須使用abstract關鍵字宣告,因必須被子類別繼承,修飾子不能為private
l   抽象類別與抽象方法的繼承:
抽象類別被子類別繼承後,其抽象方法必須被子類別覆寫;此外因抽象類別無法建立物件實體,其建構式、資料成員與一般方法成員若要由子類別呼叫,必須使用super敘述。
l   範例:
package testPackage;
abstract class testAbstract{
    //
資料成員
    int stat = 100;
    //
一般方法成員
    public static void showData(){
        System.out.println("4 Effort Points Convert to 1 Stat Point");
    }
    //
抽象方法成員
    public abstract void addStat(int effort);
}
class testPoke extends testAbstract{
    public void addStat(int effort){
        System.out.println("Before Receiving Effort Points, Stat: " + stat);
        stat += (effort / 4);
        System.out.println("After Receiving Effort Points, Stat: " + stat);
    }
}
public class test{
    public static void main(String[] args){
        testAbstract.showData();
        testPoke sylveon = new testPoke();
        sylveon.addStat(252);
    }
}

介面(Interface)
l   語法:
interface
介面名稱{
   
成員存取修飾子 資料型別 資料成員名稱 = 初值;
   
成員存取修飾子 傳回傳型別 方法成員名稱(引數串列);
}
l   介面的資料成員:
介面內所定義的變數在編譯時會變成publicfinal型態,因此介面的變數為常數型態。
l   介面的方法成員:
介面內所定義的任何方法都不可以被完整地描述,只提供方法的定義而不實作,在編譯時會變成publicabstract型態。
l   介面用以達成多重繼承:
一個類別可以有多個介面的特質,而不管類別是什麼關係,如父類別、子類別等,也可以使用implements實作同一個介面。
l   介面實作範例:
package testPackage;
interface testInterface{
    //
資料成員
    public int totalEffort = 255;
    //
方法成員
    public void addStat(int effort);
}
class testPoke implements testInterface{
    int stat = 100;
    public void addStat(int effort){
        System.out.println("Before Receiving Effort Points, Stat: " + stat);
        stat += (effort / 4);
        System.out.println("After Receiving Effort Points, Stat: " + stat);
    }
}
public class test{
    public static void main(String[] args){
        System.out.println("Total Effort Points: " + testInterface.totalEffort);
        testPoke sylveon = new testPoke();
        sylveon.addStat(252);
    }
}
l   介面繼承範例:
package testPackage;
interface tmMove{
    public void moveOne();
    public void moveTwo();
}
interface learnset extends tmMove{
    public void moveThree();
    public void moveFour();
}
//
一定要將所有介面方法成員的敘述區段完成
class testPoke implements learnset{
    public void moveOne(){
        System.out.println("Gengar's Move: Thunderbolt");
    }
    public void moveTwo(){
        System.out.println("Gengar's Move: Sludge Bomb");
    }
    public void moveThree(){
        System.out.println("Gengar's Move: Shadow Ball");
    }
    public void moveFour(){
        System.out.println("Gengar's Move: Destiny Bond");
    }
}
public class test{
    public static void main(String[] args){
        testPoke gengar = new testPoke();
        gengar.moveOne();
        gengar.moveTwo();
        gengar.moveThree();
        gengar.moveFour();
    }
}

多型(Polymorphism)
l   不同物件執行相同名稱的方法,卻可以得到不同的結果:
使用父類別變數參考到子類別物件後,即透過父類別變數來存取子類別與父類別同時擁有的資料成員、方法成員。
l   以抽象類別實作多型:
package testPackage;
abstract class testAbstract{
    abstract void showData();
}
class glaceon extends testAbstract{
    public void showData(){
        System.out.println("Glaceon: HP65, Atk60, Def110, SpA130, SpD130, Spe65");
    }
}
class leafeon extends testAbstract{
    public void showData(){
        System.out.println("Leafeon: HP65, Atk110, Def130, SpA60, SpD65, Spe95");
    }
}
public class test{
    public static void main(String[] args){
        //
宣告testAbstract抽象類別的baseStats參考變數
        testAbstract baseStats;
        glaceon iceEevee = new glaceon();
        baseStats = iceEevee;
        baseStats.showData();
        leafeon grassEevee = new leafeon();
        baseStats = grassEevee;
        baseStats.showData();
    }
}
l   以介面實作多型:
package testPackage;
interface testInterface{
    void showData();
}
class glaceon implements testInterface{
    public void showData(){
        System.out.println("Glaceon: HP65, Atk60, Def110, SpA130, SpD130, Spe65");
    }
}
class leafeon implements testInterface{
    public void showData(){
        System.out.println("Leafeon: HP65, Atk110, Def130, SpA60, SpD65, Spe95");
    }
}
public class test{
    public static void main(String[] args){
        //
宣告testInterface介面的baseStats參考變數
        testInterface baseStats;
        glaceon iceEevee = new glaceon();
        baseStats = iceEevee;
        baseStats.showData();
        leafeon grassEevee = new leafeon();
        baseStats = grassEevee;
        baseStats.showData();
    }
}

套件(Package)
l   一個.java檔只能定義一個套件名稱,只要是屬於testPackage套件的類別,就要放在testPackage資料夾裡面。
l   類別存取修飾子在不同套件的存取權限-public、不宣告(預設)
public
表示該類別可以在不同套件存取。
預設階層表示該類別只能在相同套件存取。
l   成員存取修飾子在不同套件的存取權限-privateprotectedpublic、不宣告(預設)
private
表示該成員在不同套件,沒有繼承權限,沒有使用權限。
private
表示該成員在相同套件,沒有繼承權限,沒有使用權限。
protected
表示該成員在不同套件,有繼承權限,沒有使用權限。
protected
表示該成員在相同套件,有繼承權限,有使用權限。
public
表示該成員在不同套件,有繼承權限,有使用權限。
public
表示該成員在相同套件,有繼承權限,有使用權限。
預設階層表示該成員在不同套件,沒有繼承權限,沒有使用權限。
預設階層表示該成員在相同套件,有繼承權限,有使用權限。

二、例外處理

例外處理的語法
l   語法:
try{
   
檢查是否發生例外的程式區塊}
catch (
例外類別 變數名稱){
   
例外發生時執行的程式區塊}
finally{
   
絕對會執行的程式區塊}
l   catch
用以抓取例外,可以使用一個catch敘述,亦可使用多個catch敘述。
l   例外類別:
所有的例外類別都是內建類別Throwable的子類別,Throwable是例外類別中的最上層,由它延伸出Error類別和Exception類別,其中Exception類別可用來捕捉不確定的例外;Exception類別又可以再延伸出RuntimeException類別,RuntimeException類別屬於執行時期發生的例外。
l   finally
不一定需要用到finallyfinally用在無論是否執行catch例外情況,最後皆須執行的程式區塊。
l   範例:
package testPackage;
public class test{
    public static void main(String[] args){
        try{
            //
字串無法轉換成整數
            int a = Integer.parseInt("Hello World");}
        catch (ArithmeticException e){
            System.out.println("Arithmetic Exception: " + e.toString());}
        //
只能在最後一個catch使用(Exception e){...}捕捉不確定的例外
        catch (Exception e){
            System.out.println("Exception: " + e.toString());}
        finally{
            System.out.println("Hello World");}
    }
}

自行拋出例外
l   使用throw拋出例外:
package testPackage;
public class test{
    static void divide(int a, int b){
        try{
            if (b == 0){
                //
自行抛出Throwable類別或其子類別的例外物件
                throw new ArithmeticException("Divisor Is 0");}
            System.out.println(a + " / " + b + " = " + (a / b));}
        catch (ArithmeticException e){
            // getMessage()
方法傳回使用new建立物件建構式之引數值
            System.out.println("Arithmetic Exception: " + e.getMessage());
            // toString()
方法傳回引數值與例外字串物件
            System.out.println("Arithmetic Exception: " + e.toString());}
    }
    public static void main(String[] args){
        divide(6, 3);
        divide(6, 0);
    }
}
l   使用throws宣告該方法可以拋出例外:
package testPackage;
public class test{
    static void divide(int a, int b) throws ArithmeticException{
        if (b == 0){
            throw new ArithmeticException("Divisor Is 0");}
        System.out.println(a + " / " + b + " = " + (a / b));
    }
    public static void main(String[] args){
        try{
            divide(6, 3);
            divide(6, 0);}
        catch (ArithmeticException e){
            System.out.println("Arithmetic Exception: " + e.getMessage());
            System.out.println("Arithmetic Exception: " + e.toString());}
    }
}

自訂例外類別
l   繼承Exception類別後,可以覆寫Throwable類別的方法成員,並定義自己所需的例外訊息。
l   範例:
package testPackage;
class customizedException extends Exception{
    public String showMessage(){
        return "showMessage() Is Overrided by Customized Method";
    }
}
public class test{
    static void divide(int a, int b){
        try{
            if (b == 0){
                throw new customizedException();}
            System.out.println(a + " / " + b + " = " + (a / b));}
        catch (customizedException e){
            System.out.println("Customized Exception: " + e.showMessage());}
    }
    public static void main(String[] args){
        divide(6, 3);
        divide(6, 0);
    }
}

三、集合與泛型

集合物件架構(Collections Framework)
l   使用前必須載入:import java.util.*;
l   集合介面,下層介面繼承上層介面:
Collection        >Set                 >SortedSet
                        >List
Map                 >SortedMap
l   實作集合介面的具體類別及其特性:
集合介面        具體類別                        集合物件的特性
Set                   HashSet                          
唯一性
SortedSet         TreeSet                           
唯一性、排序性
List                   ArrayList
LinkedList      循序性
Map                 HashMap                        
鍵值對應
SortedMap      TreeMap                        
鍵值對應、排序性
l   建立集合物件的語法及範例:
//
具體類別名稱<資料型別> 集合物件名稱 = new 具體類別名稱<>();
HashSet<Integer> aObj = new HashSet<>();
//
集合介面名稱<資料型別> 集合物件名稱 = new 具體類別名稱<>();
Set<Integer> bObj = new HashSet<>();
Collection<Integer> cObj = new HashSet<>();

Collection<資料型別>介面
l   Collection<資料型別>介面常用的方法成員:
// Collection<String> aObj = new HashSet<>();
// Collection<String> bObj = new HashSet<>();
//
集合物件是空的,傳回true
System.out.println(aObj.isEmpty());
//
指定物件的元素新增為元素,若成功則傳回true
System.out.println(aObj.add("Hello World"));
//
指定集合物件的所有元素新增為元素,若成功則傳回true
System.out.println(aObj.addAll(bObj));
//
傳回集合物件元素個數
System.out.println(aObj.size());
//
集合物件包含指定物件的元素,傳回true
System.out.println(aObj.contains("Hello World"));
//
集合物件包含指定集合物件的所有元素,傳回true
System.out.println(aObj.containsAll(bObj));
//
移除指定物件的元素,若成功則傳回true
System.out.println(aObj.remove("Hello World"));
//
移除指定集合物件的所有元素,若成功則傳回true
System.out.println(aObj.removeAll(bObj));
//
僅保留集合物件的元素,其餘皆移除,若成功則傳回true
System.out.println(aObj.retainAll(bObj));
//
指定物件與集合物件相同,傳回true
System.out.println(aObj.equals(bObj));
//
移除集合物件的所有元素
aObj.clear();

Set<資料型別>介面與HashSet<資料型別>類別
l   HashSet<資料型別>類別常用的建構式:
//
建立一個全新的空HashSet物件,預設元素個數為16
Set<String> aObj = new HashSet<>();
//
建立一個全新的空HashSet物件,指定元素個數為10
Set<String> bObj = new HashSet<>(10);
//
建立一個含指定物件bObjHashSet物件
Set<String> cObj = new HashSet<>(bObj);

SortedSet<資料型別>介面與TreeSet<資料型別>類別
l   SortedSet<資料型別>介面常用的方法成員:
// SortedSet<Integer> aObj = new TreeSet<>();
//
傳回集合物件第一個元素
System.out.println(aObj.first());
//
傳回集合物件最後一個元素
System.out.println(aObj.last());
//
傳回集合物件中值小於16的所有元素資料
System.out.println(aObj.headSet(16));
//
傳回集合物件中值大於等於85的所有元素資料
System.out.println(aObj.tailSet(85));
//
傳回集合物件中值大於等於16,且小於85的所有元素資料
System.out.println(aObj.subSet(16, 85));
l   TreeSet<資料型別>類別常用的建構式:
//
建立一個全新的空TreeSet物件,元素由小到大排序
SortedSet<String> aObj = new TreeSet<>();
//
建立一個含指定物件aObjTreeSet物件
SortedSet<String> bObj = new TreeSet<>(aObj);

List<資料型別>介面與ArrayList<資料型別>LinkedList<資料型別>類別
l   List<資料型別>介面常用的方法成員:
// List<Integer> aObj = new ArrayList<>();
// List<Integer> bObj = new ArrayList<>();
//
指定物件的元素新增為元素至尾部,若成功則傳回true
System.out.println(aObj.add(200));
//
指定物件的元素新增為元素至索引位置
aObj.add(0, 300);
//
指定集合物件的所有元素新增為元素至尾部,若成功則傳回true
System.out.println(aObj.addAll(bObj));
//
指定集合物件的所有元素新增為元素至索引位置,若成功則傳回true
System.out.println(aObj.addAll(1, bObj));
//
傳回索引位置的元素
System.out.println(aObj.get(4));
//
傳回第一次出現指定元素的索引位置,若不包含該元素則傳回-1
System.out.println(aObj.indexOf(8));
//
傳回最後出現指定元素的索引位置,若不包含該元素則傳回-1
System.out.println(aObj.lastIndexOf(8));
//
傳回索引位置包括1到索引位置不包括4之間的集合
System.out.println(aObj.subList(1, 4));
//
移除指定索引位置的元素,傳回被移除的元素
System.out.println(aObj.remove(4));
//
替換指定索引位置的元素,傳回被替換的元素
System.out.println(aObj.set(0, 400));
l   ArrayList<資料型別>類別常用的建構式:
// ArrayList
不用事先宣告元素數量,是可以自行調整大小的動態串列
//
建立一個全新的空ArrayList物件,預設元素個數為10
List<String> aObj = new ArrayList<>();
//
建立一個全新的空ArrayList物件,指定元素個數為20
List<String> bObj = new ArrayList<>(20);
//
建立一個含指定物件bObjArrayList物件
List<String> cObj = new ArrayList<>(bObj);
l   ArrayList<資料型別>類別常用的方法成員:
// ArrayList<Integer> aObj = new ArrayList<>();
//
增加此ArrayList集合物件的容量
aObj.ensureCapacity(50);
//
調整此ArrayList集合物件的容量為串列目前大小
aObj.trimToSize();
l   LinkedList<資料型別>類別常用的建構式:
// LinkedList
將元素視為節點,每個節點皆有資料欄與鏈結欄
//
建立一個全新的空LinkedList物件
List<String> aObj = new LinkedList<>();
//
建立一個含指定物件aObjLinkedList物件
List<String> bObj = new LinkedList<>(aObj);
l   LinkedList<資料型別>類別常用的方法成員:
// LinkedList<Integer> aObj = new LinkedList<>();
//
將指定元素插入鏈結串列開頭,其指標值重新排序
aObj.addFirst(25);
//
將指定元素插入鏈結串列尾端
aObj.addLast(50);
//
移除並傳回鏈結串列的第一個元素
System.out.println(aObj.removeFirst());
//
移除並傳回鏈結串列的最後一個元素
System.out.println(aObj.removeLast());
//
傳回鏈結串列的第一個元素
System.out.println(aObj.getFirst());
//
傳回鏈結串列的最後一個元素
System.out.println(aObj.getLast());

Map<K, V>介面與HashMap<K, V>類別
l   Map<K, V>介面常用的方法成員:
// Map<String, String> aObj = new HashMap<>();
// Map<String, String> bObj = new HashMap<>();
//
集合物件是空的,傳回true
System.out.println(aObj.isEmpty());
//
將關鍵值K與對應值V新增至集合物件
aObj.put("Sylveon", "Fairy");
//
將指定的Map集合物件新增至目前的Map集合物件
aObj.putAll(bObj);
//
傳回集合物件元素個數
System.out.println(aObj.size());
//
集合物件包含指定關鍵值K,傳回true
System.out.println(aObj.containsKey("Sylveon"));
//
集合物件包含指定對應值V,傳回true
System.out.println(aObj.containsValue("Fairy"));
//
傳回集合物件中指定關鍵值K的對應值V
System.out.println(aObj.get("Sylveon"));
//
將所有關鍵值K傳回,並轉換成實作Set介面的集合物件
System.out.println(aObj.keySet());
//
將所有對應值V傳回,並轉換成實作Collection介面的集合物件
System.out.println(aObj.values());
//
移除集合物件中指定關鍵值K,若成功則傳回的對應值V
System.out.println(aObj.remove("Sylveon"));
//
移除集合物件的所有元素
aObj.clear();
l   HashMap<K, V>類別常用的建構式:
//
建立一個全新的空HashMap物件,預設元素個數為16
Map<String, String> aObj = new HashMap<>();
//
建立一個全新的空HashMap物件,指定元素個數為10
Map<String, String> bObj = new HashMap<>(10);
//
建立一個含指定物件bObjHashMap物件
Map<String, String> cObj = new HashMap<>(bObj);

SortedMap<K, V>介面與TreeMap類別
l   SortedMap<K, V>介面常用的方法成員:
// SortedMap<String, String> aObj = new TreeMap<>();
//
傳回集合物件第一個元素的關鍵值K
System.out.println(aObj.firstKey());
//
傳回集合物件最後一個元素的關鍵值K
System.out.println(aObj.lastKey());
//
傳回集合物件中關鍵值K小於G的所有元素資料
System.out.println(aObj.headMap("G"));
//
傳回集合物件中關鍵值K大於等於R的所有元素資料
System.out.println(aObj.tailMap("R"));
//
傳回集合物件中關鍵值K大於等於G,且小於R的所有元素資料
System.out.println(aObj.subMap("G", "R"));
l   TreeMap<K, V>類別常用的建構式:
//
建立一個全新的空TreeMap物件,元素依關鍵值K由小到大排序
SortedMap<String, String> aObj = new TreeMap<>();
//
建立一個含指定物件aObjTreeMap物件
SortedMap<String, String> bObj = new TreeMap<>(aObj);

Collections集合工具類別
l   CollectionsCollection介面的工具類別,該類別中的方法成員皆採static靜態方法。
l   範例:
package testPackage;
import java.util.*;
public class test{
    public static void main(String[] args){
        List<Integer> aObj = new ArrayList<>();
        for (int i = 1; i < 100; i += 7){
            aObj.add(i);}
       
        //
對集合物件的元素做反轉順序的排列
        Collections.reverse(aObj);
        System.out.println(aObj);
        //
對集合物件的元素做由小到大的排列
        Collections.sort(aObj);
        System.out.println(aObj);
        //
將集合物件中指定位置的元素交換
        Collections.swap(aObj, 0, 1);
        System.out.println(aObj);
        //
傳回集合物件的最大元素
        System.out.println(Collections.max(aObj));
        //
傳回集合物件的最小元素
        System.out.println(Collections.min(aObj));
        //
使用指定資料替換集合物件的所有元素
        Collections.fill(aObj, 11);
        System.out.println(aObj);
    }
}

集合的走訪器
l   Iterator<資料型別>介面:
只要能實作Collection支系介面的集合物件皆可實作Iterator介面,Iterator的資料型別需與集合物件的資料型別相同。
l   Iterator<資料型別>介面常用的方法成員:
package testPackage;
import java.util.*;
    public class test{
        public static void main(String[] args){
        SortedSet<Integer> aObj = new TreeSet<>();
        for (int i = 1; i <= 40; i++){
            aObj.add(i);}
        //
建立走訪器物件aItera
        Iterator<Integer> aItera = aObj.iterator();
        //
傳回Iterator目前指向的元素
        System.out.println(aItera.next());
        //
刪除Iterator目前指向的元素
        aItera.remove();
        //
集合還有Iterator指向的下個元素,傳回true
        while (aItera.hasNext()){
            int num = aItera.next();
            for (int j = 2; j < num; j++){
                if (num % j == 0){
                    aItera.remove();
                    break;}}}
        System.out.println("Prime Number between 1 & 40: " + aObj);
    }
}
l   ListIterator<資料型別>介面:
ListIterator
介面繼承Iterator介面;Iterator介面物件的走訪方式是單向的,ListIterator介面物件則是雙向的;Iterator介面物件只能讀取與刪除元素,ListIterator介面物件則可以讀取、刪除、新增與修改元素。
l   ListIterator<資料型別>介面常用的方法成員:
package testPackage;
import java.util.*;
public class test{
    public static void main(String[] args){
        List<String> aObj = new ArrayList<>();
        String[] gem = {"Ruby", "Sapphire", "Emerald"};
        for (String i : gem){
            aObj.add(i);}
        ListIterator<String> aItera = aObj.listIterator();
       
        //
集合還有ListIterator指向的下個元素,傳回true
        while (aItera.hasNext()){
            //
傳回ListIterator目前指向的元素
            System.out.print(aItera.next());
            //
傳回ListIterator目前指向的元素的索引值
            System.out.println(aItera.nextIndex());
            if (aItera.nextIndex() == 3){
                //
ListIterator指向的元素置換元素資料
                aItera.set("Platinum");}}
       
        //
集合還有ListIterator指向的前個元素,傳回true
        while (aItera.hasPrevious()){
            //
傳回ListIterator目前指向的元素
            System.out.print(aItera.previous());
            //
傳回ListIterator目前指向的元素的索引值
            System.out.println(aItera.previousIndex());
            if (aItera.previousIndex() == 1){
                //
刪除ListIterator目前指向的元素
                aItera.remove();}}
       
        aItera = aObj.listIterator(2);
        //
ListIterator指向的元素前加入元素資料
        aItera.add("Emerald");
        System.out.println(aObj);
    }
}

四、多執行緒

Thread類別
l   Thread類別常用的建構式:
//
建立一個空的Thread物件,啟動執行緒時會執行Threadrun()方法
public Thread()
//
引數name用來設定執行緒物件的名稱
public Thread(String name)
//
引數target是用來實作Runnable介面物件
public Thread(Runnable target)
//
同時傳入實作Runnable介面物件,與設定執行緒物件的名稱
public Thread(Runnable target, String name)
l   Thread類別常用的方法成員:
package testPackage;
class testThread extends Thread{
    //
覆寫Thread類別的run()方法,要執行的程式碼置於此
    public void run(){
        try{
            for (int i = 1; i <= 5; i++){
                //
取得執行緒的名稱
                System.out.println(getName() + ": " + i);
                //
使用sleep()必須捕捉例外
                sleep(1000);}}
        catch (InterruptedException e){
            e.printStackTrace();}
    }
}
public class test{
    public static void main(String[] args){
        testThread aObj = new testThread();
        //
設定執行緒的名稱
        aObj.setName("Thread A");
        //
設定執行緒的優先權,設定值為110,數值越大優先權越高
        aObj.setPriority(6);
        //
取得執行緒的優先權
        System.out.println(aObj.getPriority());
        aObj.setPriority(Thread.MAX_PRIORITY);
        System.out.println(aObj.getPriority());
        aObj.setPriority(Thread.MIN_PRIORITY);
        System.out.println(aObj.getPriority());
        aObj.setPriority(Thread.NORM_PRIORITY);
        System.out.println(aObj.getPriority());
        //
啟動執行緒
        aObj.start();
        //
取得目前執行緒的參考變數值,例如目前執行緒的名稱
        System.out.println(Thread.currentThread().getName());
        try{
            //
等待執行緒終止,才會繼續執行join()方法後的程式
            //
使用join()必須捕捉例外
            aObj.join();}
        catch (InterruptedException e){
            e.printStackTrace();}
        //
取得執行緒是否存活
        System.out.println(aObj.isAlive());
    }
}

三種建立執行緒的方式
l   直接建立Thread類別執行緒物件:
package testPackage;
public class test{
    public static void main(String[] args){
        Thread tortoise = new Thread(){
            public void run(){
                for (int i = 1; i <= 10; i++){
                    System.out.println("Tortoise Runs " + i + " KM(s)");}
                System.out.println("Tortoise Reaches the Finish Line");}
        };
        Thread rabbit = new Thread(){
            public void run(){
                for (int i = 3; i <= 10; i += 3){
                    if ((int)(Math.random() * 10 + 1) % 2 == 0){
                        i -= 3;
                        System.out.println("Rabbit Rests");}
                    else{
                        System.out.println("Rabbit Runs " + i + " KM(s)");}}
                System.out.println("Rabbit Reaches the Finish Line");}
        };
        tortoise.start();
        rabbit.start();
    }
}
l   宣告繼承Thread類別的自訂執行緒類別:
package testPackage;
class testThread extends Thread{
    String threadName;
    testThread(String name){
        threadName = name;
        //
啟動執行緒
        start();
    }
    public void run(){
        for (int i = 1; i <= 5; i++){
            System.out.println(threadName + ": " + i);}
    }
}
public class test{
    public static void main(String[] args){
        //
建立testThread類別的aObj物件
        new testThread("Thread A");
        new testThread("Thread B");
    }
}
l   實作Runnable介面來建立執行緒:
package testPackage;
class testThread implements Runnable{
    String threadName;
    testThread(String name){
        threadName = name;
    }
    public void run(){
        for (int i = 1; i <= 5; i++){
            System.out.println(threadName + ": " + i);}
    }
}
public class test{
    public static void main(String[] args){
        //
建立Thread類別的準執行緒aObj物件
        Thread aObj = new Thread(new testThread("Thread A"));
        Thread bObj = new Thread(new testThread("Thread B"));
        //
啟動執行緒
        aObj.start();
        bObj.start();
    }
}

執行緒的同步(Synchronized)
l   避免在同一時間,多個執行緒同時存取同一個物件而造成資料錯誤。
l   範例:
package testPackage;
class testThread extends Thread{
    static int totalGold = 20000000;
    int grabed;
    String name;
    testThread(String n){
        grabed = 0;
        name = n;
        start();
    }
    private synchronized static boolean grabGold(){
        if (totalGold > 0){
            totalGold -= 1;
            return true;}
        else{
            return false;}
    }
    public void run(){
        while (grabGold() == true){
            grabed += 1;}
        System.out.println(name + " Digs Out " + grabed + " Nuggets");
    }
}
public class test{
    public static void main(String[] args){
        System.out.println("There Are " + testThread.totalGold + " Nuggets");
        new testThread("Timmy");
        new testThread("Wendy");
        new testThread("Mai");
    }
}

執行緒的等待和喚醒
l   wait()notify()notifyAll()方法:
notify()
方法喚醒一個等待中的執行緒。
notifyAll()
方法喚醒所有等待中的執行緒。
wait()
方法讓指定的執行緒成為等待狀態。
wait()
方法須寫在synchronized敘述區段,並使用try...catch捕捉例外。
wait()
方法須寫在迴圈,避免notify()notifyAll()喚醒不該喚醒的執行緒。
l   範例:
package testPackage;
class Frisbee{
    private boolean isThrow = false;
    public synchronized void throwF(int tNo){
        while (isThrow){
            try{
                wait();}
            catch (InterruptedException e){
                e.printStackTrace();}}
        System.out.println("Throw No." + tNo + " Frisbee");
        isThrow = true;
        notify();
    }
    public synchronized void accessF(int aNo){
        while (!isThrow){
            try{
                wait();}
            catch (InterruptedException e){
                e.printStackTrace();}}
        System.out.println("Access No." + aNo + " Frisbee");
        isThrow = false;
        notify();
    }
}
class ThrowFrisbee extends Thread{
    Frisbee frisbee;
    ThrowFrisbee(Frisbee frisbee){
        this.frisbee = frisbee;
    }
    public void run(){
        for (int i = 1; i <= 5; i++){
            frisbee.throwF(i);}
    }
}
class AccessFrisbee extends Thread{
    Frisbee frisbee;
    AccessFrisbee(Frisbee frisbee){
        this.frisbee = frisbee;
    }
    public void run(){
        for (int i = 1; i <= 5; i++){
            frisbee.accessF(i);}
    }
}
public class test{
    public static void main(String[] args){
        Frisbee frisbee = new Frisbee();
        ThrowFrisbee master = new ThrowFrisbee(frisbee);
        AccessFrisbee dog = new AccessFrisbee(frisbee);
        master.start();
        dog.start();
    }
}

五、Lambda語法

匿名類別物件與Lambda語法
l   Lambda語法常用於匿名(Anonymous)類別並實作方法的場合,以便讓Java語法更簡潔,通常用於只有一個public方法的介面。
l   自訂類別物件範例-不使用匿名類別物件、Lambda語法:
package testPackage;
import java.util.*;
class student{
    public String name;
    private int chi;
    private int eng;
    public student(String n, int c, int e){
        name = n;
        chi = c;
        eng = e;
    }
    public int getSum(){
        return (chi + eng);
    }
}
class studentComparator implements Comparator<student>{
    public int compare(student aObj, student bObj){
        int a, b, returnValue = 0;
        a = aObj.getSum();
        b = bObj.getSum();
        if (a > b){
            returnValue = 1;}
        else if (a == b){
            returnValue = 0;}
        else if (a < b){
            returnValue = -1;}
        return returnValue;
    }
}
public class test{
    public static void main(String[] args){
        student[] allStu = {new student("aStudent", 54, 77), new student("bStudent", 88, 27), new student("cStudent", 83, 77), new student("dStudent", 66, 44)};
        System.out.println("Before Sorting Sum:");
        for (int i = allStu.length - 1; i >= 0; i--){
            System.out.println(allStu[i].name);}
        // Arrays.sort(
要排序的物件陣列, 要排序的規則物件);
        Arrays.sort(allStu, new studentComparator());
        System.out.println("After Sorting Sum:");
        for (int i = allStu.length - 1; i >= 0; i--){
            System.out.println(allStu[i].name);}
    }
}
l   自訂類別物件範例-使用匿名類別物件、Lambda語法:
package testPackage;
import java.util.*;
class student{
    public String name;
    private int chi;
    private int eng;
    public student(String n, int c, int e){
        name = n;
        chi = c;
        eng = e;
    }
    public int getSum(){
        return (chi + eng);
    }
}
public class test{
    public static void main(String[] args){
        student[] allStu = {new student("aStudent", 54, 77), new student("bStudent", 88, 27), new student("cStudent", 83, 77), new student("dStudent", 66, 44)};
        System.out.println("Before Sorting Sum:");
        for (int i = allStu.length - 1; i >= 0; i--){
            System.out.println(allStu[i].name);}
       
        /*
使用匿名類別物件
        Arrays.sort(allStu, new Comparator<student>(){
            public int compare(student aObj, student bObj){
                int a, b, returnValue = 0;
                a = aObj.getSum();
                b = bObj.getSum();
                if (a > b){
                    returnValue = 1;}
                else if (a == b){
                    returnValue = 0;}
                else if (a < b){
                    returnValue = -1;}
                return returnValue;
            }
        });
        */
       
        //
使用Lambda語法
        Arrays.sort(allStu, (aObj, bObj) -> {
            int a, b, returnValue = 0;
            a = aObj.getSum();
            b = bObj.getSum();
            if (a > b){
                returnValue = 1;}
            else if (a == b){
                returnValue = 0;}
            else if (a < b){
                returnValue = -1;}
            return returnValue;
        });
       
        System.out.println("After Sorting Sum:");
        for (int i = allStu.length - 1; i >= 0; i--){
            System.out.println(allStu[i].name);}
    }
}
l   執行緒範例-使用匿名類別物件、Lambda語法:
package testPackage;
public class test{
    public static void main(String[] args){
       
        /*
使用匿名類別物件
        Thread obj = new Thread(new Runnable(){
            public void run(){
                for (int i = 1; i <= 5; i++){
                    System.out.println("Hello World " + i);}
            }
        });
        */
       
        //
使用Lambda語法
        Thread obj = new Thread(() -> {
            for (int i = 1; i <= 5; i++){
                System.out.println("Hello World " + i);}
        });
       
        obj.start();
    }
}

Lambda語法與方法參考
l   範例:
package testPackage;
import java.util.Arrays;
public class test{
    public static void main(String[] args){
        String[] name = {"Red", "leaf", "Ethan", "lyra", "Brendan", "may"};
       
        /*
使用Lambda語法
        Arrays.sort(name, (str1, str2) -> str1.compareToIgnoreCase(str2));
        */
       
        //
使用方法參考
        Arrays.sort(name, String::compareToIgnoreCase);
       
        for (int i = 0 ; i < name.length; i++){
            System.out.println(name[i]);}
    }
}

沒有留言:

張貼留言