Lab03: Inheritance

เป้าหมายของแล็บนี้คือ
  • ให้นิสิตทดลองโค้ดที่เล่นกับ inheritance หลายๆแบบ
  • ให้ตัวอย่างซึ่งนิสิตสามารถเอาไปทดลองต่อได้อีก
  • ให้เห็นตัวอย่างของการใช้ type ที่ต่างกับตัว object
  • หลักการคือ ทดลองทำ ค้นหาเหตุผล แล้วอธิบายออกมาให้ได้

หมายเหต:ุ  text file ให้เขียนใน Notepad เลย อย่าไปทำใน Eclipse เพราะ Eclipse ของบางคนใช้ภาษาไทยไม่ได้นะ

Inheritance

แล็บนี้จะให้ทำเป็นขั้นๆไปเรื่อยๆ เอาให้ทุกคนเข้าใจหลักการ Inheritance ให้ได้ ก่อนอื่นมาทวน inheritance กันหน่อย

 

เริ่มทำ

ก่อนอื่นเรามาทดลองเรื่องการใช้ไทป์ที่ไม่ตรงกับตัวออบเจ็กต์กันก่อน สร้างโปรเจ็คและพิมพ์โค้ดที่นิยามจักรยานตามนี้เลย

 

public class Bicycle {

     

    // the Bicycle class has three fields

    public int cadence;

    public int gear;

    public int speed;

     

    // the Bicycle class has one constructor

    public Bicycle(int startCadence, int startSpeed, int startGear) {

        gear = startGear;

        cadence = startCadence;

        speed = startSpeed;

    }

     

    // the Bicycle class has four methods

    public void setCadence(int newValue) {

        cadence = newValue;

    }

     

    public void setGear(int newValue) {

        gear = newValue;

    }

     

    public void applyBrake(int decrement) {

        speed -= decrement;

    }

     

    public void speedUp(int increment) {

        speed += increment;

    }

     

}

 

คราวนี้มาลองทำ MountainBike ซึ่งเป็นสับคลาสของ Bicycle ลอกโค้ดข้างล่างนี้ไปเลย:

 

public class MountainBike extends Bicycle {

     

    // the MountainBike subclass adds one field

    public int seatHeight;

 

    // the MountainBike subclass has one constructor

    public MountainBike(int startHeight, int startCadence,

                        int startSpeed, int startGear) {

        super(startCadence, startSpeed, startGear);

        seatHeight = startHeight;

    }

     

    // the MountainBike subclass adds one method

    public void setHeight(int newValue) {

        seatHeight = newValue;

    }

}

 

ตกลง MountainBike มีเมธอดกี่เมธอด ตัวแปรกี่ตัวแปร จงแจกแจงอธิบายมาใน text file

ตามปกติ เวลาเราสร้างออบเจ็กต์ขึ้นมา เราก็จะให้ไทป์ของมันตรงกับก้อนออบเจ็กต์จริงๆ เช่น

 

    public MountainBike myBike = new MountainBike();

 

** ก้อนออบเจ็กต์ คือตัวที่สร้างขึ้นด้วยคำสั้ง new ส่วนไทป์นั้น ในที่นี้คือ MountainBike ที่เรานิยามต่อจากคำว่า public

MountainBike นั้น extend มาจาก Bicycle ส่วน Bycycle ก็มาจาก Object (ไม่ได้เขียน extend แต่ว่าเป็นที่่เข้าใจกัน) ดังนั้น MountainBike คันหนึ่งก็ถือเป็นทั้ง Bicycle และ Object ดังนั้นจึงใช้ในที่ที่สามารถใช้ Bicycle และ Object ได้เลย 


จงเขียนโค้ดส่วนนี้ลงใน main ของ MountainBike สังเกตว่าคอมไพล์ได้หรือไม่ บันทึกผลลงใน text file  ถ้าไม่ได้ ต้องบอกสาเหตุด้วย

Object a = new MountainBike();  

ถ้ามีปัญหา ให้เขียนโค้ดแก้ซะ เขียนบอกว่าแก้โค้ดตรงไหนบ้างใน text file

 

