เรียน Java เพื่อนำไปสร้าง Application ระดับโลก [9]


Object และ Generics

class ทุกตัว ใน java จะถูก inherit มาจาก java.lang.Object ซึ่ง Compiler จะเป็นตัว
จัดการจาก class A {} เป็น class A extends Object {} ซึ่งทำให้ได้รับ Method ต่างๆมาด้วยเช่น

  • public String toString();
  • public boolean equals(Object);
  • protected void finalize() throws Throwable;
  • public final void wait(long) throws InterruptedException;
  • protected native Object clone() throws CloneNotSupportedException;

เรามักนิยม Override สอง Method ที่สำคัญคือ toString(); เพื่อแสดงค่าของ instance
ตอน print และ equals(); เพื่อกำหนดเงื่อนไขการเท่ากันของ instance เช่น

class A{}

System.out.println(new A());//ผลลัพท์ที่ได้จะเป็นค่า reference ของ instance A
ทีนี้ลอง Override method toString(); ดู

class A{ public String toString() {return "This is A";}

System.out.println(new A());//ผลลัพท์ที่ได้คือ This is A

จากตัวอย่างเป็นการใช้ข้อดีของ OOP นั่นก็คือ Polymophism นั่นเอง ทำให้ได้ผลลัพท์
ที่หลากหลายตามแต่ละ instance

ปกติแล้วเราจะไม่สามารถใช้ operator == เพื่อเปรียบเทียบค่าของ instance ได้
เรามักจะใช้ method equals(Object); แทนเช่น

class A {

             int i;
              public boolean equals(Object o) {
                return i==((A)object).i;
            }

}

System.out.println(new A());//ค่า reference จะขึ้นตัวชื่อ class ตามด้วย @xxx
System.out.println(new A()==new A());//false เพราะเป็นการเปรียบเทียบ reference
System.out.println(new A().equals(new A()));//true

Generics

Generics นั้นเพิ่งเพิ่มเข้ามาใน java 5 เพื่อประโยชน์ในการทำ type safe ซึ่งจะถูก
ตรวจสอบตั้งแต่ Compile time ลองดูตัวอย่าง code ที่ไม่ใช้ Generics ครับ

class Box {
            Object component;
            Box(Object component) {setComponent(component);}
            void setComponent(Object component) {
                this.component = component;
            }
            Object getComponent() {
                return component;
            }

}

Box b = new Box("text");
b.setComponent(new java.util.Date());
//..//
(String)b.getComponent();// Object นี้เป็น type อะไร

จากตัวอย่างมีโอกาสเกิด Error ตอน runtime ได้เนื่องจาก type ของ Component
ได้เปลี่ยนไปเป็น java.util.Date แล้ว ภาษาโปรแกรมที่ปลอดภัยควรตรวจสอบ type
ได้ตั้งแต่ตอน compile time ทีนี้ลองดูตัวอย่างการใช้ generic เพื่อช่วยเรือง 
type safe ดังนี้

class Box<T> {
            T component;
            Box(T component) {setComponent(component);}
            void setComponent(T component) {
                this.component = component;
            }
            T getComponent() {
                return component;
            }

}

Box<String> boxString = new Box<String>("Hello");
String s = boxString.getComponent();//ไม่ต้อง casting เพราะ type เป็น String แน่นอน
boxString.setComponent(new java.util.Date());//Compile Error

int[]a = {0};
Box<int[]> boxInt = new Box<int[]>(a);
int[] i = boxInt.getComponent();//return type เป็น Array of integer

นอกจากจะทำ Generic ในระดับ Class, Constructor และ method ยังทำในระดับ
interface ได้ด้วยและสามารถมีได้หลาย type เช่น

interface Service<T,S> {

             S register(T t);

}

เราสามารถ extends generic เพื่อที่จะเจาะจงว่าสามารถใช้ Type อะไรได้บ้างดังนี้

        class A{}
        class B extends A{}
        class C extends A{}
        class Box<T extends A> {
            T component;
            Box(T component) {setComponent(component);}
            void setComponent(T component) {
                this.component = component;
            }
            T getComponent() {
                return component;
            }
        }
        Box<A> a;
        Box<B> b;
        Box<C> c;
        Box<String> s;//Compile Error!

Wildcards

จากตัวอย่างข้างต้นแม้ว่า B จะถูก inherit มาจาก A แต่เราไม่สามารถทำแบบนี้ได้ เช่น

