星期三, 10月 17, 2012

OCPJP Day 9


*Overloading method 的執行規則
  • 基礎對應(找相同或是相容)
    • 如果找不到相同的型別, 就往上找相同的型別
    • byte → char / short → int → long → float → double
  • Autoboxing / AutoUnboxing
    • 如果找不到基礎對應, 就會嘗試Autoboxing 的方式
    • Autoboxing 是一對一的對應, 也就是 int 只會找 Integer 不會找其他
  • Varargs


TestOverloading.java

package mod13;

public class TestOverloading {
//透過註解不同的方法來觀察 overloading 配合Test.java
//註解觀察 順序 首先觀察基礎對應 int → long → float → double
//再來觀察 Autoboxing 註解 Integer
//觀察 Varargs 註解 int or Integer
public void oops(byte a){
System.out.println("oops(byte a)");
}
public void oops(short a){
System.out.println("oops(short a)");
}
public void oops(int a){
System.out.println("oops(int a)");
}
public void oops(long a){
System.out.println("oops(long a)");
}
public void oops(float a){
System.out.println("oops(float a)");
}
public void oops(double a){
System.out.println("oops(double a)");
}
public void oops(Integer a){
System.out.println("oops(Integer a)");
}
public void oops(Long a){
System.out.println("oops(Long a)");
}
public void oops(int... a){
System.out.println("oops(int... a)");
}
public void oops(Integer... a){
System.out.println("oops(Integer... a)");
}

}


Test.java

package mod13;

public class Test {

public static void main(String[] args) {
//
short a = 25;
char b = 'a';
//char short 雖然位元數一樣, 但是還是要 Casting (互轉型別)
// a = (short) b;
// b = (char) a;
TestOverloading to = new TestOverloading();
//搭配上面的TestOverloading 來了解順序
to.oops(100);
//如果傳的是 大寫的Integer, 如果找不到, 會找小寫的int 並找向上相容 → 再找 Varargs ( 但是int Integer 只能有一個)
to.oops(new Integer(100));
// 如果傳入的是 char Overloading 的時候會往上相容, 所以會呼叫 int
to.oops(b);
}

}

Notes:
  • char short 雖然位元數一樣, 但是還是要 casting (轉型), 但是在Overloading 的時候會往上相容, 所以會呼叫 int


*Chapter 10 多型

Notes:
  • 現實生活中利用多型來簡化生活用語, 例如用"東西"來代表所有的事物
  • 多型是為了要有高度的擴充性以及讓程式精簡
  • 物件導向語言藉由繼承與多型來改善傳統語言的缺點

*多型(Polymorphism)
  • 擁有不同型態的能力
  • 事實上物件只有一個型態
  • Java 藉由參考變數參考不同型態的物件來達成多型的目的, 其中參考變數的型別須為物件型別的父類別或是更上層的型別
  • Complier 會將參考的物件是為參考變數所宣告的型別來使用

Notes:
  • 宣告一個父類別的物件, 但是指向子類別, 稱之為多型
    • 例如: Manager Employee 的子類別
    • Employee d = new Manager(); //多型的宣告
    • //Compiler 會將參考的型別視為被宣告的型別來使用

*虛擬方法呼叫(Virtual Method Invocation)
  • 如果使用多型的狀況, 如果子類別有override 方法, 就會產生虛擬方法呼叫VMI, 也就是會呼叫子類別的方法
  • Compile-time 型別及runtime型別的呼叫
    • Compile-time 型別, 編譯時期方法名稱必須是宣告變數型別的成員, 也就是父類別要有相對的方法
    • runtime 型別: 在執行時期物件的型別, 所以會採用子類別的實作, 稱為動態繫結(Dynamic Binding)






Lab: 多型

Animal.java

package mod10;

public class Animal {
//建立一個父類別來實現多型, 定義 speak and walk
//如果子類別沒有 override 方法就會出現預設的方法
public void speak(){
System.out.println("speak");
}
//
public void walk(){
System.out.append("Walking");
}
}


AnimalUN.java

package mod10;