แต่ในทางกลับกัน Bicycle คันหนึ่ง ไม่จำเป็นต้องเป็น MountainBike สิ่งที่โค้ดตีความว่าไม่ใช่ MountainBike จึงนำมาใส่ในตัวแปรที่เป็น MountainBike ไม่ได้ 

 
 จงเขียนโค้ดส่วนนี้ต่อลงไปใน main แล้่วดูซิว่ามีอะไรเกิดขึ้น 

    MountainBike myBike = a;

 

จะสังเกตได้ว่าคอมไพล์เลอร์แจ้ง error ออกมา เพราะสำหรับคอมไพเลอร์แล้ว a เป็นวัตถุชนิด Object ซึ่ง Object นั้น ไม่จำเป็นที่จะต้องเป็น MountainBike ดังนั้นจึงใช้ไม่ได้ เราแก้ error นี้ได้ด้วยการ สั่งเปลี่ยนไทป์เลย 

 

จงแก้ให้เป็น

    MountainBike myBike = (MountainBike)a;

การทำอย่างนี้เรียกว่าการ cast ซึ่งจะเป็นการทำ runtine check ว่า a ต้องถูกทำเป็น Mountainbike คอมไพเลอร์จะได้ไม่ต้องห่วงอะไรอีก ถ้าตอนรัน a ไม่ได้เป็นออบเจ็กต์ MountainBike จริงๆละก็ จะมี exception เกิดขึ้น (exception คือ error ที่เกิดตอนรันโปรแกรม)

ลองรันโปรแกรมนี้ดู หลังจากนั้น ทดลองเปลี่ยน new MountainBike() เป็น new Bicycle()  แล้วลองรันใหม่  เกิดอะไรขึ้น รายงานสิ่งที่เกิดและสาเหตุมาใน text file  

เปลี่ยนโค้ดให้กลับเป็นตามเดิม เพื่อไม่ให้เกิด exception

Note: เราสามารถตรวจออบเจ็กต์ได้ว่าเป็นชนิดไหนแน่ โดยใช้ โอเปอร์เรเตอร์ instanceof ตัวอย่างเช่น

 

        if (a instanceof MountainBike) {

           MountainBike myBike = (MountainBike)a;

        }

 ในโค้ดข้างบนนี้ เราสามารถแน่ใจได้ว่า จะไม่มี exception ที่เกิดจากการ cast ไม่ดี แน่นอน 


 Overriding and Hiding Methods

Instance Methods(เมธอดของออบเจ็กต์)

Instance method สำหรับสับคลาส ที่มี signature (ชื่อเมธอด จำนวนพารามิเตอร์ ไทป์ของพารามิเตอร์) และ return type เหมือนกับ instance method ที่นิยามใน superclass จะ override เมธอดของ  superclass 

Class Methods(เมธอดของคลาส)

ถ้าสับคลาสนิยาม class method ที่มี signature เหมือนกับในซุปเปอร์คลาส เรากล่าวได้ว่า เมธอดของสับคลาสนั้น hide เมธอดใน superclass

 

ถ้าเป็น override ตัวเมธอดที่เรียกใช้จะเป็นของตัวสับคลาส แต่ถ้าเป็น hide แล้วละก็ เมธอดที่เรียกใช้จะขึ้นอยู่กับว่าซุปเปอร์คลาสหรือสับคลาสเป็นคนเรียก 

เอาล่ะ ถึงเวลาทำแล็บต่อแล้ว ให้ทำดังต่อไปนี้

  1.       เขียนโค้ดดังนี้

public class Animal {

    public static void testClassMethod() {

        System.out.println("The class method in Animal.");

    }

    public void testInstanceMethod() {

        System.out.println("The instance method in Animal.");

    }

}

 

  1.       สร้างคลาส Cat ซึ่งเป็น subclass ของ Animal ดังต่อไปนี้

public class Cat extends Animal {

    public static void testClassMethod() {

        System.out.println("The class method in Cat.");

    }