        Box<A> a = new Box<B>(new B());//Compile Error!

เนื่องจาก Compiler จะมอง Box<A> กับ Box<B> เป็นคนละ Type กัน แต่เราสามารถ
แก้ปัญหาได้ดังนี้

        Box b = new Box<B>(new B());
        Box c = new Box<C>(new C());
        c = b;//Correct!

แต่กลับเป็นการเพิ่มปัญหาใหม่คือ Compiler จะยอมให้ c สามารถ set instance ของ 
Type A ได้ และยอมให้ getComponent ออกมาเป็น type C ได้อีกด้วยดังนี้

        c.setComponent(new B());
        C c2 = (C)c.getComponent();//Runtime Error!

ภาษา Java จึงมี wildcards ? ซึ่งเป็นการระบุขอบเขตของ Type ดังตัวอย่างนี้

        Box<?> b = new Box<B>(new B());
        b.setComponent(new B());//Compile Error!

เนื่องจาก b สามารถถือ reference ของ Box<?> โดยที่ ? เป็น type A ใดๆก็ได้ เช่น

        Box<?> b= new Box<A>(new A());
        b = new Box<B>(new B());
        b = new Box<C>(new C());

ความหมายของ ? จริงๆก็คือ unknown type ทำให้เราไม่สามารถเรียก setComponent
ได้เพราะ Compiler ไม่มีทางรู้ว่าตอน Runtime นั้น component จะเป็น Type อะไร 
ในทางกลับกันที่เราสามารถ get ค่าของมันได้ โดยที่จะ return ออกมาเป็น Type A 
(ตามที่ประกาศ โดย class Box<T extends A> {..} จากตัวอย่างข้างบน) เช่น

        Box<?> b = new Box<B>(new B());
        b.setComponent(new B());//Compile Error!
        B b2 = (B)b.getComponent();//Correct!

นอกจากนี้เรายังสามารถระบุขอบเขตของ ? โดยใช้ extends ได้เช่น

        Box<? extends A> b = new Box<A>(new A());
        b = new Box<B>(new B());

จากตัวอย่างจะเ้ป็นการระับุขอบเขตบนนั่นคือ reference b จะรับได้แค่
Box<A> และ Box<B> ได้เท่านั้นและไม่สามารถเรียก setComponent แต่เรียกใช้ 
getComponent ซึ่ง return เป็น Object ได้

ในทางตรงกันข้ามหากเราใช้ ? ร่วมกับ super จะเป็นการระบุขอบเขตล่างของ ? เช่น

       Box<? super B> b = new Box<A>(new A());
       b = new Box(B)(new B());

เนื่องจาก Box<A> และั Box<B> ตรงตามเงื่อนไข คือเป็น super ของ 
B<? super B> และเราสามารถเรียกใช้ b.setComponent(new B()); ได้เพราะเป็น
ลำดับล่างสุด ซึ่ง reference ใดๆสามารถถือได้ตามเงื่อนไขนี้ แต่เราไม่สามารถ
getComponent ได้ เพราะ Compiler ไม่มีทางรู้ว่าถือ reference ของ Type ลำดับ
อะไร

       b.setComponent(new B());//Correct!
       b.getComponent();Compile Error!

 

คำสำคัญ (Tags): #java
หมายเลขบันทึก: 386472เขียนเมื่อ 20 สิงหาคม 2010 07:54 น. ()แก้ไขเมื่อ 22 พฤศจิกายน 2023 14:36 น. ()สัญญาอนุญาต: ครีเอทีฟคอมมอนส์แบบ แสดงที่มา-ไม่ใช้เพื่อการค้า-อนุญาตแบบเดียวกันจำนวนที่อ่านจำนวนที่อ่าน:


ความเห็น (0)

ไม่มีความเห็น

พบปัญหาการใช้งานกรุณาแจ้ง LINE ID @gotoknow
ClassStart
ระบบจัดการการเรียนการสอนผ่านอินเทอร์เน็ต
ทั้งเว็บทั้งแอปใช้งานฟรี
ClassStart Books
โครงการหนังสือจากคลาสสตาร์ท