public class AnimalUN {

public static void main(String[] args) {
//用來測試多型
Animal d = new Dog(); //多型, 建立一個父物件類別但是指向子物件
d.speak(); //如果子類別沒有 override 方法, 就會出現 speak, 如果有就會出現 dog speak
//
Animal c = new Cat();
c.speak();
}
}


Dog.java

package mod10;

public class Dog extends Animal {
//使用override 方式來執行子類別的方法
public void speak(){
System.out.println("Dog speak");
}
//
public void walk(){
System.out.append("Dog walking");
}
}


Cat.java

package mod10;

public class Cat extends Animal {
//使用override 方式來執行子類別的方法
public void speak(){
System.out.println("Cat speak");
}
//
public void walk(){
System.out.append("Cat Walking");
}
}


*異質集合
  • 帶有相同型別的物件集合稱為同質性集合(homogeneous collections)
  • 帶有不同類別型別的物件集合稱為異質性集合(heterogeneous collections)


*多型參數的傳遞
  • 宣告一個接受父類別型別參數的方法, 然後傳遞子類別的物件給該方法


Lab: 多型參數

Human.java

package mod10;

public class Human extends Animal{
//
public void speak(){
System.out.println("Human speak");
}
//
public void walk(){
System.out.append("Human Walking");
}
}


修改剛剛的 AnimalUN.java

AnimalUN.java

package mod10;

public class AnimalUN {

public static void main(String[] args) {
//用來測試多型
Animal d = new Dog(); //多型, 建立一個父物件類別但是指向子物件
d.speak(); //如果子類別沒有 override 方法, 就會出現 speak, 如果有就會出現 dog speak
System.out.println("--------------------");
//
Animal c = new Cat();
c.speak();
System.out.println("--------------------");
AnimalUN un = new AnimalUN();
//多型物件的傳遞, c Cat 類別, Animal 的子類別, speech 方法內為Animal (父類別)
un.speech(c);
//多型物件的傳遞
un.chat(c, d);
//
Human h = new Human();
un.speech(h);


}

//這邊使用的是 Animal
public void speech(Animal a){
a.speak();
}
//這邊使用的是 Animal
public void chat(Animal a, Animal b){
a.speak();
b.speak();
}

// use VarArgs 來擴充
public void mutiChat(Animal ... as){
}
}




*多型的目的
  • 簡化程式的開發
  • 高度的擴充性


*Overriding 三大規則
  • 方法簽章要跟父類別被Overriden的方法一模一樣
  • 存取控制不能比被Overriden的方法還小(比父類別還開放)
    • Override 方法時不能使用更封閉的存取修飾子
    • private 的方法不會被override
  • 不能丟出Overriden方法未宣告丟出的Exception


*instanceof 運算子
  • instanceof 運算子可以用來判斷物件的真實身份

*物件轉型
  • 轉型的目的為了要恢復該物件的完整功能
  • 使用instanceof 來測試一個物件的型別
  • 藉由轉型(casting)來恢復物件的完整功能
  • 根據下列的指導方針來檢查轉型的適當性
    • 在類別階層中, 向上(upward)轉型(其實就是多型)(子類別轉成父類別)會自動發生
    • 向下(downward)轉型(父類別轉成子類別)則需要符合類別階層的定義, 並經由compiler的檢查
    • 物件的型別需要runtime時期透過instanceof 進行檢查, 否則會發生錯誤.(ClassCastException)

*instanceof
  • 可以用來做相容型別的測試
  • 藉由判別回傳 true 或是 false, 來判斷是否為相容型別
    • Employee ← Manager ← Director
      • Employee e = new Employee();
      • Manager m = new Manager();
      • Director d = new Director();
      • ( e instanceof Employee ) → true
      • ( e instanceof Manager ) → false
      • ( e instanceof Director ) → false
      • ( m instanceof Employee ) → true
      • ( m instanceof Manager ) → true
      • ( m instanceof Director ) → false


*抽象類別
  • 一個方法如果沒有提供實作的方法, 該方法須宣告為抽象方法(abstract method)
  • 一個類別如果包含一個以上的抽象方法 ,該類別需宣告為抽象類別(abstract class)
  • 有別於具體類別(concrete class)(實作完整的類別), 抽象類別不能夠建立實體物件, 但仍可當作變數型別的宣告