    public void testInstanceMethod() {

        System.out.println("The instance method in Cat.");

    }

 

    public static void main(String[] args) {

        Cat myCat = new Cat();

        Animal myAnimal = myCat;

        Animal.testClassMethod();

        myAnimal.testInstanceMethod();

    }

}

 

ลองรันดู ทดลองเปลี่ยน Cat กับ Animal ดูตามที่ต่างๆ ผลจากการรันบอกอะไรเราบ้างเกี่ยวกับการเรียก class method และ instance method (เขียนอธิบายการทดลองแต่ละอย่างให้ละเอียดชัดเจน) จงเขียนรายงานต่อใน text file

 

หลังจากนั้น เพิ่มเมธอด a() เข้าไปในคลาส Cat และเปลียนโค้ดของเมนตามนี้


public void a(){

}
   
    public static void main(String[] args) {

        Cat myCat = new Cat();

        Animal myAnimal = myCat;

        Animal.testClassMethod();

        myAnimal.a();

    }

ดูว่าเกิดอะไรขึ้น คิดว่าทำไมถึงเกิดเหตุการณ์เช่นนี้ เขียนรายงานมาใน text file

ต่อไป ลองเพิ่มเมธอด b ให้ Animal ให้เป็นโค้ดดังนี้


public void b(){
    System.out.println("The instance method b in Animal.");
}

แล้วลองเรียก myAnimal.b(); ดู แทนการเรียก myAnimal.a(); 

เกิดอะไรขึ้นจงอธิบาย และให้เหตุผลขอสิ่งที่เกิดขึ้น ใน text file

์Note: ถ้าเป็นฟิลด์ หรือ instance variable นั้น ฟิลด์ที่ชื่อเหมือนฟิลด์ในซุปเปอร์คลาสจะ hide ฟิิลด์ของซุปเปอร์คลาส แม้ว่าไทป์จะไม่เหมือนกันก็ตาม ดังนั้นเราจะไม่สามารถเข้าถึงฟิลด์ของซุปเปอร์คลาสได้จากภายในสับคลาส นอกเสียจากจะใช้ีคีย์เวิร์ด super




Using the Keyword super

Accessing Superclass Members

ถ้าเมธอดของซุปเปอร์คลาสถูก override เราก็ยังเรียกเมธอดที่ถูก override ได้ โดยการใช้คีย์เวิร์ด super  

ให้ทำดังต่อไปนี้

  1. สร้างคลาสใหม่ ดังรูป 

public class Superclass {

 

    public void printMethod() {

        System.out.println("Printed in Superclass.");

    }

}

 

  1. สร้างสับคลาสที่ override เมธอด printMethod ดังรูป

 

public class Subclass extends Superclass {

 

    public void printMethod() { //overrides printMethod in Superclass

        super.printMethod();

        System.out.println("Printed in Subclass");

    }

 

    public static void main(String[] args) {

        Subclass s = new Subclass();

        s.printMethod();  

    }

}

 

รัน main นี้ดู แล้วอธิบาย ถึงสิ่งที่เกิดขึ้น และสาเหตุของสิ่งที่เกิดขึ้น มาใน text file เดียวกับอธิบาย Animal

 


วิธีการส่ง
ส่งจาร์ไฟล์ที่รวม source ทั้งหมด รวมทั้ง text file ที่ใช้ตอบคำถามด้วย ส่งมาทางเมล์ progmethcp@gmail.com ภายในวันพุธที่ 20 มิถุนายน เวลา 24.00น.

ไฟล์จะต้องตั้งชื่อว่า lab03_xxxxxxxxxx.jar โดย xxxxxxxxxx นั้นเป็นเลขประจำตัวนิสิต ส่วนใน subject ของเมล์ ให้ใส่ lab03_ xxxxxxxxxx_Time โดย xxxxxxxxxx นั้นเป็นเลขประจำตัวนิสิต และ Time เป็นเวลา (หน่วยเป็นชั่วโมง:นาที) ที่นิสิตใช้ในการทำแล็บนี้