Lab: 抽象類別

修改剛剛的Animal.java

package mod10;

//如果方法內有一個抽象方法, 就必須宣告為抽象類別
public abstract class Animal {
//建立一個父類別來實現多型, 定義 speak and walk
//如果子類別沒有 override 方法就會出現預設的方法
//speak方法改為抽象, 注意要連同{ } 一起移除(抽象方法內不可以有實作, 也就是敘述 {} ), 並加上 ;
public abstract void speak();
//
public void walk(){
System.out.append("Walking");
}
}

Notes:
  • 為何要使用抽象類別, 因為要提供多型還有VMI
  • UML 圖形內, 斜體字代表抽象
  • 使用抽象類別,如果子類別沒有辦法提供實作, 那子類別就要宣告為抽象類別


*介面(Interface)
  • Interface 等同於class
  • Interface 內都是抽象類別, 沒有定義任何的實作.
  • Interface 可以當成一種型別
  • Interface 不會受到單一繼承的限制
  • 一個公開介面(public interface)是介於用戶端程式(client code)和實作這個介面的類別之前的契約.
  • Java interface 是這種契約的正式宣告, 其中所有的方法都沒有提供實作
  • interface 所有的方法必定是 public abstract, 所有的屬性必定是 public static final
  • 不相關的類別可以實作相同的interface
  • 一個類別可以實作多個不相關的interface

Lab: Interface

將上面的程式改成 interface

Animal.java

package mod10;

//如果方法內有一個抽象方法, 就必須宣告為抽象類別
//interface void class 改成 interface
//一旦宣告為 interface, 那裏面的方法都是抽象的方法
public interface Animal {
//建立一個父類別來實現多型, 定義 speak and walk
//如果子類別沒有 override 方法就會出現預設的方法
//speak方法改為抽象, 注意要連同{ } 一起移除(抽象方法內不可以有實作, 也就是敘述 {} ), 並加上 ;
//如果是 interface 的話, abstract 關鍵字就可以省略
public void speak();
//
public void walk();
}


Dog.java

package mod10;
// 如果Animal interface 那就要使用 implements 關鍵字, extends 關鍵字
public class Dog implements Animal {
//使用override 方式來執行子類別的方法
public void speak(){
System.out.println("Dog speak");
}
//
public void walk(){
System.out.append("Dog walking");
}
}


Cat.java

package mod10;
// 如果Animal interface 那就要使用 implements 關鍵字, extends 關鍵字
public abstract class Cat implements Animal {
//
public void speak(){
System.out.println("Cat speak");
}
//這邊 Cat 沒有實作 walk(), 等等就會要用 Exception, 因為interface 子類別都要實作
}


AnimalUN.java

package mod10;

public class AnimalUN {

public static void main(String[] args) {
//用來測試多型
Animal d = new Dog(); //多型, 建立一個父物件類別但是指向子物件
d.speak(); //如果子類別沒有 override 方法, 就會出現 speak, 如果有就會出現 dog speak
System.out.println("--------------------");
//因為 Cat walk 方法沒有實作, 所以要有 throw Excption
Animal c = new Cat() {

@Override
public void walk() {
throw new UnsupportedOperationException("Not supported yet.");
}
};
c.speak();
System.out.println("--------------------");
AnimalUN un = new AnimalUN();
//多型物件的傳遞, c Cat 類別, Animal 的子類別, speech 方法內為Animal (父類別)
un.speech(c);
//多型物件的傳遞
un.chat(c, d);
//
Human h = new Human();
un.speech(h);


}

//這邊使用的是 Animal
public void speech(Animal a){
a.speak();
}
//這邊使用的是 Animal
public void chat(Animal a, Animal b){
a.speak();
b.speak();
}

// use VarArgs 來擴充
public void mutiChat(Animal ... as){
}
}




*介面的使用
  • 用來規範一個或多個類別應實作的方法
  • 訂定物件的程式介面而不需要揭露類別本體的實作
  • 在完全不相干的類別之間尋求相似性, 而不需要勉強建立類別間的繼承關係
  • 藉由一個實作多重介面的類別可以模擬多重繼承的效果

沒有留言: