บทที่ 5: Objects และ Classes intro. to Java (FEU.faa)
if(i != 0 && i % 10 == 0)
buffer.append("\n");
//stop appending when there is no item left (null)
if(arr[i] == null)
break;
//left align data with width = 5
String out = String.format("%5s", arr[i]);
buffer.append(out);
}
//returning an output String
return new String(buffer + "\n");
}
ภายใน method toString() เราใช StringBuffer ในการเกบ็ สวนประกอบตา ง ๆ ทเ่ี ราตองการสง กลบั
ออกไป ซง่ึ จะประกอบไปดว ยขอ มูลทีไ่ ดรบั การกําหนดรูปแบบ (formatted) ไวก อนลว งหนาดว ยการ
ใช String out.format("%5s", arr[i]) นน่ั กค็ อื เราตองการใหความกวา งของขอมลู ทุกตัวมีคา เปน 5
เชนถา ขอมลู ของเราเปน 56, 7, 100 เราก็จะไดผลลพั ธเ ปน (□ หมายถึงหนง่ึ ชอ งตัวอกั ษร)
□□□56□□□□7□□100
เรานาํ ขอ มูลเหลา นีไ้ ปเกบ็ ไวใน buffer ดว ยการใช method append() ทุก ๆ ครั้งทเ่ี ราไดข อมลู ครบ
10 ตัวเราจะทําการ append newline เขา สู buffer ถา หากวา เราไดข ยายขนาดของ array แตไ มได
ใสขอ มูลครบตามขนาดที่ไดขยายข้ึน เราจะยุตกิ ารนําขอมลู เขาสู buffer เนื่องจากวา ขอ มลู เหลานี้มี
คา เปน null และเรากไ็ มตอ งการแสดงคา เหลา น้ี เม่ือเราไดข อมลู ทง้ั หมดทตี่ องการแลว เราก็สงกลบั
ออกไป โดยสงออกไปในรูปแบบของ String (เพราะ System.out.println() ตอ งการ String) ดว ย
คําส่งั
return new String(buffer + "\n");
ผูอ า นสามารถนําเอาเทคนิคนี้ไปใชกบั การแสดงขอมลู อืน่ ๆ ผา นทาง System.out.println() ไดโดย
ไมมีขอจาํ กดั ใด ๆ ทัง้ ส้ิน
เราสามารถทีจ่ ะสราง class เพื่อการใชง านของเราโดยไมม ีขดี จํากัดใด ๆ ทั้งนีก้ ็ตอ งขึน้ อยูกับลักษณะ
งานนั้น ๆ วาอยใู นรูปแบบไหน ความยาก งา ยของงานเปน อยางไร ตัวอยางการสรา ง array ขึ้นมาใช
งานเปน เพยี งตวั อยางเล็ก ๆ เพียงตวั อยา งเดยี วที่เราไดแสดงใหด ถู ึงขอดีของภาษา Java ยงั มสี ิง่ อน่ื
ๆ ทผี่ ูอานสามารถทีจ่ ะสรา งขนึ้ มาสาํ หรบั งานของตัวเองได
5.7 Generic Class
Class MyArray ท่ีเราไดออกแบบใชก อ นหนานเ้ี ลอื กใชข อมูลท่เี ปน comparable object ซ่งึ ยอมให
เราใชข อมลู ไดห ลากชนิด แต Java 1.5 ยงั มีโครงสรา งอกี ตัวหนงึ่ ทย่ี อมใหเรากําหนดชนิดของขอ มลู
ในขณะท่โี ปรแกรมกําลงั execute โดยเราตองกําหนดให class ทีเ่ ราสรา งขึ้นมีรูปแบบที่ Java
เรียกวา generic class โปรแกรม BucketOfItems.java เปนความพยายามของเราที่จะสราง array ท่ี
เกบ็ ขอมูลตามความตองการของผูใช ณ เวลาท่โี ปรแกรมกาํ ลังทาํ งานอยู
1: /**
2: Array of Generics
3: */
4:
5: class BucketOfItems<T> {
6: //initial capacity
7: private final int MAX = 3;
8: //generic container
9: private T[] bucket;
10: //number of items in container
11: private int count;
12:
13: public BucketOfItems() {
14: bucket = (T[])new Object[MAX];
15: count = 0;
16: }
17:
18: //getting container size
19: public int size() {
20: return count;
197
เร่ิมตน การเขยี นโปรแกรมดวย Java
21: }
22: //add item into container intro. to Java (FEU.faa)
23:
public void add(T value) {
24: //double container size if necessary
25: if(count > bucket.length - 1) {
26:
T[] temp = (T[])new Object[MAX * 2];
27: //copy items from bucket to temp
28: System.arraycopy(bucket, 0, temp, 0, bucket.length);
29:
//reassign bucket to temp
30: bucket = temp;
31:
}
32: //add new item
33: bucket[count++] = value;
34:
}
35:
36: //remove an object from container
37:
public boolean remove(T value) {
38:
int i;
39: //look for specified object in container
40:
for(i = 0; i < count; i++)
41:
42: if(bucket[i].equals(value)) //found
43: break;
44:
45: if(i == count) //not found
46: return false;
47:
48: else {
49: //move objects from higher index down
50: for(int j = i; j < count - 1; j++)
51:
bucket[j] = bucket[j + 1];
52: count--; //decrement size
53: return true; //success
54:
55: }
56:
}
57:
//search for a given object in container
58:
59: public boolean search(T key) {
60: for(int i = 0; i < count; i++)
if(bucket[i].equals(key)) //found
61:
62: return true;
63: } return false; //not found
64: //display items in container via standard output
65: public String toString() {
66:
67: StringBuffer out = new StringBuffer();
out.append("[" + bucket[0]);
68:
for(int i = 1; i < count; i++)
69:
70: out.append(", " + bucket[i]);
out.append("]");
71:
return new String(out);
72:
73: } }
ในบรรทัดท่ี 5 เราออกแบบ class ใหมีรูปแบบดังน้ี
5: class BucketOfItems<T> {
ตวั T ท่ีอยใู นเครือ่ งหมาย <> บอกถงึ ชนิดของขอ มูลท่ี class BucketOfItems สามารถรองรับได ซง่ึ
สามารถเปน ขอ มลู ชนิดที่ Java มีใหหรือเปน ขอมลู ที่เราสรา งข้นึ เองก็ได ตัวอกั ษรที่เราใชภ ายใน
เคร่อื งหมาย <> ก็ไมจ าํ เปนตองเปน ตัว T (เราเรียกวา type variable) เปนตวั อักษรใด ๆ ก็ได ก่ีตัวก็
ได แตโ ดยทวั่ ไปนิยมใช ตวั อักษรตวั ใหญต ัวเดียว และเมอ่ื เราเลอื กใชตวั อกั ษรใดแลว เราก็ตอ งใช
ตัวอักษรตวั นใ้ี นทกุ ๆ ทที่ ่ีเราอางถึงขอมลู ชนิดน้ี เชน ในบรรทดั ท่ี 9
9: private T[] bucket;
ในบรรทดั นี้เราประกาศใหต วั แปร bucket เปน array ท่ีใชเ กบ็ ขอมลู ชนิด T และเม่อื เราเรียกใช class
BucketOfItems นเี้ ราก็ตองบอกถึงชนิดนัน้ ๆ ของขอมูลทเี่ ราจะใชภ ายในโปรแกรม เชน
1: /**
198
บทท่ี 5: Objects และ Classes intro. to Java (FEU.faa)
2: Test module for array of generics
3: */
4:
5: class TestGenericArray {
6: public static void main(String[] args) {
7: //create array of Integers
8: BucketOfItems<Integer> bucket = new BucketOfItems<Integer>();
9:
10: //add ints in list into bucket
11: int[] list = {12, 2, 45, 67, 23, 98};
12: for(int item : list) {
13: bucket.add(item);
14: }
15:
16: System.out.println(bucket);
17: bucket.remove(45);
18: System.out.println(bucket);
19:
20: //create array of Strings
21: BucketOfItems<String> city = new BucketOfItems<String>();
22:
23: //add strings
24: city.add("Chiang Mai");
25: city.add("Chiang Rai");
26: city.add("Chiang San");
27:
28: System.out.println(city);
29:
30: String town = new String("Bangkok");
31: if(city.search(town))
32: System.out.println("Found " + town);
33: else
34: System.out.println(town + " is not in the list!");
35: }
36: }
ในบรรทดั ท่ี 8 เราไดสรา ง object จาก class BucketOfItems
8: BucketOfItems<Integer> bucket = new BucketOfItems<Integer>();
โดยเราไดก ําหนดใหขอมูลทต่ี อ งใชใน class BucketOfItems มีชนิดเปน Integer เพราะฉะน้นั การ
กระทาํ ทกุ ๆ อยางภายใน class BucketOfItems ก็จะกระทํากับ Integer สวนในบรรทดั ท่ี 21 เราได
สรา ง object จาก class BucketOfIems สําหรบั การทํางานกับ String เพราะฉะนัน้ การกระทาํ ตาง ๆ
กจ็ ะทาํ กบั String เทานั้น
เน่อื งจากวา Java ไมย อมใหเ ราสรา ง array สําหรับเกบ็ generic โดยตรงดังน้ันเราจงึ ตองกําหนดให
array ของเราเก็บ object กอนแลวจึงทาํ การเปล่ยี นใหเปน array ทีเ่ ก็บขอมูลชนดิ T ทหี ลงั
(BucketOfItems.java บรรทัดท่ี 14)
14: bucket = (T[])new Object[MAX];
วิธกี ารอาจไมส วยเทาไร แตกท็ าํ ใหเราทาํ งานกับขอ มูลท่เี ราไดอ อกแบบไวไดดีพอสมควร ผูอา นจะ
เห็นวาเม่อื เรา compile โปรแกรมของเราส่งิ ทเี่ ราไดจาก compiler กค็ ือขอ ความทเี่ ตือนถงึ การใช
โครงสรางที่ Java ไมคอ ยจะชอบใจเทา ไรนกั
Note: BucketOfItems.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
และเมื่อเรา compile ใหมด ว ย option: -Xlint:unchecked สิ่งที่เราไดคอื
BucketOfItems.java:14: warning: [unchecked] unchecked cast
found : java.lang.Object[]
required: T[]
bucket = (T[])new Object[MAX];
^
199
เริม่ ตนการเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
BucketOfItems.java:27: warning: [unchecked] unchecked cast
found : java.lang.Object[]
required: T[]
T[] temp = (T[])new Object[MAX * 2];
^
2 warnings
แตก็ยงั ยอมใหเ ราใชอยู และผลลัพธข องการ run โปรแกรม TestBucketOfItems.java ก็คอื
[12, 2, 45, 67, 23, 98]
[12, 2, 67, 23, 98]
[Chiang Mai, Chiang Rai, Chiang San]
Bangkok is not in the list!
[การสงคาทเ่ี ปน generic ออกจาก generic array]
ในการสงคา ท่ีเปน generic ออกจาก method น้ันดูอยา งผวิ เผนิ แลวกไ็ มนาจะยาก หรือซบั ซอนอะไร
มากมายนกั เชน ถา เราจะสง คาทีเ่ ปน คาท่ีอยตู รงกลางออกจาก array ที่เห็นกอ นหนา นเี้ รากอ็ าจเขียน
code ไดงา ย ๆ ดงั น้ี
public T getMiddleValue() {
return bucket[bucket.length / 2];
}
แตถา เราอยากให method ของเราเปน generic method เรากท็ าํ ไดด วยการกําหนดดังน้ี
public <T> T getMiddleValue() {
return (T) bucket[bucket.length / 2];
}
ผอู า นจะเห็นวาเราตองมี คาทส่ี งกลบั (return type) T และตัวแปรทบ่ี งบอกชนดิ ของขอ มูล (type
variable) <T> โดยเราไมส ามารถขาดตวั ใดตวั หนงึ่ ไดและในการเรียกใช method เรากส็ ามารถ
เรียกใชไดสองแบบคือ
int middle = bucket.<Integer>getMiddleValue();
หรือ
int middle = bucket.getMiddleValue();
ทัง้ น้ีก็เนอื่ งจากวา compiler มีขอมลู พอท่จี ะเรียกใช method ท่ีถูกตองตามชนดิ ที่ไดถกู กําหนดไว
[การกําหนดขอบเขตของ type variable]
บางคร้งั เราก็ตอ งการท่ีจะกาํ หนดขอบเขตของ type variable ใหทํางานอยูในกรอบของขอมลู นน้ั ๆ
เชน ตัวอยางทเ่ี ห็นน้ี
public <T extends Comparable> T largestItem() {
if(bucket.length == 0)
return null;
T largest = (T)bucket[0];
for(int i = 1; i < bucket.length; i++)
if(largest.compareTo(bucket[i]) < 0)
largest = (T)bucket[i];
return largest;
}
Method largestItem() ตองการท่ีจะคนหาขอมลู ที่มีคามากทสี่ ุดดว ยการเปรยี บเทียบคา ทุกตวั ท่ีมีอยู
ใน bucket ดวยการใช method compareTo() ถาเราไมกําหนดให type variable ของเราทํางาน
ภายใตขอบเขตของขอมูลที่เปน subclass ของ Comparable เราก็ไมสามารถเรียกใชได (เราจะพูด
เร่อื ง subclass ในบทตอ ไป ในท่ีนี้ขอเพียงใหเ ขาใจวาเราตอ งกาํ หนดแบบน้ี) method
largestItem() นบั แตน ีต้ อไปกจ็ ะทาํ งานกบั array ของ class ที่ตอ ยอดจาก interface Comparable
เทาน้นั (class ท่ีมี method compareTo())
200
บทที่ 5: Objects และ Classes intro. to Java (FEU.faa)
5.8 Package
Package เปน ท่ีรวมของ class ตา ง ๆ ที่ถกู เรียกใชใ นโปรแกรม หรอื method ตา ง ๆ class ทุก ๆ ตวั
ของ Java ไดถ กู จัดถกู เก็บอยใู น package ตา ง ๆ เชน java.lang หรือ java.io การเอา class ตาง ๆ
มารวมกันไวใ น package เดียวกันทาํ ใหก ารเรียกใช class ตา ง ๆ เหลานที้ ําไดงา ยข้ึน ถาผอู านมอง
ยอ นกลบั ไปดูโปรแกรมตวั อยา งตาง ๆ ทเี่ ราเขียนขน้ึ ก็จะเห็นการเรยี กใช package เหลาน้ีใน
โปรแกรมหลาย ๆ ตวั เราจะมาดูถงึ วิธีการสราง package เพอ่ื เก็บ class และการเรยี กใช package
เหลา นี้ในโปรแกรมตวั อยา ง
5.8.1 การสราง package
การสราง package นั้นไมย าก ขนั้ ตอนก็ไมซ ับซอนเทา ไร ข้นั ตอนแรกทีเ่ ราตอ งทํากค็ อื ใสคําวา
package ตามดว ย ชอื่ ของ package นัน้ กอนประโยคใด ๆ ในไฟลทเ่ี กบ็ class นั้น ๆ ท่เี ราสรา งขน้ึ
(ยกเวน ประโยคท่เี ปน comment) เชน
//package Shape
package Shape;
public class Rectangle {
…
…
}
ถาเราไมใสค าํ วา public ไวดานหนา ของ class หรอื method ทอี่ ยูใน package ทีเ่ ราสรางขึ้น
โปรแกรม หรือ class ตวั อืน่ ๆ ทีอ่ ยนู อก package กไ็ มส ามารถทจ่ี ะเรียกใช class นไ้ี ด ยกเวน class
อ่ืน ๆ ทอ่ี ยใู น package นีเ้ ทาน้ัน package ตวั อยางของเราใชชื่อวา Sample โดยเรากําหนดให
Sample ประกอบไปดวย class One และ class Two และเราไดสราง package อีกตวั หนึง่ ใน
Sample ใหชื่อวา oneMore และใน package oneMore นีเ้ ราจะเก็บ class Three ไว ดงั ทเี่ ห็นจาก
code ขางลา งน้ี
1: //sample package
2: package Sample;
3: import static java.lang.System.out;
4:
5: public class One {
6: public One() {
7: out.println("This is class One in Sample package.");
8: }
9: }
1: //sample package
2: package Sample;
3: import static java.lang.System.out;
4:
5: public class Two {
6: public Two() {
7: out.println("This is class Two in Sample package.");
8: }
9: }
1: //sample package
2: package Sample.oneMore;
3: import static java.lang.System.out;
4:
5: public class Three {
6: public Three() {
7: out.println("This is class Three in Sample\\oneMore package.");
8: }
9: }
ในการ compile ไฟลทั้งสามท่ีไดส รางข้นึ น้ี เราใชค าํ ส่ัง javac -d
D:\java.books\Intro.to.Java\Word.Format\edition3\source ตามดวยชอ่ื ไฟล เชน javac -d
D:\java.books\Intro.to.Java\Word.Format\edition3\source One.java Two.java Three.java
201
เริม่ ตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
เราตองใช option -d ในการ compile ไฟลท ง้ั สามเพือ่ บอกให Java รถู ึงแฟม ปลายทางทเ่ี ราตอ งการ
เกบ็ class ไฟลท ีเ่ กิดข้ึนจากการ compile ในทีน่ ีเ้ ราจะเกบ็ class ไฟลไวใน
D:\java.books\Intro.to.Java\Word.Format\edition3\source
ภายในไฟล One.java และ Two.java เราไดใชคําสง่ั package Sample เปน ตวั บอกถึงทเ่ี กบ็ class
ไฟล และในตวั ไฟล Three.java เราใชค าํ ส่ัง package Sample.oneMore เพราะฉะน้ัน class ไฟลท ่ี
เกดิ ขนึ้ จะถกู เก็บไวใ นแฟม (directory) เหลา น้ี ดงั ท่ีไดแสดงไวในภาพท่ี 5-8
package ชอื่ Sample ใน
D:\java.books\Intro.to.Java\Word.Format\edition3\
source
package ชอื่ oneMore ใน
D:\java.books\Intro.to.Java\Word.Format\edition3\
source\Sample
Class ที่ถูกสรางขึ้น
ภาพท่ี 5-8 แฟม เก็บ class file ทเี่ กิดขึน้ จากการ compile ดว ย option -d
หลงั จากนั้นเรากส็ รางโปรแกรมตรวจสอบการเรียกใช package ท่เี ราไดสรา งข้นึ โดยท่ีเรากําหนดให
มกี ารเรยี กใช class ตา ง ๆ ดว ยการใชค ําสัง่ import ดังน้ี
1: /**
2: Test the packages
3: */
4:
5: import Sample.One;
6: import Sample.Two;
7: import Sample.oneMore.Three;
8:
9: class TestPackage {
10: public static void main(String[] args) {
11: One object1 = new One();
12: Two object2 = new Two();
13: Three object3 = new Three();
14: }
15: }
เมอ่ื ทดลอง run ดูผลลัพธทไ่ี ดคือ
This is class One in Sample package.
This is class Two in Sample package.
This is class Three in Sample\oneMore package.
ในการสราง package น้ัน Java จะไปสรา งแฟมท่ีมีช่ือเหมือนกบั ทเี่ รากาํ หนดไว ดังที่ไดเ หน็ ใน
ตัวอยา ง และเราสามารถทจ่ี ะกําหนด sub-directory ดวยการใช . (dot) เชนท่ีเราไดทําไว
(Sample.oneMore) และเราตอ งไมล ืมใชคาํ วา public นําหนา class และ method ตา ง ๆ ท่ีเรา
ตองการใหโ ปรแกรม หรอื class หรือ method อ่ืน ๆ ที่อยนู อก package ใช
เราไมจําเปนตอ ง compile ดว ยการใชค าํ ส่ังทม่ี ี option –classpath ในการ compile โปรแกรมที่
เรยี กใช package ตาง ๆ ของ Java เพราะ Java ไดจ ัดการเร่ืองตาง ๆ เหลานใ้ี หเราเรยี บรอ ยแลว
202
บทท่ี 5: Objects และ Classes intro. to Java (FEU.faa)
ถา เราใช class ตา ง ๆ ท่อี ยใู น package ท่ีสรางข้ึนบอยครั้ง หรือทกุ คร้ัง เราก็สามารถทีจ่ ะกําหนดให
Java คนหา class ตา ง ๆ เหลานโ้ี ดยไมต อ งกําหนด option –d ในการ compile เราเพียงแตกาํ หนด
classpath ไวกอนการ compile ครั้งแรกเพียงครงั้ เดยี ว เชน
set classpath=e:\bc221Book\source
ถา เราไมอยากทีจ่ ะกาํ หนด classpath ทกุ ครัง้ ที่เราตอ ง compile เราก็กําหนด classpath ไวในไฟล
autoexec.bat สาํ หรบั Windows รนุ เกา ๆ สวน Windows รุนใหมเราตองกําหนด classpath ไวใน
environment variables (คลา ย ๆ กบั การกาํ หนด path ของ Java ในบทที่หนึ่ง) ถา เรามี package
อน่ื ๆ ทีเ่ ราตอ งการใช เรากใ็ ช ; เปนตัวแบง classpath เชน
set classpath=e:\bc221Book\source; c:\myOthers\Shape
สรปุ
ในบทนเ้ี ราไดสํารวจถึงวธิ กี ารสราง class การสราง object การสรา ง method และการสรา ง method
และ constructor ทีม่ ี signature ท่ีแตกตา งกนั ในการรองรับการเรยี กใชด ว ย parameter ทต่ี างกนั
การกําหนดนโยบายการเขาหาขอมลู ท่ีอยใู น class รวมไปถงึ การสรา ง nested class และการสราง
package โดยสรุปแลว เราไดทราบถึง
9 สว นประกอบของ class
9 ชอื่ ของ class จะตองเปน ชื่อเดียวกันกับๆฟลท ี่เก็บ class น้นั อยู
9 การประกาศตัวแปรทเ่ี รียกวา class variable ตองใชคําวา static นาํ หนา
9 ตวั แปรที่เปน instance variable สามารถทีจ่ ะเขาหาไดผา นทาง object ทเ่ี กิดจาก class นนั้
9 การสราง method จะตอ งบอกถึงสิง่ ทตี่ อ งสง กลับ ชนดิ และจํานวนของ parameter (ถาม)ี
9 Method ทปี่ ระกาศใหเ ปน static สามารถถกู เรียกใชไดถงึ แมว าจะไมม ี object ใด ๆ ถูกสราง
ขึน้
9 Method finalize() ถกู เรยี กใชโดย garbage collector เพอ่ื จดั การกบั หนว ยความจาํ ทีไ่ มใช
แลว
9 การเขาหาขอ มูลใน class มีสามแบบคือ private public และ protected (ไมนับแบบทไ่ี มม ีคาํ
ใด ๆ นาํ หนา)
9 การสราง class สามารถทจี่ ะสรางใหอ ยใู น class อ่นื ได
9 การสราง และ การใช package จะตองใชคาํ วา public นาํ หนา class หรือ method ทตี่ อ งการ
ใหผ ูอ น่ื ท่ีอยนู อก package ใช
แบบฝก หดั
1. จงออกแบบ class ท่ใี ชเ กบ็ ขอมูลเกีย่ วกับ นักศึกษา เชน รหัส ชือ่ -นามสกลุ ท่อี ยู และขอ มูลอ่นื
ๆ ทเี่ ห็นวาเหมาะสม ใหเขยี นโปรแกรมทดสอบการสราง object ตา ง ๆ จาก class ท่ีไดสรา งข้ึน
น้ี
2. จงออกแบบ class ทใ่ี ชเ ก็บขอมูลท่เี กย่ี วขอ งกับน้าํ หนัก เชน ตัน กิโลกรมั และ กรมั โดยให
ออกแบบใหม ี constructor ที่รองรบั การสรา ง object ดว ยจํานวน parameter ทีต่ า งกนั ชนิด
ของ parameter ทีต่ า งกัน รวมไปถึงการออกแบบ method ที่ทําการบวก การลบ object ตาง ๆ
ท่ไี ดถ ูกสรา งขึ้น ใหเขยี นโปรแกรมทดสอบ
3. จาก class MyArray ทีส่ ามารถเก็บขอ มลู ท่ีเปน object ตางชนดิ กนั ได จากตัวอยางที่ใหไ ว จง
เขียน method ทส่ี ง จาํ นวน object ทม่ี ีอยูใน array ใหช่อื วา getCount() และ method
dataAt() ท่สี งคา ของขอมลู ณ ตําแหนงท่ีกาํ หนดใหกลบั ไปยังผเู รียก เชน ถา เรยี กดวย
Object obj = arr.dataAt(7);
จะสง ขอ มลู ณ ตําแหนงที่ 7 มาใหก ับตวั แปร obj
ใหเ ขยี นโปรแกรมทดสอบ method ทีเ่ ขียนขึ้น
203
เร่มิ ตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
4. จงเขียนโปรแกรมท่มี ี method ในการคํานวณหาพ้นื ทีข่ องวงกลมที่มี parameter ตางชนิดกนั
เชน ผเู รียกใช method อาจสงขอมลู ทม่ี ีชนดิ เปน int double float หรือ String ท่ีเปน ตวั เลข
เชน "234" ใหเขยี นโปรแกรมตรวจสอบ method เหลา นี้
5. จงเขียนโปรแกรมท่ตี รวจสอบการใช overloaded constructor ในการกาํ หนดคา ใหกับ instance
variable ท่ีมอี ยใู น class นนั้ ๆ ใหเ ขยี นโปรแกรมทดสอบ
6. จงออกแบบ class สาํ หรับเกบ็ ขอ มูลทีเ่ ก่ียวของกับนกั ศกึ ษา เชน รหัสประจําตัว ช่ือ นามสกุล ท่ี
อยู และขอมลู อ่นื ๆ ทีจ่ ําเปน รวมไปถึง method ตา ง ๆ ทใ่ี ชใ นการกาํ หนดคา หรือประมวลผล
เกรดเฉลย่ี และ method สําหรบั การแสดงผลไปยังหนาจอ
7. จงออกแบบ class สาํ หรบั เกบ็ ขอ มูลของ วนั เดือน ป ในรูปแบบของ dd:mm:yyyy โดย
กาํ หนดใหข อมูลนนี้ าํ เขา มาจาก keyboard ใหเ ขียน Method ทท่ี ําหนา ท่ใี นการเปลีย่ นขอ มูลน้ี
ใหอ ยูในรปู แบบท่ีขน้ึ ตนดว ย วนั ตามดว ย วนั ที่ เดือน และ ป เชน วันจนั ทรท ่ี 12 สงิ หาคม พ.ศ.
2546 หรอื Monday 12 August 2003 ใหเ ขียนโปรแกรมทดสอบ
8. จงออกแบบ class Matrix สาํ หรับการประมวลผลตา ง ๆ เชน การบวก การลบ การคูณ และ
กระบวนการอนื่ ๆ ทเ่ี กย่ี วขอ ง ใหเขียนโปรแกรมทดสอบ
9. จงออกแบบ class ท่ใี ชส ําหรับการคํานวณหาอายุของ user ที่ใสเขา มาจาก keyboard ใน
รูปแบบของ mm/dd/yyyy โดยใหผลลพั ธที่หาไดอ ยูในรูปแบบของ จาํ นวนของชว่ั โมงและนาที
ใหเ ขียนโปรแกรมทดสอบ
10. จงออกแบบ class MyString ที่มี method สําหรับการประมวลทเ่ี ก่ยี วของกับ string ตา ง ๆ เชน
การบวก string สองตัว การคนหาคําใน string การลบคาํ ที่อยใู น string การนบั จาํ นวนตวั อกั ษร
ท่ีอยใู น string ใหเขียนโปรแกรมทดสอบ
11. จงเขยี นโปรแกรมที่แสดงปฏทิ ินของปท ก่ี าํ หนดใหจ าก user โดยใช class GregorianCalendar
ดงั ทไ่ี ดแ สดงใหดูเปน ตัวอยา งในบทน้ี โปรแกรมจะแสดงเดอื นทกุ เดือนท่ีมีอยู ใน dialog
window โดยกําหนดใหม ี scrollbar เปนตวั ชวยในการเลือกดเู ดือนตา ง ๆ
12. โปรแกรมตวั อยา งการแสดงปฏทิ นิ นั้น แสดงเฉพาะคาทเี่ ปนภาษาองั กฤษเทา นนั้ จงเปล่ียน
โปรแกรมดังกลา วใหส ามารถแสดงชือ่ เดือนและสัปดาหเ ปนภาษาไทย
13. จงเขียน code เพอื่ รองรับ class Int ท่ีมขี อ กาํ หนดดงั น้ี
class Int {
Int(value : int) สรา ง object ดว ยคา ที่กําหนดใหใ น value
getValue() : int สงคา int ใหแกผ เู รยี ก
isEven() : boolean สงคา true ถาคา ของ object เปน เลขคู หรือ false ถา ไมใ ช
isEven(value : Int) สงคา true ถา object Int เปน คู
isEven(value : int) สงคา true ถาคา value เปนคู
equals(value : Int) สงคา true ถา object นี้มีคา เทา กันกับ object ท่ีสง เขามา
equals(value : int) สงคา true ถาคา ทส่ี งเขา มาเทา กันกบั คา ของ object น้ี
}
จงเขยี นโปรแกรมทดสอบ method ทกุ ตวั
204
บทท่ี 5: Objects และ Classes intro. to Java (FEU.faa)
14. จงออกแบบ class Account ท่มี ีขอ กาํ หนดดงั นี้
class Account {
id : int เก็บหมายเลขบญั ชี
balance : double เกบ็ จาํ นวนเงินในบญั ชี
annualInterestRate : double เกบ็ อตั ราดอกเบ้ียประจําป
Account() – default account
Account(id : int, balance : double, annualInterestRate : double)
สรา ง account จาก parameter ทกี่ าํ หนดให
getId() : int สงคา id ใหผูเรียก
getBalance() : double สงคา balance
getAnnualInterestRate() : double สงอตั ราดอกเบีย้ ประจําป
setId(id : int) : void กําหนดคา ของ id สาํ หรับบัญชนี ้ี
setBalance(balance : double) : void กาํ หนดจาํ นวนเงินในบัญชี
getMonthlyInterestrate() : double สงอตั ราดอกเบี้ยตอเดอื นของบญั ชีนี้
withdraw(amount : double) : void
ถอนเงนิ ออกจากบัญชนี ี้ตามจาํ นวนทีก่ าํ หนดใน amount
deposit(amount : double) : void ฝากเงนิ เขาสูบัญชีนต้ี ามจาํ นวนทกี่ าํ หนดใน amount
}
ใหเขยี นโปรแกรมทดสอบการสรา ง object จาก class ดังกลาวและการเรยี กใช method ตาง ๆ
205
เรม่ิ ตนการเขยี นโปรแกรมดวย Java intro. to Java (FEU.faa)
206
เราไดพ ดู ถึงการสรา ง class และสว นประกอบตา ง ๆ ทีส่ ําคญั ของ class รวมไปถงึ การสรา ง intro. to Java (FEU.faa)
method ในบทท่หี า สําหรับบทที่หกนีเ้ ราจะสาํ รวจในเรอ่ื งของการสราง class ใหมจาก class
เดิมที่มีอยู การนาํ เอาสวนประกอบของ class เดมิ มาใชใ น class ใหม การถายทอดคณุ สมบัติ
และ กระบวนการตา ง ๆ จาก class เดิมสู class ใหม
หลังจากจบบทนีแ้ ลว ผูอานจะไดทราบถึงเรอ่ื งของ
o การใช class เดิมสําหรับการสราง class ใหม (Extended class)
o การถายทอดคณุ สมบัติ (Inheritance)
o คุณสมบัติ และการใชประโยชนจ าก polymorphism
o การสราง abstract class และ abstract method
o การใช และ การสรา ง interface
การสรา ง class ใหมจาก class เดิมท่มี ีอยแู ลว เปน การพฒั นาโปรแกรมทท่ี าํ ใหก ารเขียน code
ใชเวลานอ ย และเปน การใช code อยา งคมุ คา ท่ีสดุ Java ยอมใหมกี ารสราง class เดิมจาก class
ใหมไดอ ยางงาย ๆ โดยทผี่ เู ขียนโปรแกรมแทบจะไมตอ งทําอะไรมากมาย (ยกเวน code ใหมที่
เขียนขึน้ ) กอนทจี่ ะพูดถึงศัพทตาง ๆ ท่เี กยี่ วขอ งกบั การสราง class ใหมจ าก class เดมิ เราจะมา
ดูกันถึงตัวอยางของการสราง class ใหมจาก class เดิมกอน
6.1 การสราง class ใหมจาก class เดมิ และการถา ยทอดคณุ สมบัติ
เราจะเรม่ิ ตนดว ยการสรา ง class งาย ๆ class หน่ึงทเี่ ก่ียวกับรถทใี่ ชเครื่องยนต (motor vehicle)
โดยกาํ หนดใหมขี อ มูลทไ่ี มซ บั ซอ น เชน ย่หี อ (make) รนุ (model) ปทผ่ี ลิต (year) และ
จํานวนที่นัง่ (seats) พรอ มทง้ั กาํ หนดใหมี method สําหรับการเขา หาขอ มลู เหลา น้ัน หลังจากท่ี
ได class MotorVehicle แลว เราก็ออกแบบ class อื่น ๆ ที่ไดรบั คุณสมบตั ิจาก class
MotorVehicle ดังทแ่ี สดงใหเ หน็ คราว ๆ จาก diagram น้ี (เราจะดูโครงสรา งของ class ทงั้ หมด
ตอ ไป)
MotorVehicle
Car Motorcycle
Compact OffRoad Scooter Chopper
ภาพที่ 6-1 ตัวอยางของ base-class และ derived-class
เราออกแบบให class MotorVehicle เปน class แมแ บบ หรอื ที่เรยี กวา parent class (หรือ
base class หรอื super class) ซง่ึ จะเปน class ท่อี ยดู านบนสุดของ class ตา ง ๆ ในกลมุ นี้ เรา
กําหนดให class MotorVehicle มี class ลูก (children) อยสู อง class คอื class Car และ class
Motorcycle class ลกู ทัง้ สองตา งก็มี class ที่เปนลูกของมันเองอกี สอง class โดยที่ class Car
มลี ูกเปน class Compact และ class OffRoad สว น class Motorcycle มี class Scooter และ
class Chopper เปน class ลูก เราจะกําหนดให class ลกู ไดรบั คุณสมบตั ิจาก class แมท งั้ หมด
เรม่ิ ตน การเขยี นโปรแกรมดว ย Java
คอื ขอ มูลทุกตัวทมี่ ีอยใู น class MotorVehicle เรามาดกู นั ถงึ ขอมลู และ method ที่เรา intro. to Java (FEU.faa)
กาํ หนดใหมใี น class MotorVehicle
1: /**
2: Class MotorVehicle
3: */
4:
5: class MotorVehicle {
6: protected String make; //e.g. Ford, Honda
7: protected String model; //e.g. Taurus, Steed
8: protected int year; //e.g. 2001, 2003
9: protected int seats; //e.g. 4, 2
10:
11: //constructor
12: MotorVehicle(String make, String model, int year, int seats) {
13: this.make = make;
14: this.model = model;
15: this.year = year;
16: this.seats = seats;
17: }
18:
19: //returns company who makes this vehicle
20: protected String getMake() {
21: return make;
22: }
23:
24: //returns model of this vehicle
25: protected String getModel() {
26: return model;
27: }
28:
29: //returns year when this vehicle is made
30: protected int getYear() {
31: return year;
32: }
33:
34: //returns number of seats this vehicle has
35: protected int getSeats() {
36: return seats;
37: }
38: }
ใน class MotorVehicle เรากําหนดใหม ี constructor เพียงตวั เดยี วสําหรับการสราง object โดย
เราเลือกใชค ําสง่ั this ในการแยกแยะตวั แปรที่อยใู น class กับตัวแปรทีเ่ ปน parameter
MotorVehicle(String make, String model, int year, int seats) {
this.make = make;
this.model = model;
this.year = year;
this.seats = seats;
}
เราไมจ ําเปนที่จะตองใช this เปนตวั บงบอกตัวแปรเสมอไป ถา เราใชตวั แปรท่อี ยใู น parameter
list ทม่ี ีชือ่ ไมเหมอื นกับ ตวั แปรของ class (เชน ตัวอยา งอ่ืน ๆ ทเี่ ราไดแสดงไวใ นบททีห่ า) สว น
method อ่ืน ๆ ที่มอี ยกู เ็ ปน เพียง method ที่สง คาของตวั แปรเหลาน้ีใหก บั ผูเรียก สําหรับ class
อืน่ ๆ ท่เี ราไดสรางขนึ้ มดี งั นี้
1: /**
2: Class Car
3: a subclass of MotorVehicle
4: */
5:
6: class Car extends MotorVehicle {
7: //number of doors this car has
8: private int doors;
9:
10: //default constructor
11: Car(String make, String model, int year,
int seats, int doors) {
12: //calling MotorVehicle's constructor
208
บทที่ 6: Classes และการถายทอดคุณสมบตั ิ
13: super(make, model, year, seats); intro. to Java (FEU.faa)
this.doors = doors;
14: }
15:
//returns number of doors
16: protected int getDoors() {
17:
18: return doors;
}
19:
20: public String toString() {
21: StringBuffer buffer = new StringBuffer();
buffer.append(super.getMake() + ", " +
22: super.getModel() + ", " +
23: super.getYear() + ", " + "seating: " +
super.getSeats() + ", " + doors + " doors.");
24: return new String(buffer);
25:
26: }
27:
28:
29:
30: }
เราสรา ง class Car จาก class MotorVehicle ดว ยการใชคาํ สง่ั class Car extends
MotorVehicle ซง่ึ เปนคาํ สง่ั ท่ี Java กําหนดใหใชถ าตอ งการสราง class ใหมท ี่ตองการใช
คุณสมบัตขิ อง class อ่นื
ภายใน class Car ทเ่ี ราไดส รา งขนึ้ เรากาํ หนดใหม ีตัวแปรหนง่ึ ตวั ท่เี ปนตัวกาํ หนดจาํ นวนของ
ประตทู ี่รถคนั นม้ี อี ยู และเพือ่ ใหการแสดงผลไปยังหนา จอทําไดง ายข้ึน เราก็สราง method
toString() สาํ หรบั การแสดงผลของ object ท่ีเกดิ จาก class Car ของเรา เราเรียกขอมลู ทเี่ รา
ไดรับการถายทอดจาก class MotorVehicle ดว ยการใชค ําสง่ั ดังนี้
super.getMake();
เม่อื Java เห็นการใชคาํ สงั่ แบบน้ี Java กจ็ ะไปคนหา method getMake() ที่อยใู น class ทเ่ี ปน
class แม หรอื ทเ่ี รยี กกันวา super class พรอ มท้งั ประมวลผลคําสั่งตา ง ๆ ท่มี อี ยูใน method
getMake()
ผอู า นจะเหน็ วาเราไมตองประกาศตัวแปรขน้ึ มาใชใหมใน class Car ของเราเลย เราสามารถ
เรียกใชตัวแปรเหลา น้จี าก class MotorVehicle ไดเ ลย เรามาทดสอบ class ทง้ั สองดว ยการ
สรา ง object จาก class Car สองตัว เชนทเี่ หน็ ในโปรแกรม TestVehicle.java น้ี
1: /**
2: Test module for class Car
3: */
4:
5: class TestVehicle {
6: public static void main(String[] args) {
7: //create two cars, ford and honda
8: Car ford = new Car("Ford", "Taurus", 2001, 5, 5);
9: Car honda = new Car("Honda", "City", 2003, 4, 4);
10:
11: //display information about cars
12: System.out.println(ford);
13: System.out.println(honda);
14: }
15: }
ผลลพั ธท เี่ ราไดจากการ run คอื
Ford, Taurus, 2001, seating: 5, 5 doors.
Honda, City, 2003, seating: 4, 4 doors.
209
เรมิ่ ตนการเขยี นโปรแกรมดว ย Java
[access modifier: protected]
เราไดใชน โยบายการเขา หาแบบทีใ่ ชค าํ วา protected ซ่ึงเราไมไดอธบิ ายไวเลยกอ นหนา นี้ intro. to Java (FEU.faa)
สาเหตกุ ็เนอื่ งจากวาคําวา protected โดยสวนใหญจ ะใชกนั ในเร่ืองของการถา ยทอดคุณสมบตั ิ
จาก class แมไปยัง class ลูก โดยกําหนดไวว า class ลูกสามารถท่ีจะใชต ัวแปร (หรอื method
ท่ีใชค ําวา protected นําหนา ) จาก class แมไ ดอ ยางไมมีเง่ือนไข แตถาเราใชคําวา private
แทน class ลูกไมสามารถท่จี ะเขาหาตัวแปร หรือ method เหลาน้ีได ดังตัวอยางตอ ไปนี้
Car(String make, String model, int year, int seats, int doors) {
super(make, model, year, seats);
this.doors = doors;
System.out.println("base class: " + super.make);
}
ใน class MotorVehicle เราเปลี่ยนนโยบายการเขา หาตัวแปร make ใหเ ปน private
private String make;
และเพ่ิมประโยค
System.out.println("base class: " + super.make);
ใน constructor ของ class Car ซ่ึงเปน ประโยคท่ีพยายามเขาหาตวั แปรใน class MotorVehicle
ดวยการใช super.make Java จะไมย อมใหเ รา compile พรอมกบั ฟองวา เราไมสามารถเขา หา
ตวั แปรตวั น้ไี ด วิธีเดียวที่เราจะเขาหาตัวแปรเหลา นี้ได กค็ ือการเขาผานทาง method
getMake() ทเ่ี ราไดก ําหนดนโยบายการเขาหาใหเ ปน public เทา นั้น
โดยท่วั ไปเรามกั จะกําหนดใหต ัวแปรที่ใชร ว มกันใน class ลูก (ทีม่ อี ยูใ น class แม) ทั้งหลายมี
นโยบายการเขาหาที่เปนแบบ private เพอื่ ปองกนั การใชท ี่ไมพึงประสงคจาก class อน่ื และเรา
ก็ควรจะกาํ หนดให method ท่ีอยูใน base class มีนโยบายการเขาหาท่เี ปนแบบ protected ดว ย
เหตุผลเชน เดียวกนั และเหตผุ ลอีกอันหน่งึ กค็ ือ คําวา protected เมอื่ มีการนํามาใชแ ลว class
อ่นื ๆ ท่ีอยใู น package เดียวกันก็สามารถที่จะเขาหาตวั แปร หรอื method เหลาน้ไี ด ดงั นนั้ ถา
ตองการให class ตาง ๆ ของเราทีส่ รางขึ้นในตวั อยา งเปน class ที่การใชนโยบายการเขาอยาง
ถกู ตอง เรากต็ อ งเปลีย่ น ตวั แปรใน class MotorVehicle ของเราใหเ ปน ดงั นี้
private String make; //e.g. Ford, Honda
private String model; //e.g. Taurus, Steed
private int year; //e.g. 2001, 2003
private int seats; //e.g. 4, 2
เราไมส ามารถท่ีจะเปล่ยี นนโยบายการเขา หาของ method toString() ใหเ ปน protected ไดก ็
เพราะวา Java ไดกาํ หนดใหก ารเขา หาของ method toString() เปนแบบ public ไวแ ลว ซ่ึงเรา
จะไดอธิบายตอ ไปในเรือ่ งของการ override
คาํ วา protected ยังมคี วามหมายตอสมาชิกอื่น ๆ ท่ีอยใู น package เดยี วกัน น่ันก็คอื ทกุ คน
(สมาชิก) สามารถทจ่ี ะเขา หา class หรอื method ตา ง ๆ ไดอ ยา งไมม เี งอ่ื นไขถา มกี ารใช
protected เปนนโยบายของการเขาหา แตถา อยตู าง package กันการเขาหาจะตองเปนการอา ง
ถงึ class หรือ
6.1.1 ลาํ ดบั การเรียก constructor
กอนที่เราจะพูดถึงการ override เราจะมาดูกันถึงเรอ่ื งลาํ ดบั ของการเรียก constructor ของ
Java ในกรณที ่ีมกี ารสราง class ใหมจ าก class ท่มี ีอยู สมมติวาเรามี class ดังน้ี
1: /**
2: How constructors are called
3: */
4:
5: class WareHouse {
6: public WareHouse() {
7: System.out.println("WareHouse constructor");
8: }
210
บทท่ี 6: Classes และการถายทอดคุณสมบตั ิ intro. to Java (FEU.faa)
9: }
10:
11: class Maintainance extends WareHouse {
12: public Maintenance() {
13: System.out.println("Maintenance constructor");
14: }
15: }
16:
17: class PaintShop extends Maintenance {
18: public PaintShop() {
19: System.out.println("PainShop constructor");
20: }
21:
22: public static void main(String[] args) {
23: PaintShop p = new PaintShop();
24: }
25: }
เราไดก าํ หนดให class PaintShop ไดร บั การถายทอดคุณสมบตั จิ าก class Maintenance และ
class Maintenance ไดรับการถา ยทอดจาก class WareHouse โดยท่ีเราเพียงแตสราง
constructor ของแตล ะ class เทานัน้ ซ่ึงเมอื่ เราทดลอง run ดเู ราก็ไดผลลพั ธดังน้ี
WareHouse constructor
Maintenance constructor
PainShop constructor
ผูอานจะเหน็ วาโปรแกรมทดสอบของเราสราง object จาก class PaitShop เพียงตัวเดยี วเทา น้นั
แตผ ลลพั ธไดแ สดงถงึ การเรียก constructor ถึงสามตัวซ่ึงเกิดข้นึ ตามลาํ ดบั ชั้นของ class ทมี่ อี ยู
จากการกาํ หนดการถา ยทอดคณุ สมบัติ ถึงแมว า เราจะไมสรา ง constructor ใหก บั class
PaintShop ก็ตามการสรา ง object จาก class PaitShop จะทาํ ให constructor ของ class
Maintenance และ class WareHouse ถูกเรยี กเชนเดยี วกัน
6.1.2 การ override method ทอ่ี ยูใ น class แมจาก class ลกู
เพอื่ ใหเหน็ ถึงความพิเศษของ การถา ยทอดคณุ สมบัติ และเพ่ือเปนการแนะนําเรอ่ื งของการ
override เราจะสรา ง class Compact ขน้ึ มาอกี class หนงึ่ โดยกําหนดให class Compact นี้
เปน class ทีไ่ ดร ับการถายทอดคุณสมบัตจิ าก class Car ดังน้ี
1: /**
2: Class Compact
3: Derived from Car
4: */
5:
6: class Compact extends Car {
7:
8: //constructor -using base class (Car) constructor
9: Compact(String make, String model, int year, int seats, int doors) {
10: super(make, model, year, seats, doors);
11: }
12:
13: //overide Car's toString() method
14: //presenting Compact car's details as string
15: public String toString() {
16: StringBuffer buffer = new StringBuffer();
17: buffer.append("Compact car: ");
18: buffer.append(super.toString());
19:
20: return new String(buffer);
21: }
22: }
class Compact ของเราเรยี กใชขอ มูลทุกอยา งท่ี class แมม ใี ห ตวั แรกที่เราเรียกใชก ค็ ือ
constructor ของ class Car (ซ่งึ constructor ของ class Car กเ็ รียกใช constructor ของ
class MotorVehicle) ตวั ทส่ี องทเี่ ราเรียกใชก ็คือ method toString() ของ class Car ซ่ึงเราได
เพิม่ คาํ วา "Compact car: " ไวกอนหนา ขอ มูลอืน่ ๆ ดว ยการใช method append() ของ class
StringBuffer ดังนี้
211
เรม่ิ ตนการเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
buffer.append("Compact car: ");
buffer.append(super.toString());
เม่ือทดลอง run ดวยโปรแกรม
1: /**
2: Test module for Compact car
3: */
4:
5: class TestCompact {
6: public static void main(String[] args) {
7: Compact honda = new Compact("Honda", "Jazz", 2004, 4, 4);
8:
9: System.out.println(honda);
10: }
11: }
ผลลพั ธท ไ่ี ด คอื
Compact car: Honda, Jazz, 2004, seating: 4, 4 doors.
ซง่ึ ตา งจากการ run กอนหนา น้ี (ตอนทีเ่ ราสราง object จาก class Car)
เราใชเทคนิคที่เรยี กวา method overriding ในการแสดงผลขอมูลของ object ที่เกิดจาก class
Compact ในการ override (ซึง่ ตา งกบั overload ท่เี ราไดทาํ กอนหนา น้ี – overload ทํากบั
method ทีอ่ ยูใ น class เดยี วกันและตอ งเปน method ที่มี parameter list ไมเหมอื นกัน)
method จาก class แม หรือที่เรยี กวา base class นัน้ เราสามารถทีจ่ ะเขยี น code ใหท ํางานใน
ลกั ษณะใดก็ได โดยทั่วไปการ override method ทําใหการเรยี กใชงานทําไดงา ยข้นึ ไมสับสน
เพราะ method ชื่อเดียวกันมีอยูใ น class ทุกตัว แตท าํ หนาทต่ี ามทีไ่ ดกาํ หนดไวใน method
ของ class นน้ั ๆ
เราสามารถทจ่ี ะ override method ทม่ี ีอยูใน class แมไ ดท ุกตวั และ object ท่เี กิดจาก class
ลกู หรือทเ่ี รียกวา derived class นนั้ เมือ่ มีการเรยี กใช method ทีไ่ ดร ับการ override Java จะ
ไปเรียก method ท่อี ยใู น class ลูก ไมใช method ที่อยูใ น class แม
จากตวั อยางของ class Compact ที่ไดกลาวไว เราไดใ ชทั้ง การถา ยทอดคณุ สมบัติ และการ
override method โดยเราไดรับการถา ยทอดในเรื่องของตัวแปร และไดใชเทคนคิ การ override
ในการใช method toString()
Method ทไ่ี ดรับการ override ใน class ลูกนัน้ ไมส ามารถที่จะเปลี่ยนแปลงนโยบายของการเขา
หาใหเ ปนอยางอน่ื ทีม่ ีความเขม งวดกวาได เชน ถา method ใน class แมมีนโยบายการเขาหาที่
เปน public ใน class ลกู กไ็ มสามารถที่จะเปลย่ี นใหเ ปน private ไดเพราะการเขา หาแบบ
private นน้ั เขม งวดมากกวา แตถ าใน class แมน โยบายเปน private เราสามารถที่จะเปลยี่ นให
เปน public ได พดู งา ย ๆ กค็ ือวา เราเพ่ิมความเขม งวดนโยบายการเขา หาใน class ลูกไมไ ด แต
ลดลงได
เรามาลองดตู วั อยางของการถา ยทอดคุณสมบตั กิ ันอีกสกั ตัวอยา งหน่ึง สมมติวา เรามี class ตา ง ๆ
ดังท่แี สดงใน diagram น้ี
MyShapes
MyPolygon MyCircle
MyTriangle MyRectangle MySquare
212
บทที่ 6: Classes และการถายทอดคุณสมบัติ intro. to Java (FEU.faa)
ภาพที่ 6-2 ตัวอยาง class ท่เี ก่ียวขอ งกบั shape ตา ง ๆ
โดยกําหนดใหก ารถา ยทอดคณุ สมบตั เิ ปน ไปดงั ทเี่ หน็ ใน diagram คอื MyShapes เปน base
class MyPolygon และ MyCircle เปน class ลูกของ MyShapes สวน MyTriangle,
MyRectangle และ MySquare เกิดมาจาก class MyPolygon
ในทกุ ๆ class เรากําหนดใหม ี method what() เพยี ง method เดียว ดงั ทแี่ สดงไวใน code ท่ี
เหน็ นี้
1: /**
2: Class MyShapes
3: Base class for all shapes
4: */
5:
6: public class MyShapes {
7: //Information about this shape
8: protected String what() {
9: return "I am a shape.";
10: }
11: }
1: /**
2: MyPolygon
3: A subclass of MyShapes
4: */
5:
6: public class MyPolygon extends MyShapes {
7: //Information about this shape
8: protected String what() {
9: return "I am a polygon.";
10: }
11: }
1: /**
2: MyCircle
3: A subclass of MyShapes
4: */
5:
6: public class MyCircle extends MyShapes {
7: //Information about this shape
8: protected String what() {
9: return "I am a circle.";
10: }
11: }
1: /**
2: Triangle
3: A subclass of Polygon
4: */
5:
6: public class MyTriangle extends MyPolygon {
7: //Information about this shape
8: protected String what() {
9: return "I am a triangle.";
10: }
11: }
1: /**
2: MySquare
3: A subclass of MyPolygon
4: */
5:
6: public class MySquare extends MyPolygon {
7: //Information about this shape
8: protected String what() {
9: return "I am a square.";
10: }
11: }
1: /**
2: MyRectangle
213
เริ่มตนการเขียนโปรแกรมดวย Java intro. to Java (FEU.faa)
3: A subclass of MyPolygon
4: */
5:
6: class MyRectangle extends MyPolygon {
7: //Information about this shape
8: protected String what() {
9: return "I am a rectangle.";
10: }
11: }
เราเขียนกําหนดใหโปรแกรมตรวจสอบเปนดังนี้
1: /**
2: Testing module for shapes
3: */
4:
5: class TestMyShapes {
6: public static void main(String[] args) {
7: MyShapes shape = new MyShapes();
8: MyShapes polygon = new MyPolygon();
9: MyShapes square = new MySquare();
10: MyShapes circle = new MyCircle();
11:
12: //displays informations about shapes
13: System.out.println(shape.what());
14: System.out.println(square.what());
15: System.out.println(circle.what());
16: System.out.println(polygon.what());
17: }
18: }
ในโปรแกรมตรวจสอบเราไดสราง object สีต่ วั จาก class MyShapes แตท าํ การกําหนดการสรา ง
ผา นทาง constructor ของ class นั้น ๆ ทเ่ี ราตอ งการสรา ง เชน
MyShapes sq = new Square();
ถามองดูอยา งผวิ เผนิ จะเหน็ วาการประกาศแบบน้ีไมน าทจี่ ะทาํ ได เนื่องจากวา เรากาํ หนดให sq
เปน object ที่มีสถานะเปน MyShapes แตก ลบั ไปเรียก constructor ของ MySquare แต Java
ยอมใหการสรา ง object แบบน้ีเกิดขนึ้ ไดก ็เพราะวา MySquare เปน class ที่เกดิ มาจาก class
MyShapes (พูดงาย ๆ ก็คอื MyCircle เปน MyShapes แบบหน่งึ ) และภายใน class MyShapes
เรากําหนดใหมี method what() อยู ดงั นนั้ class ลูกทเ่ี กดิ มากส็ ามารถท่ีจะเขา หา method นี้
ไดแ ต ภายในตวั class ลูกท้งั หมดก็มี method what() อยดู งั นน้ั การเรียก method what()
ขึน้ มาใชจึงเปน การเรียก method ท่มี อี ยูภ ายใน class ลกู (overriding) ดังทีแ่ สดงใหเ หน็ จาก
ผลลพั ธน ้ี
I am a shape
I am a square.
I am a circle.
I am a polygon.
6.2 Polymorphism (ความมีรปู แบบทีห่ ลากหลาย)
การ overload (และ override) method ตา ง ๆ ทีเ่ ราไดแ สดงใหดใู นบทท่ี 5 (และกอนหนา น้)ี ก็
อาจเรยี กไดว าเปน ความสามารถของการมีรูปแบบทหี่ ลากหลายได กลาวคอื เรามี method ทมี่ ี
ช่อื เดยี วกนั แตม ีความสามารถรองรบั การทํางานไดห ลายรปู แบบ สวนการทํางานในลกั ษณะที่ได
กลาวมาในเรือ่ งของการสรางรูปทรงตาง ๆ กอนหนา นเ้ี ราเรียกวา late binding หรือที่เรยี กกัน
มากมายในหนงั สือหลาย ๆ เลมวา polymorphism ซึ่งหมายถงึ ความเปลยี่ นแปลงรูปแบบตาม
สภาพของ object ท่ไี ดถ ูกสรางขึน้ หรอื ท่ีเปนอยู คาํ วา late binding หมายถึงเวลาที่ compiler
จดั สรรหนวยความจําใหกับตัวแปรในขณะที่โปรแกรมกําลังถกู execute (run อยู) ไมใ ชในขณะ
ทีก่ าํ ลัง compile โปรแกรม
Polymorphism ทาํ ไดเฉพาะ method เทา นั้นเราไมสามารถจะใชวธิ ีการแบบนี้กบั ตวั แปรที่อยใู น
class ได การเขา หาตัวแปรจะตอ งทาํ ผา นทาง object ที่เกิดจาก class น้ัน ๆ เทาน้นั
214
บทท่ี 6: Classes และการถา ยทอดคุณสมบตั ิ intro. to Java (FEU.faa)
สมมติวาเราตองการที่จะเขยี น method ท่ีคาํ นวณหาเสนรอบวงของ object ตา ง ๆ ทสี่ รา งขึ้นมา
จาก class Shapes เราก็อาจทําไดด ว ยการเขยี น method ลงไปใน class น้ัน ๆ (ทถี่ ูกสรา งมา
จาก class แม) แตก ารกระทําดงั กลา วคงไมค อ ยดเี ทาไรนัก ถาเราไมร ูวา object ท่ีเราตองการ
สรา งขึ้นมานนั้ รูปรา งหนา ตาเปน อยางไร และคงจะไมคอ ยเขาทาเทาไรนกั ที่จะหาเสนรอบวงของ
shape ท่เี รายังไมรูวาเปน shape อะไร แต Java เอ้อื โอกาสใหเ ราสามารถทีจ่ ะประกาศ
(declare) method ใน class แมแ ตไ ปกาํ หนดหนา ท่ี (define) ใน class ลกู วธิ ีการดงั กลาวเรา
เรยี กวา การสราง abstract class
abstract class เปน class ท่มี กี ารประกาศ method ใน class แม แตไมม กี ารกําหนดหนาท่ใี ด ๆ
เร่อื งของการกําหนดหนา ทจ่ี ะเปนภาระของ class ลกู
Abstract class ไมย อมใหเราสราง object หรอื ทเ่ี รียกวา instantiation ได เชน เราไมสามารถ
สรา ง object จาก class Shapes ท่เี หน็ นีไ้ ดแ ละ compiler จะฟอ งทันทถี า เราพยายามสรา ง
object จาก class Shapes สมมติวา เราประกาศตัวแปรดังนี้
Shapes s = new Shapes("Just a shape");
และเรยี ก compiler ใหทําการแปลงชดุ คําสงั่ สิง่ ทเี่ ราไดค ือ
TryShapes.java:3: Shapes is abstract; cannot be instantiated
Shapes s = new Shapes("Just a shape");
^
1 error
เพราะฉะนน้ั เราตอ งใชความระมดั ระวังในการออกแบบ class ท่เี ราตอ งการใหเ ปน abstract
อยา งดี หากเราเผลอไปสราง object เขาเราก็จะได error แทนสิง่ ทเี่ ราตอ งการ
1: /**
2: Class Shapes
3: Base class for all shapes
4: */
5:
6: public abstract class Shapes {
7: private String iAm;
8:
9: //default constructor
10: Shapes(String whatIam) {
11: iAm = new String(whatIam);
12: }
13:
14: //self info.
15: public String toString() {
16: StringBuffer buffer = new StringBuffer();
17: buffer.append("I am a " + iAm);
18: return new String(buffer);
19: }
20:
21: //dummy method - implementation is done in derived classes
22: public abstract double perimeter();
23: }
เรากําหนดให class Shapes ของเราใหเปน abstract class พรอ มท้งั ประกาศ method
perimeter() ท่ีไมมี code ใด ๆ อยเู ลย หลังจากนัน้ เราก็สราง class อืน่ ๆ ท่ีไดรบั การถายทอด
คณุ สมบัติจาก class Shapes ดังน้ี
1: /**
2: Class Polygons
3: */
4:
5: public abstract class Polygons extends Shapes {
6:
7: //constructor
8: Polygons(String type) {
9: super(type);
10: }
11:
215
เริ่มตนการเขียนโปรแกรมดวย Java
12: //self info. intro. to Java (FEU.faa)
public String toString() {
13:
14: return super.toString();
}
15:
16: //dummy method to be implemented by derived classes
17: public abstract double perimeter();
18:
19: }
1: /**
2: Class Triangle
3: A subclass of Polygons
4: */
5:
6: public class Triangle extends Polygons {
7: private double side1, side2, side3;
8:
9: //constructor
10: Triangle(String type, double side1, double side2, double side3) {
11: super(type); //calling base-class constructor
12: this.side1 = side1;
13: this.side2 = side2;
14: this.side3 = side3;
15: }
16:
17: //self info.
18: public String toString() {
19: return super.toString();
20: }
21:
22: //calculating a perimeter of this triangle
23: public double perimeter() {
24: return side1 + side2 + side3;
25: }
26: }
1: /**
2: Class Circle
3: A subclass of Shapes
4: */
5:
6: public class Circle extends Shapes {
7: private double radius;
8:
9: //constructor
10: Circle(String type, double radius) {
11: super(type);
12: this.radius = radius;
13: }
14:
15: //self info
16: public String toString() {
17: return super.toString();
18: }
19:
20: //calculating a perimeter of this circle
21: public double perimeter() {
22: return 2.0 * Math.PI * radius;
23: }
24: }
1: /**
2: Class Square
3: A subclass of Polygons
4: */
5:
6: public class Square extends Polygons {
7: double side;
8:
9: //constructor
10: Square(String type, double side) {
11: super(type);
12: this.side = side;
216
บทที่ 6: Classes และการถา ยทอดคุณสมบัติ
13: } intro. to Java (FEU.faa)
14: //self info.
15: public String toString() {
16: return super.toString();
17: }
18:
//calculating a perimeter of this square
19: public double perimeter() {
20:
21: return side * 4;
}
22:
23:
24: }
หลังจากทีเ่ ราไดสรา ง class Polygons, class Circle, class Triangle, และ class Square พรอ ม
ทั้งกาํ หนดหนาที่ของ method perimeter() ใน class Circle, class Triangle, และ class
Square เรียบรอยแลว เราก็เขยี นโปรแกรมเพื่อตรวจสอบวา method ของเราใชง านไดถูกตอ ง
หรอื ไม ดังนี้
1: /**
2: Testing module of polymorphism
3: */
4:
5: import static java.lang.System.out;
6:
7: class TestShapes1 {
8: public static void main(String[] args) {
9: Shapes circle, triangle;
10: Polygons square;
11:
12: //create shapes
13: circle = new Circle("circle", 2.0);
14: triangle = new Triangle("triangle", 3.0, 4.0, 5.0);
15: square = new Square("square", 4.0);
16:
17: out.printf("%s with a perimeter of %.2f%n",
circle, circle.perimeter());
18: out.printf("%s with a perimeter of %.2f%n",
triangle, triangle.perimeter());
19: out.printf("%s with a perimeter of %.2f%n",
square, square.perimeter());
20: }
21: }
ในโปรแกรม TestShapes.java เราประกาศตวั แปร circle และ triangle จาก class Shapes ตัว
แปร square จาก class Polygons สาเหตทุ ี่เราประกาศตวั แปรแทนการสราง object กเ็ พราะวา
Java ไมยอมใหเราทาํ เนอ่ื งจากวา class Shapes และ class Polygons เปน class ทถี่ ูก
กําหนดใหเ ปน abstract class แตเ ราสามารถทจี่ ะใชต ัวแปรท้ังสามในการสราง object
(instantiation) จาก class Circle, class Square และ class Triangle ได
ประโยคในการสรา ง object ทง้ั สาม
circle = new Circle("circle", 2.0);
triangle = new Triangle("triangle", 3.0, 4.0, 5.0);
square = new Square("square", 4.0);
อาจดแู ปลกไปจากการสรา ง object ท่เี ราไดเ คยทาํ มา แตเ ราสามารถทาํ ไดก ็เพราะวา class
Shapes เปน base class ของ class ท้ังหมด สวน class Polygons กเ็ ปน base class ของ
class Square และ class Triangle การสราง object ทั้งสามจึงสามารถทําได พดู งา ย ๆ กค็ ือวา
ทงั้ square, circle และ triangle ตางก็เปน shape
ผลลพั ธท เี่ ราไดจ ากการ run คอื
I am a circle with a perimeter of 12.57
I am a triangle with a perimeter of 12.00
I am a square with a perimeter of 16.00
217
เร่ิมตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
Polymorphism มีประโยชนมากในการกาํ หนดหนาท่ีของ method ที่ object ตา ง ๆ ใชรวมกนั
ซ่งึ หนา ทต่ี าง ๆ เหลานี้จะขึน้ อยกู ับคุณลกั ษณะของ object ท่ีเกดิ จาก class น้ัน ๆ ดังทเี่ ราได
แสดงใหดูในการหาเสน รอบวงของรูปทรงตา ง ๆ หากเราตอ งการเราก็สามารถท่จี ะสราง array
ในการเกบ็ shape ตาง ๆ เหลา นไ้ี ด ดังตวั อยา งที่แสดงใหเหน็ นี้
1: /**
2: Testing module of polymorphism
3: */
4:
5: import static java.lang.System.out;
6:
7: class TestShapes {
8: public static void main(String[] args) {
9: Shapes []shapes = new Shapes[5];
10:
11: //instantiate 5 shapes
12: for(int i = 0; i < shapes.length; i++)
13: shapes[i] = randomShape();
14:
15: //display information about shapes
16: for(int i = 0; i < shapes.length; i++) {
17: out.printf("%s with a perimeter of: %.2f%n",
18: shapes[i], shapes[i].perimeter());
19: }
20: }
21:
22: //create shapes randomly
23: private static Shapes randomShape() {
24: switch((int)(Math.random() * 3)) {
25: default:
26: case 0: return new Circle("circle", Math.random() * 12.0);
27: case 1: return new Square("square", Math.random() * 10.5);
28: case 2: return new Triangle("triangle", 2.5, 4.0, 5.5);
29: }
30: }
31: }
เราเลือกท่ีจะใหก ารสรา งรูปทรงตา ง ๆ เกดิ แบบ random ดังนั้นเราจงึ เขียน method
randomShape() ขึ้นมาใชส ําหรับการสรางรูปทรงท่ไี มม ขี อ กาํ หนดที่ตายตวั รปู ทรงทเ่ี กดิ ขนึ้ จะ
ถูกกาํ หนดโดย method random() ของ class Math
ผลลพั ธท่ไี ดจากการ run คอื
I am a circle with a perimeter of: 12.49
I am a triangle with a perimeter of: 12.00
I am a circle with a perimeter of: 21.66
I am a triangle with a perimeter of: 12.00
I am a triangle with a perimeter of: 12.00
หากเราอยากรูวา object ท่สี รางขึ้นมานนั้ เกดิ จาก class อะไรเราก็สามารถหาไดจ ากการใช
method getClass() และ method getName() ทีม่ อี ยูใน class Class ของ Java เชนถา เรา
ตอ งการรวู า object ท่ี shapes[0] เกบ็ ไวเ กิดมาจาก class อะไรเราก็ใชคําส่ังดังนี้
Class object = shapes[0].getClass();
System.out.println(object.getName());
ถาเราอยากรวู า object ตวั นีม้ ี class แมห รอื ไม เรากใ็ ช method getSuperclass() เชน
Class shape = object.getSuperclass();
System.out.println(shape.getName());
ยงั มี method ใน class Class อกี หลายตวั ท่ีเราสามารถนํามาใชได แตโดยสวนใหญแลว เรา
แทบทจี่ ะไมตอ งใช method เหลา นใ้ี นการพฒั นาโปรแกรมทั่วไปเลย เพราะ method เหลานจ้ี ะ
ใหข อมูลท่ีเก่ียวกับ class ท่ผี ูใช (หรือ ของ Java) สรางข้ึนมาเทานน้ั เอง
218
บทที่ 6: Classes และการถายทอดคุณสมบัติ intro. to Java (FEU.faa)
6.3 method กับความมีรูปแบบท่หี ลากหลาย
โปรแกรมตวั อยา งทจ่ี ะแสดงใหดตู อ ไปอาจดแู ลวแปลก ๆ ทั้งนี้ก็เพราะวา เรากําหนดใหมกี ารสง
object เขา ไปใน method ดวยคณุ สมบตั ิอยา งหนง่ึ แตทาํ การการสง object กลบั ดว ยการ
เปลี่ยนแปลงคณุ สมบัติบางอยา ง เชน สมมติวา เราตองการสราง วงกลมจาก สเี่ หล่ียมดา นเทา ที่มี
อยูแลว เราก็อาจเขียน method ทีท่ าํ หนาทีน่ ใ้ี หเรา ดังนี้
1: /**
2: Passing and returning object to/from method
3: */
4:
5: import static java.lang.System.out;
6:
7: class SquareToCircle {
8: public static void main(String []args) {
9: Shapes square; //a square object
10: Shapes circle; //a circle object
11:
12: //creating a square with side = 3
13: square = new Square("square", 3.0);
14: out.println(square + " with an area of " + square.area());
15:
16: //creating a circle from a square
17: circle = sqToCir(square);
18: out.println(circle + " with an area of " + circle.area());
19: }
20:
21: //method to convert a square to a circle
22: public static Shapes sqToCir(Shapes square) {
23: //finding a radius from an area of a square
24: double SqArea = square.area();
25: double radius = Math.sqrt(SqArea / Math.PI);
26:
27: //instantiating a circle
28: Circle circle = new Circle("circle", radius);
29:
30: return circle;
31: }
32: }
เพือ่ ใหก ารทํางานของเราประสพผลสําเร็จ เราไดเ พมิ่ abstract method area() ใน class
Shapes และทําการกาํ หนดหนา ทขี่ อง method area() ใน class Square และ class Circle ซ่ึง
เปนการคํานวณหาพนื้ ทข่ี องรูปทรงที่ไดถ กู สรา งขน้ึ
ใน class Shapes เรากําหนด ดังน้ี
public abstract class Shapes {
…
…
//code อนื่ ๆ เหมือนเดิม
…
…
public abstract double perimeter();
public abstract double area();
}
การกําหนดให class Shapes เปน abstract class กเ็ พราะวาเราไมต อ งการใหใครสรา ง object
จาก class Shapes เราตอ งการให Shapes เปน เสมือนกบั interface สาํ หรบั class ลูกท่สี รา งมา
จาก Shapes และเราตองการให class ลกู ไดเรียกใช method ที่อยใู น Shapes (perimeter
และ area) ซึง่ ยังมกี ารกําหนดการทาํ งานแตอ ยางใด การกาํ หนดหนา ทกี่ ารทาํ งานของท้งั สอง
method จะกาํ หนดใน class ลกู (Circle และ Square)
ใน class Circle เรากาํ หนด code ของ method area() ดังน้ี
219
เรม่ิ ตน การเขียนโปรแกรมดวย Java intro. to Java (FEU.faa)
//calculate area of this circle
public double area() {
return Math.PI * radius * radius;
}
และใน class Square เรากําหนด code ของ method area() ดงั น้ี
//calculate area of this square
public double area() {
return side * side;
}
ในตวั โปรแกรมของเรา เราสราง object สองตัวคอื square และ circle โดยกาํ หนดให square มี
ความยาวของดา นแตล ะดานเทา กบั 3.0 หลงั จากที่แสดงขอ มูลของ square เรียบรอ ยแลวเราก็
สง square ไปให method sqToCir() ซึ่งเปน method ท่ีทําการเปลี่ยน square ใหเปน circle
โดยกาํ หนดใหท ้งั สอง object มพี ้นื ทเี่ ทากนั
public static Shapes sqToCir(Shapes square) {
//finding a radius from an area of a square
double SqArea = square.area();
double radius = Math.sqrt(SqArea / Math.PI);
//instantiating a circle
Circle circle = new Circle("circle", radius);
return circle;
}
เราเรมิ่ ตน ดวยการหาพน้ื ทขี่ อง square ท่สี ง เขามา หลังจากน้ันเรากห็ ารศั มีของวงกลมท่เี รา
ตองการสรา งจากพนื้ ท่ี ท่หี าได เมอ่ื ไดแลวเราก็สรา ง circle ดวยรศั มนี ้ี เสร็จแลวจงึ สงวงกลมท่ี
ไดน ก้ี ลบั ไป ผูอา นคงจะสงั เกตไดว าเราสามารถสง object จาก class Circle กลับออกไปไดก ็
เพราะวา เราไดป ระกาศให method sqToCir() สง object จาก class Shapes ซ่ึง circle กเ็ ปน
หนึง่ ใน object ทีม่ าจาก class Shapes
ผลลัพธทเี่ ราไดจากการ run โปรแกรมของเราคอื
I am a square with an area of 9.0
I am a circle with an area of 9.0
ขอ ดีของการกําหนดให base class เปน abstract class นัน้ กค็ ือ เราไมตองกําหนดหนา ทขี่ อง
method ใน class แม เพราะวาเราอาจไมรขู อมูลท้ังหมดที่ method ตอ งการใช ดงั เชน method
perimeter() และ method area() เนอ่ื งจากวาเรายงั ไมร ูวา shape ท่ีมอี ยเู ปน object ชนดิ อะไร
ขอมูลเปนอยา งไร แตเรารขู อมลู ทง้ั หมดที่ Circle และ Square ตองการใชในการคาํ นวณหาเสน
รอบวง และพื้นท่ีจาก การสรา ง object ของ class ทัง้ สอง
6.4 การสราง Interface
จากเทคนคิ การใช polymorphism ในตัวอยา งกอ นหนานี้ เราตอ งกาํ หนดใหม ี method ใน class
แม และไปกาํ หนดหนา ทข่ี อง method เหลา นี้ใน class ลกู ซ่ึงเปนการสราง class ในลกั ษณะที่
ซ้าํ ซอนพอสมควร ถาเราตอ งคุณสมบตั ขิ อง polymorphism ใน class ทเี่ กิดจาก class แมนี้ เรา
ก็ไมจําเปนท่ีจะตอ งสรา ง class แมขึน้ มา แตไปสราง interface ข้นึ มาแทน
Interface เปน ทีร่ วบรวมคา คงท่ี และ abstract method ตาง ๆ ทจี่ ะตองมีการเรียกใชใน class
อ่ืน ๆ ทเี่ รยี ก interface น้ไี ปใช การสราง interface ก็ไมย าก แทนทเ่ี ราจะใชค าํ วา class เราก็ใช
คาํ วา interface แทน เราจะใช class ตา ง ๆ ทเี่ ราไดส รา งไวก อ นหนานใี้ นเรื่องของรปู ทรงตาง ๆ
เปนตวั อยาง และเราจะตองทําการเปลย่ี นแปลง class ตาง ๆ ดังน้ี
ใน class Shapes และ class Polygons เราจะตดั เอา abstract method perimeter() และ
area() ออกพรอมกบั เปลีย่ นการประกาศ class Shapes ใหเ ปนดังนี้
220
บทท่ี 6: Classes และการถายทอดคุณสมบัติ intro. to Java (FEU.faa)
public abstract class Shapes implements Calculate {
private String iAm;
Shapes(String whatIam) {
iAm = new String(whatIam);
}
//self info.
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("I am a " + iAm);
return new String(buffer);
}
}
เราเพม่ิ คําวา implements Calculate เขาสดู านหลังสุดของ class Shapes โดยมเี งอ่ื นไขวา เรา
ตอ งมี interface ช่ือ Calculate อยแู ลว การสรา ง interface ก็ทําไดไมย าก เราเพยี งแต
กําหนดให Calculate เปนช่ือของ interface ทเี่ ราตองการใช พรอมทั้งกาํ หนดใหมี method
ตาง ๆ ทเ่ี ราตองการที่จะใหมใี น class อน่ื ๆ เชน
//interface for Shapes
public interface Calculate {
double perimeter();
double area();
}
ในการเขียน Method ที่อยใู น interface นน้ั เราไมจําเปนที่จะตอ งกาํ หนดนโยบายของการเขา หา
การกาํ หนดนโยบายจะตอ งทาํ ใน class ทีเ่ รียกใช (implement) interface นี้
class อ่นื ๆ ทีเ่ หลอื อยกู ็ไมม ีการเปลี่ยนแปลงอะไรมากมาย ยกเวน การคาํ นวณหาพ้ืนท่ีของ
รูปทรงตา งๆ
ใน class Triangle เราเพม่ิ method
//calculating an area of this triangle
//using Huron's formula
public double area() {
double s = perimeter() / 2.0;
double area = Math.sqrt((s * (s-side1) * (s-side2) * (s-side3)));
return area;
}
ใน class Circle เราเพม่ิ method
//calculate area of this circle
public double area() {
return Math.PI * radius * radius;
}
ใน class Square เราเพม่ิ method
//calculate area of this square
public double area() {
return side * side;
}
หลงั จากท่เี ปลี่ยนแปลง code บางสว นในโปรแกรมทดสอบ ดังนี้
1: /**
2: Testing module of polymorphism
3: */
4:
5: import static java.lang.System.out;
6:
7: class TestShapes {
8: public static void main(String[] args) {
221
เร่ิมตนการเขยี นโปรแกรมดว ย Java
9: Shapes []shapes = new Shapes[5]; intro. to Java (FEU.faa)
10: //instantiate 5 shapes
11: for(int i = 0; i < shapes.length; i++)
12: shapes[i] = randomShape();
13:
14: //display information about shapes
for(int i = 0; i < shapes.length; i++) {
15:
16: out.printf("%s with a perimeter of: %.2f",
17: shapes[i], shapes[i].perimeter());
18: out.printf(", an area of %.2f%n", shapes[i].area());
19: }
}
20:
21: //create shapes randomly
22: private static Shapes randomShape() {
23: switch((int)(Math.random() * 3)) {
24: default:
25: case 0: return new Circle("circle", Math.random() * 12.0);
case 1: return new Square("square", Math.random() * 10.5);
26: case 2: return new Triangle("triangle", 2.5, 4.0, 5.5);
27: }
28: }
29:
30:
31:
32: }
ผลลพั ธท ่ีไดค อื
I am a circle with a perimeter of: 66.70, an area of 354.02
I am a triangle with a perimeter of: 12.00, an area of 4.58
I am a square with a perimeter of: 27.19, an area of 46.19
I am a triangle with a perimeter of: 12.00, an area of 4.58
I am a triangle with a perimeter of: 12.00, an area of 4.58
เน่อื งจากวา เราไดท ําการเรียกใช interface Calculate ใน class แม ดังน้นั เราไมจ าํ เปน ที่จะตอ ง
เรียกใช interface Calculate ใน class ลูกเพราะ class ลูกเหลา นี้ไดร บั การถายทอดคณุ สมบัติ
จาก class แมเรยี บรอ ยแลว เหตุผลอกี อยางหนึ่งทเี่ รากาํ หนดให class Shapes มกี าร
implements Calculate ก็คือ เราไมต อ งการเปลยี่ นแปลง code ท่เี ราไดเ ขียนข้นึ กอนหนา น้ี
มากมายนกั
[การใช interface Comparable เพื่อเปรยี บเทียบ object]
หลาย ๆ คร้งั ท่ีเราตอ งการรวู าพนกั ของเราคนไหนมีเงนิ เดือนมากกวาใครเทาไร (นสิ ัยของคน
อยากรู –?) เราสามารถท่ีจะออกแบบให class ของเราทําการ implement interface:
Comparable ซึ่งมีการออกแบบจาก Java ไวดังนี้
public interface Comparable<T> {
int comnpareTo(T obj);
}
เราจะลองออกแบบ class ที่ทําการ override method compareTo() ใหทาํ การเปรียบเทียบคา
เงนิ เดอื นของพนักงานใน class Employee
1: /**
2: comparing objects
3: */
4:
5: class Employees implements Comparable<Employees> {
6: private String name;
7: private double salary;
8:
9: public Employees(String name, double salary) {
10: this.name = name;
11: this.salary = salary;
12: }
13:
14: public String getName() {
15: return name;
16: }
222
บทท่ี 6: Classes และการถา ยทอดคุณสมบตั ิ
17: public double getSalary() { intro. to Java (FEU.faa)
return salary;
18:
19: }
20: public void raiseSalary(double amount) {
21: salary += amount;
22:
}
23:
24: //override compareTo() to compare employees
25: //by salary
public int compareTo(Employees emp) {
26:
27: if(salary < emp.salary)
return -1;
28:
29: if(salary > emp.salary)
30: return 1;
31: return 0;
32: }
33:
34:
35: }
Java 1.5 เราสามารถท่ีจะ override method compareTo() ตามชนิดของ object (หรือขอ มูล)
ท่เี ราตอ งการเปรยี บเทยี บ (generic) โดยเราจะตอ งทําการ implement interface:
Comparable เชน ในบรรทัดที่ 5
5: class Employees implements Comparable<Employees> {
หลงั จากนน้ั เรากท็ าํ การเขียน code สําหรับการเปรยี บเทียบของเราขน้ึ มาใชเ อง ดังท่แี สดงใหดู
ในบรรทัดที่ 28 – 34 ของโปรแกรม Employees.java ซึ่งเมือ่ เราเรยี กใชในโปรแกรม
1: /**
2: Sorting array of Employees
3: */
4:
5: import java.util.Arrays;
6:
7: class TestEmployeesSort {
8: public static void main(String[] args) {
9: Employees[] emp = new Employees[4];
10:
11: emp[0] = new Employees("Kid Walker", 54000);
12: emp[1] = new Employees("Jim Wallace", 44000);
13: emp[2] = new Employees("Peter Tucker", 65000);
14: emp[3] = new Employees("Mike Kawakami", 55000);
15:
16: //sort employees & display
17: Arrays.sort(emp);
18: for(Employees e : emp)
19: System.out.printf("%15s [%.2f]%n",
20: e.getName(), e.getSalary());
21: }
22: }
Method sort() ของ class Arrays ก็จะไปเรยี กใช method compareTo() ทีเ่ ราเขียนข้นึ ใน
class Employee ทําใหก ารจัดเรียงขอ มลู เปน ไปตามเงนิ เดือนของแตละคนจากนอ ยไปหามาก
Jim Wallace [44000.00]
Kid Walker [54000.00]
Mike Kawakami [55000.00]
Peter Tucker [65000.00]
6.4.1 การถา ยทอดคณุ สมบตั ิจากหลายแหลง (Multiple Inheritance)
เราสามารถท่ีจะเขยี นโปรแกรมใหมกี ารรบั การถา ยทอดคณุ สมบตั ิจากหลาย ๆ ทไ่ี ด เชน เราอาจ
ตอ งการบอกใหร วู า "object X เปน Y และเปน Z และเปน W" ซง่ึ ในการท่ีจะไดมาซึง่ การ
ถายทอดแบบนเี้ ราตอ งใช interface หลายตวั เขา มาชวย แตเ ราสามารถมี class (concrete
class) ไดเพียง class เดยี ว ดงั ตัวอยางที่เราจะแสดงใหด ูตอ ไปนี้
223
เริม่ ตนการเขยี นโปรแกรมดวย Java intro. to Java (FEU.faa)
interface CanBark {
void bark();
}
interface CanFetch {
void fetch();
}
interface CanSwim {
void swim();
}
1: /**
2: Base class
3: */
4:
5: class Dog {
6: private String name;
7:
8: public Dog(String name) {
9: this.name = new String(name);
10: }
11:
12: //name of this dog
13: public String getName() {
14: return name;
15: }
16:
17: //this dog is barking
18: public void bark() {
19: System.out.println("Woof Woof");
20: }
21: }
เราตองการที่จะสราง class ท่ีไดร ับการถา ยทอดจาก interface CanBark, CanFetch,
CanSwim และจาก class Dog ซึง่ เราอาจออกแบบ class ทว่ี าดงั น้ี
1: /**
2: Class MyDog
3: Gain multiple inheritances from interfaces
4: CanBark, CanFetch, and CanSwim as well as class Dog
5: */
6:
7: import static java.lang.System.out;
8:
9: class MyDog extends Dog
10: implements CanBark, CanFetch, CanSwim {
11:
12: //give this dog a name
13: public MyDog(String name) {
14: super(name);
15: }
16:
17: //this dog is swiming
18: public void swim() {
19: out.printf("%s is swiming.%n", super.getName());
20: }
21:
22: //this dog is fetching
23: public void fetch() {
24: out.printf("%s is fetching.%n", super.getName());
25: }
26: }
ผอู านจะสังเกตวา เราทําการถา ยทอดโดยตรงจาก class Dog ดวยการใชคําสง่ั extends และ
เรียกใช interface ท้ังสามดวยคําสง่ั implements โดยเราไดก ําหนดใหมี method bark() ใน
class Dog แตเ ราจะ implement method swim() และ fetch() ใน class MyDog
สวนโปรแกรมทดสอบของเรามดี งั นี้
224
บทที่ 6: Classes และการถา ยทอดคุณสมบตั ิ intro. to Java (FEU.faa)
1: /**
2: Testing multiple inheritance
3: */
4:
5: class MultipleInheritance {
6: public static void main(String[] args) {
7: MyDog red = new MyDog("Red");
8:
9: act1(red); //treat as CanBark
10: act2(red); //treat as CanFetch
11: act3(red); //treat as CanSwim
12: act4(red); //treat as MyDog
13: }
14:
15: public static void act1(CanBark d) {
16: d.bark();
17: }
18:
19: public static void act2(CanFetch d) {
20: d.fetch();
21: }
22:
23: public static void act3(CanSwim d) {
24: d.swim();
25: }
26:
27: public static void act4(Dog d) {
28: d.bark();
29: }
30: }
ผลลัพธท ีเ่ ราไดจ ากการ run คือ
Woof Woof
Red is fetching.
Red is swiming.
Woof Woof
จะเห็นวาผลลพั ธทีไ่ ดเ ปน ไปตามท่เี ราไดคาดหวังไว การใช interface เขามาชว ยเรอ่ื งของการ
ถายทอดคุณสมบตั ิทาํ ใหการเขียน code ของเรางา ยขน้ึ
6.5 การใช interface ActionListener ของ Java
เรามาลองดูตวั อยา งของการใช interface ที่ Java มใี หอีกสกั ตวั อยางหนงึ่ โดยเราจะเรยี กใช
interface ActionListener ในการตรวจจับเหตุการณท่ีจะเกิดขึ้นจากตวั โปรแกรม ตวั อยา งน้ีอาจมี
ขอ มลู ท่เี รายังไมไ ดพ ูดถงึ มากพอสมควร แตป ระเดน็ หลกั ทีต่ อ งการแสดงกค็ ือการเรียกใช
interface เราจะปรบั ปรุงโปรแกรม Interests.java ที่เราไดเ ขยี นขึ้นในบททส่ี าม ซง่ึ เปน
โปรแกรมสาํ หรับการคํานวณหาดอกเบ้ยี ทบตน เราจะสรา ง class ข้นึ ใหมดงั นี้
class Account ใชเปนตวั เกบ็ ยอดเงิน (balance) คํานวณดอกเบ้ยี แสดงผล class นเี้ รยี กใช
interface BankRate
class Timer เปน class ทมี่ ีอยใู น Java ใชส ําหรบั การกระทําท่ีตองใชเวลา
class Interests1 เปน โปรแกรมทดสอบสว นตาง ๆ ท่ีเราสรางข้ึน
interface BankRate ใชเ กบ็ คาคงที่ RATE ท่ีใชในการคาํ นวณหาดอกเบี้ย
interface ActionListener ใชในการตรวจสอบเหตกุ ารณท เ่ี กดิ จากผใู ชโ ปรแกรม เชน ออกจาก
โปรแกรม
เรากาํ หนดใหค วามสัมพันธข อง class เปนไปตาม diagram ท่เี ห็นนี้
225
เริม่ ตน การเขยี นโปรแกรมดวย Java
Account GetInterest intro. to Java (FEU.faa)
BankRate ActionListener
interface Timer
ภาพที่ 6 – 2 การเรยี กใช interface
เราเริ่มตน ดว ย interface BankRate และ class Account
1: /**
2: interface for bank rate
3: */
4:
5: public interface BankRate {
6: double RATE = 5.0;
7: }
1: /**
2: Class Account using interface BankRate
3: */
4:
5: public class Account implements BankRate {
6: private double balance;
7:
8: //constructor - initializing balance
9: Account(double balance) {
10: this.balance = balance;
11: }
12:
13: //method to get balance
14: protected double getBalance() {
15: return balance;
16: }
17:
18: //method to to deposit
19: protected void deposit(double amount) {
20: balance += amount;
21: }
22:
23: //method to calculate interest
24: protected double interest() {
25: return balance * RATE / 100.0;
26: }
27:
28: //method to display info. about this account
29: public String toString() {
30: return String.format("Balance: %.2f [interest: %.2f]",
31: balance, interest());
32: }
33: }
เราเขยี น class Account อยางงา ย ๆ โดยกําหนดใหมี method สาํ หรับการกําหนด balance
การคาํ นวณหาดอกเบ้ยี และการแสดงผลผานทาง method toString() ตอไปเราจะมาดู class
Interests1 ซง่ึ เปน โปรแกรมทดสอบการใชงานของ class และ interface
1: /**
2: Interests1.java
3: */
4:
5: import java.awt.event.ActionEvent;
6: import java.awt.event.ActionListener;
226
บทท่ี 6: Classes และการถา ยทอดคุณสมบตั ิ intro. to Java (FEU.faa)
7: import javax.swing.JOptionPane;
8: import javax.swing.Timer;
9:
10: class Interests1 {
11: public static void main(String[] args) {
12: //create account with initial balance of 1000
13: final Account acc = new Account(1000);
14:
15: //inner class performing interest calculation
16: //and listening to event from user
17: //stop performing when user hit stop button in
18: //the dialog window
19: class GetInterest implements ActionListener {
20: public void actionPerformed(ActionEvent event) {
21: System.out.println(acc);
22: double ints = acc.interest();
23: acc.deposit(ints);
24: }
25: }
26:
27: //create object from class GetInterest
28: GetInterest intsPeek = new GetInterest();
29: //set performing time interval to one second
30: final int DELAY = 1000;
31: //calling actionPerformed() every 1000 milliseconds
32: Timer t = new Timer(DELAY, intsPeek);
33: //start the timer
34: t.start();
35:
36: //display dialog window - stop performing and exit
37: //program when user hit the button
38: JOptionPane.showMessageDialog(null, "Stop?");
39: System.exit(0);
40: }
41: }
ในโปรแกรม Interests1.java เราสราง object acc จาก class Account ดว ยคา balance เรมิ่ ตน
ท่ี 1000 ภายใน method main() เราสราง class GetInterest ที่เรยี กใช interface
ActionListener ของ Java ซงึ่ จะคอยตรวจสอบเหตุการณ (event) ท่ีอาจเกดิ ข้นึ จาก user
พรอ มทงั้ การคํานวณหาดอกเบ้ยี
method actionPerformed() จะถกู เรียกโดย object intsPeek จาก class Timer ดว ยคา delay
1 วินาที ดว ยประโยคน้ี
Timer t = new Timer(DELAY, intsPeek);
แตกระบวนการทัง้ หมดจะเริม่ ไดดว ยการเรยี ก method start() ของ class Timer ดงั นี้ t.start()
โปรแกรมของเราจะคํานวณหาดอกเบย้ี ไปจนกวา user จะกดปมุ OK ทีแ่ สดงไวใ น dialog
window ที่ปรากฏอยใู นหนา จอ ซงึ่ dialog window นถี้ ูกสรางข้ึนมาดวยคาํ สง่ั
JOptionPane.showMessageDialog(null, "Stop?");
ซงึ่ มหี นา ตาดงั น้ี
เมอ่ื user กดปมุ OK เราก็จะยุตโิ ปรแกรม และออกจากระบบดว ยคําสั่ง System.exit(0);
227
เร่ิมตน การเขยี นโปรแกรมดวย Java
ตวั อยางผลลพั ธท่ไี ดจากการ run โปรแกรมในชวงเวลาหนงึ่ กอนการกดปมุ คือ
Balance: 1000.00 [interest: 50.00] intro. to Java (FEU.faa)
Balance: 1050.00 [interest: 52.50]
Balance: 1102.50 [interest: 55.13]
Balance: 1157.63 [interest: 57.88]
Balance: 1215.51 [interest: 60.78]
Balance: 1276.28 [interest: 63.81]
Balance: 1340.10 [interest: 67.00]
เราตองการที่จะแสดงใหเหน็ ถึงการใช interface ท้งั ที่มอี ยูใ น Java และทเ่ี ขียนขนึ้ เอง สว นการ
ใชสว นประกอบอื่น ๆ ท่ี Java มใี หเปนเพยี งส่ิงที่ผูอ า นจะไดส มั ผัสในโอกาสตอไป
เรามีทางเลือกสองทางในการสราง และกาํ หนดหนาทขี่ อง method ดงั ที่เราไดพ ูดไว คอื
1. กําหนดให class แมเปน abstract class พรอมทง้ั กาํ หนดใหมี ชือ่ ของ method ท่ีตองการ
การกําหนดหนา ทขี่ อง method จะเปนภาระของ class ลกู เอง
2. กาํ หนดให class เรยี กใช interface ทีม่ ีการกาํ หนดช่อื ของ method และ class ตอ งกาํ หนด
หนาทข่ี อง method นัน้ เอง
สรุป
เราไดพ ูดถึงการสรา ง class ใหมจ าก class ท่ีมีอยกู อ นแลว การถา ยทอดคณุ สมบัตจิ าก class
แมสู class ลูก การ override method การใช polymorphism การสรา งและใช interface โดย
สรปุ แลวสงิ่ สําคัญท่ีเราไดพ ดู ไวคือ
9 เราสามารถสราง class ใหมจ าก class ท่มี อี ยูกอ นแลวดว ยการใชคําวา extends ซึง่ class
ทเี่ รา extends มาน้นั เราเรียกวา base class หรือ parent สว น class ทีเ่ ราสรางขึน้ ใหมเรา
เรยี กวา sub class หรือ child
9 เราสรา ง abstract class ดวยการใชคําวา abstract ซ่งึ ภายใน class ท่ีเปน abstract class
นั้นจะมี method ประกาศอยู แตหนาท่ีของ method ยังไมไ ดถูกกําหนด การกําหนดจะทํา
ใน class ลูกเดทา นน้ั และเราไมส ามารถที่จะสราง object จาก abstract class ได
9 sub class ไมไ ดร บั การถา ยทอด constructor ของ super class
9 ถา เรากาํ หนดนโยบายการเขาหาของ method หรอื ตวั แปรใหเปน private ใน class แม
class ลกู จะไมสามารถเขาหาตวั แปร หรือ method ได
9 ตวั แปรทีป่ ระกาศจาก class แมส ามารถท่ีจะใชเ ปนตวั ชี้ไปยงั object ของ class ลูกได ซ่งึ
ทาํ ใหก ารเรยี กใช method ที่อยูใ น class ลกู เปนไปได
9 abstract class เปน class ท่ไี มตองกําหนดหนาท่ใี ห method ทกุ ๆ ตัวใน class
9 interface ประกอบไปดว ย คาคงที่ abstract method และ inner class
9 class ทีไ่ มกําหนดหนาท่ใี หกบั method ทกุ ตวั ทต่ี ัวมันเองตอ งใช interface จะตองประกาศ
ใหเ ปน abstract class
แบบฝก หัด
1. จากขอ มลู ที่ใหเปนคูใ นแตล ะขอ จงแสดงถึงความสัมพนั ธว าสว นไหนเปน super class และ
สว นไหนเปน sub class
ผจู ัดการ ลูกจา ง
นกั ศึกษา อาจารย
คน นกั ศึกษา
อาจารย บคุ ลากร
สามี ภรรยา
พอ ลูก
2. สมมตวิ า class RumRaisin extends มาจาก class Icecream จงหาวาประโยคใดตอไปน้ี
เปนประโยคที่ Java ยอมรบั
RumRaisin scoop1 = new RumRaisin();
228
บทท่ี 6: Classes และการถา ยทอดคุณสมบตั ิ intro. to Java (FEU.faa)
Icecream scoop2 = new Icecream;
scoop2 = scoop1;
scoop1 = scoop2;
scoop2 = new RumRaisin();
scoop1 = new Icecream();
3. จงวาด diagram ที่แสดงถึงความสมั พนั ธข องการถายทอดคุณสมบตั ขิ อง class ทใ่ี หน ี้
บคุ ลากร
ผูจดั การ
นักศึกษา
อาจารย
หองเรียน
อปุ กรณป ระกอยการเรยี น
รองอธกิ ารฝา ยวิชาการ
รองอธิการฝา ยบรหิ าร
บรรณารกั ษ
เจา หนา ทก่ี ารเงนิ
หวั หนา ฝา ยการเงิน
4. เราไดพดู ถึงการใช method clone() ในบทท่ีเราพดู ถึงเร่ือง array จง override method
clone() เพอื่ ทําการสราง object ใหมจาก class Shapes ท่ีไดก ลา วไวใ นบทนี้
5. จงเพ่มิ method withdraw() ทท่ี ําหนา ท่ใี นการถอนเงนิ ออกจากบัญชี ของ class Account
ที่ไดกลา วไวใ นบทนี้ ใหเขียนโปรแกรมทดสอบ
6. จาก class Shapes ในบทนี้ class ที่ไมไ ดพดู ถึงและไมมกี ารกาํ หนดหนา ทใี่ ด ๆ เลย คอื
class Rectangle จงเขยี น code ทท่ี าํ ให class Rectangle น้ีสมบรูณ
7. จงออกแบบ class Student ท่เี กบ็ ขอ มลู ของนกั ศกึ ษาวิทยาลัยแหงหน่ึง โดยใหมี sub
class ทม่ี ีทั้งนักศึกษาระดับปริญญาตรี และระดับปรญิ ญาโท รวมไปถึงนกั ศึกษาภาคพเิ ศษ
พรอมทงั้ เขียน method ในการกําหนด และเขา หาขอ มูลเหลา นี้ กาํ หนดใหม ี method
toString() ในทุก class สาํ หรบั การแสดงขอมลู ของ object ท่ีเกิดจาก class น้ัน ๆ ใหเ ขียน
โปรแกรมทดสอบ
8. จงออกแบบ class Employee ทมี่ ี sub class เปน TempEmployee และ
RegularEmployee โดยกาํ หนดใหลูกจา งทกุ คนมี ชือ่ และอัตราจางงานที่คิดเปน จํานวน
บาท ตอช่วั โมง จงเขยี น method ท่ที าํ การคาํ นวณหาคาจา งของลูกจา งทุกคน โดย
กําหนดใหก ารคิดคา จา งของ TempEmployee ข้ึนอยกู บั จํานวนช่วั โมงทท่ี ํา หากทําเกนิ 40
ชว่ั โมงใหคดิ คา จา งเพมิ่ เปน หนงึ่ เทา ครึ่งของอตั ราจา งประจํา ของจํานวนชั่วโมงทีท่ าํ เกิน
สว นลูกจา งประจาํ (RegularEmployee) จะไดค า จา งตามอตั ราทไ่ี ดตกลงไวลวงหนาโดยไม
คํานงึ ถงึ จาํ นวนชว่ั โมงของงานทที่ ํา จงใชเทคนิคของ polymorphism ในการออกแบบ ให
เขยี นโปรแกรมทดสอบ
* class Employee ควรเปน abstract class
9. จงปรบั ปรงุ class Shapes หรือ sub class ท่มี าจาก Shapes ใหม ี method ในการสรา ง
object จาก class หน่ึงใหเ ปน object จากอีก class หน่ึง ดังเชนทที่ ําเปนตัวอยา งในการ
สรา ง object Circle จาก Square จงเขยี นโปรแกรมทดสอบ
10. จงเขียน method ทหี่ าคา ทมี่ ากที่สุดของ object ทม่ี ีอยใู น array โดยกําหนดให method
มชี ือ่ และ parameter ดังน้ี
public static max(Object[] thisObject)
การเปรยี บเทียบ object ทาํ ไดด ว ยการเรยี กใช method compareTo()
229
เริม่ ตน การเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
ใหเขยี นโปรแกรมทดสอบดว ยการสราง array ทีเ่ ก็บ String, array ที่เก็บ Integers, และ
array ทเี่ ก็บวนั ท่ีเกดิ จาก class Date (ดขู อ มลู ของ class Date จาก Java API)
11. จงเขียน class Circle ใหมที่มีความสามารถในการเปรียบเทียบวงกลมสองวงวาเทา กนั
หรือไมด วยการใช interface Comparable และใหทําการ override method equals()
สาํ หรบั การเปรียบเทียบนั้น
230
ในบทท่ีเจด็ น้เี ราจะพูดถึงการใช และการออกแบบ exception หรอื ที่เรยี กวา การควบคมุ และดกั intro. to Java (FEU.faa)
จบั error ท่ีอาจเกดิ ขึ้นในการ compile และ run โปรแกรม
หลังจากจบบทนแ้ี ลว ผูอา นจะไดทราบถึง
o ความหมายของ exception
o วิธกี ารใชแ ละควบคุม exception
o การใช throws และ try
o การออกแบบ และใช exception ทีเ่ ขยี นขน้ึ เอง
o การใช assertion
7.1การตรวจสอบ error
ในภาษา Java น้นั exception เปน การบอกถึงส่งิ ผดิ ปรกติท่เี กดิ ขนึ้ ในโปรแกรม ซ่ึงอาจเปน
error หรือเหตุการณท่ไี มค อยเขาทาทต่ี อ งการความดูแลเปน พเิ ศษ โดยทัว่ ไปในการเขียน
โปรแกรมทด่ี ีนน้ั เราจะตอ งตรวจสอบถึงเหตกุ ารณทีอ่ าจทาํ ใหโปรแกรมของเราลมเหลวในการ
ทาํ งาน เชน ขอมูลถกู หารดว ยศูนย เขาหาขอมลู ใน array ดว ยการใช index ท่ีไมม ีอยจู ริง หรอื
อา งถึงหนวยความจําท่เี ปน null เปนตน
ถึงแมวาเรามีวิธีการตรวจสอบ error ตาง ๆ เหลา นดี้ ว ยการใช if-else หรือ การตรวจสอบอื่น ๆ ท่ี
ทาํ ใหโปรแกรมของเราทาํ งานไดร าบร่นื แตจะทาํ ให code ของเราดูแลววนุ วายเพราะถามกี าร
ตรวจสอบ error มาก code ของเราก็จะดูซบั ซอนมากย่งิ ขึ้น แตไมไ ดห มายความวา เราจะไม
ตรวจสอบ และดกั จบั error เหลา น้ี การนาํ เอา exception เขา มาเปนตัวชวยในการตรวจสอบ
และดักจับ ทาํ ใหเกดิ การแยกสวนของ code ทท่ี ํางานไดราบร่ืน ออกจากสวนของ code ท่ี
จัดการเกยี่ วกับ error ทาํ ใหเราสามารถท่จี ะคนหาสว นของ code ทง้ั สองไดงายขึ้น ถา มีการ
เปลย่ี นแปลง code ในอนาคต ขอดีอีกอันหนึง่ ของ exception กค็ ือ ทําใหก ารตรวจสอบและดัก
จับเปนไปอยางเฉพาะเจาะจง ตรงกับ error ทีเ่ กิดขนึ้ ทําใหการแกไ ขเปน ไปอยา งถกู ตอง และ
เน่อื งจากวา error มหี ลากหลายรูปแบบ เราตองเขยี น code ขึ้นมารองรับไมเ ชน นน้ั แลว
โปรแกรมของเราก็จะไมผา นการ compile
เราไมจําเปน ท่ีจะตอ งใช exception ในการตรวจสอบและดกั จบั error ในโปรแกรมเสมอไป
เพราะการใช exception จะเสียคา ใชจายในการประมวลผลมาก ทําใหโปรแกรมทาํ งานชา ลง
ดังน้ันเราจะตอ งตดั สนิ ใจใหดีวา ควรจะใช exception ในกรณีไหน อยางไร ตัวอยางของ
โปรแกรมท่ไี มตองใช exception กน็ าจะเปนการใสขอ มลู นาํ เขา แบบผดิ ๆ ของ user ซง่ึ ถอื เปน
เรื่องปกติ ถา เรามัวแตเ สยี เวลาในการดักจับดวยการใช exception แทนการตรวจสอบและดักจบั
ท่ัวไปโปรแกรมของเราก็จะเสยี เวลาในการประมวลผลสว นอื่น ๆ ไป
การใช exception ใน Java น้นั จะโดยทั่วไปจะเปน การโยน (throw) การจัดการ error ทีเ่ กดิ ขึน้
ใหกับ สวนของ code ทท่ี าํ หนา ท่ีในดา นการจัดการกับ error นัน้ ๆ ทีเ่ กิดขึ้น ซง่ึ code สวนนี้จะ
คอยดกั จบั (catch) ถามกี ารโยนเกดิ ขนึ้ แตไ มจาํ เปนท่ี code สวนนีจ้ ะตองแกไข error ท่ีเกดิ ขึ้น
อาจเปน เพยี งการดักจบั เทาน้ัน เพื่อใหโปรแกรมทํางานตอ ไปไดเ ทา นนั้
เราคงไมพ ูดถึงขอมูลตา ง ๆ ทีเ่ กี่ยวกับ error และ exception มากนกั แตจะเนนการใช
exception ในการตรวจสอบและดกั จบั error แบบพอประมาณ ผูทีส่ นใจก็สามารถทจ่ี ะหาอานได
จากหนงั สือ Java ทั่ว ๆ ไป หรอื ใน web sit ของ Java เอง
เร่มิ ตนการเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
Exception โดยปกติจะเปน object จาก sub class (class ใด class หนึง่ ) ของ class
Throwable ท่ี Java มีให และ class หลัก ๆ สอง class ทเี่ กิดจาก class Throwable โดยตรงที่
เปน class หลกั ของ class ท่ีเปน class เฉพาะของการจดั การกบั error คอื class Error และ
class Exception (ภาพท่ี 7 - 1)
Throwable
Error Exception
Other sub classes Other sub classes
ภาพท่ี 7-1 Class Throwable และ sub classes
โดยการออกแบบของ Java เราไมค วรทจ่ี ะ catch error ท่เี กิดขนึ้ จากการตรวจสอบของ class
Error เพราะ error ทเี่ กดิ ข้นึ จะเปน error ที่ โดยทวั่ ไปจะไมเกิดขนึ้ (หรือไมคาดวา จะเกิด) ซ่ึงมี
อยูสาม class คือ ThreadDeath LinkageError และ VirtualMachineError เราคงจะไมเขาไป
วนุ วายกบั class ทง้ั สามเพราะวา เราไมส ามารถที่จะแกไ ข error ทีเ่ กิดขนึ้ น้ีไดโดยตรง และตอ ง
ใชการตรวจสอบอยางละเอียดกบั error ท่เี กิดขึ้น (แตค งตองหวงั ในใจวา error ทว่ี า คงไมเ กดิ
ขน้ึ กบั เรา)
[การ throw exception]
เราจะมาดตู วั อยางการใช exception ในการจัดการกับ error ท่เี กดิ ขึ้นในโปรแกรมของเรา ดวย
โปรแกรมตัวอยางตอ ไปนี้
1: /**
2: Throwing exception when divided by zero
3: */
4:
5: import static java.lang.System.out;
6:
7: class ThrowException {
8: public static void main(String[] args) throws Exception {
9: int number = 10;
10: int divider = 0;
11:
12: out.printf("Divide %d by %d%n", number, divider);
13: int result = number / divider;
14: out.printf("Result is %d%n", result);
15: }
16: }
โปรแกรมตวั อยางดานบนนท้ี ําการ throw exception ซ่ึงเปน exception ทีเ่ กดิ ขึ้นในขณะท่ี
โปรแกรมกาํ ลงั ไดรบั การประมวลผล (เชน การหารตวั เลขทีเ่ ปน int ดว ย 0 – เราตงั้ ใจให error
น้เี กิดขน้ึ ) โปรแกรมตัวอยา งของเราไมไดท าํ การดักจับใด ๆ ทําแตเฉพาะการตรวจสอบ error ท่ี
เกิดขึ้นเทานั้น ดังที่เห็นจากผลลัพธของการ run นี้
Divide 10 by 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ThrowException.main(ThrowException.java:13)
232
บทท่ี 7: การตรวจสอบและดักจบั Error (Exceptions) intro. to Java (FEU.faa)
จะเห็นวา Java จะฟอ งใหเรารูวา error ทเ่ี กิดข้นึ เปน error ชนดิ ไหน (ArithmeticException) ที่
พยายามหาร int ดวย 0 พรอมกบั บอกวา เกดิ ขึน้ ในบรรทัดท่ีเทา ไร หลงั จากน้นั ก็ยุติการทาํ งาน
[การ catch exception]
ถาหากวา เราตอ งการท่ีจะแกไ ข หรอื ทําการใด ๆ สักอยา งหน่ึงกับ error ท่ีเกดิ ขน้ึ เราตอ งใช try
และ catch ดงั ตัวอยา งตอไปน้ี
1: /**
2: Manipulate error with try and catch
3: */
4:
5: import static java.lang.System.out;
6:
7: class TryAndCatchExample1 {
8: public static void main(String[] args) {
9: int number1 = 15;
10: int number2 = 0;
11:
12: try {
13: out.println("Division by zero in a try block.");
14: int result = number1 / number2;
15: //line below won't get executed
16: out.println("Leaving a try block.");
17: }
18: catch(ArithmeticException ex) {
19: out.println("Exception caught in a catch block.");
20: }
21:
22: out.println("After a try block.");
23: }
24: }
โปรแกรม TryAndCatchExample1.java เปน โปรแกรมตัวอยา งการใช try และ catch ในการ
จัดการกบั การหาร int ดว ย 0 (เราจะไมใชการ throws exception เหมอื นกับตวั อยา งแรก) เรา
กาํ หนดให number1 มคี า เปน 15 และ number2 มคี าเปน 0 พรอมทั้งกําหนดให
result = number1 / number2;
ใน block ของ try ซ่ึงประโยคดงั กลา วจะทาํ ใหเ กิดการโยน exception ไปยัง block ของ catch
และใน block ของ catch เราจะดกั ดวย exception ทช่ี ื่อ ArithmaticException เราไมไ ดทํา
อะไรมากมายไปกวา การแสดงขอ ความวามกี ารดักจบั error ผลลพั ธทไ่ี ดจากการ run คอื
Division by zero in a try block.
Exception caught in a catch block.
After a try block.
จากผลลัพธทไี่ ด code ที่ไดรบั การประมวลผลคอื ประโยคที่อยใู น block ของ try 2 ประโยคแรก
โดยเฉพาะประโยคทสี่ อง ที่ทําใหการประมวลกระโดดไปยัง block ของ catch ทําใหป ระโยคที่
สาม (บรรทัดที่ 16) ไมไดรบั การประมวลผล และหลังจากทปี่ ระมวลผลประโยคท่ีอยใู น block
ของ catch แลว การประมวลผลประโยคสดุ ทายทีต่ ามหลัง block ของ catch จงึ เกดิ ขึน้
เราสามารถใช ตัวแปร ex ท่ีเราไดประกาศใน parameter list ของ method catch() แสดงถึง
ขอ ความที่บง บอกเกีย่ วกับ error ทเ่ี กดิ ขึ้น ดว ยการเพ่มิ ประโยคตอ ไปนีใ้ น block ของ catch
out.println(ex.getMessage());
ex.printStackTrace();
ประโยคแรกเรียกใช method getMessage() ท่ีเกดิ ขึ้นทําการแสดงผลไปยังหนา จอ สว น
ประโยคทีส่ องเปน การตรวจสอบถึงท่มี าของ error ท่ีเกิดข้ึน ดงั ท่ีแสดงใหเ หน็ จากการ run
โปรแกรมอกี ครั้งหลงั จากการเปล่ยี นแปลง code ใน block ของ catch
Division by zero in a try block.
Exception caught in a catch block.
/ by zero
233
เรม่ิ ตน การเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
java.lang.ArithmeticException: / by zero
at TryAndCatchExample1.main(TryAndCatchExample1.java:14)
After a try block.
เราไมจ าํ เปนที่จะตองแสดงผลทเี่ กดิ ขึน้ ไปยังหนาจอ สวนใหญแลวขอมลู เหลาน้จี ะเปนประโยชน
ตอการตรวจสอบถึง error ทีเ่ กิดขึ้นเทานัน้ เอง ส่งิ ท่สี าํ คัญท่ีเราตอ งกังวลก็คือ การตรวจสอบและ
ดักจับ error ทอี่ าจเกดิ ขนึ้
Java กาํ หนดให try และ catch เปนของคกู นั เราไมส ามารถทจี่ ะแยก block สองออกจากกันได
ถาเรากาํ หนดใหมีประโยคอะไรกไ็ ดสักประโยคหนง่ึ ระหวา ง block ของ try และ catch โปรแกรม
ของเราจะ compile ไมผ าน ดังตวั อยา งท่ีมกี ารเพิ่มประโยคระหวา ง block ท้ังสองนี้
…
…
out.println("Leaving a try block.");
}
out.pritnln("In between try and catch blocks.");
catch(ArithmeticException ex) {
…
…
ถาเรา compile เราจะได error ดงั ทเ่ี หน็ น้ี
TryAndCatchExample1.java:9: 'try' without 'catch' or 'finally'
try {
^
TryAndCatchExample1.java:15: 'catch' without 'try'
catch(ArithmeticException ex) {
^
2 errors
ตัวอยา งการใช try และ catch ที่ classic อกี อนั หน่งึ กค็ ือ การใช try และ catch ใน loop ดงั
ตัวอยางตอ ไปน้ี
1: /**
2: Using try and catch in a loop
3: */
4:
5: import static java.lang.System.out;
6:
7: class TryAndCatchExample2 {
8: public static void main(String[] args) {
9: int number = 10;
10:
11: for(int index = 5; index >= -1; index--)
12: try {
13: out.printf("try block: index = %d%n", index);
14: int result = number / index;
15: out.println("Leaving a try block.");
16: }
17: catch(ArithmeticException e) {
18: out.println("Exception caught in catch block.");
19: out.println(e.getMessage());
20: e.printStackTrace();
21: }
22:
23: out.println("After a try and catch blocks.");
24: }
25: }
กอนทจี่ ะอธิบายถงึ การทาํ งานของตัวโปรแกรม เรามาดผู ลลพั ธท ีไ่ ดจ ากการ run
try block: index = 5
Leaving a try block.
try block: index = 4
Leaving a try block.
try block: index = 3
Leaving a try block.
234
บทท่ี 7: การตรวจสอบและดกั จบั Error (Exceptions) intro. to Java (FEU.faa)
try block: index = 2
Leaving a try block.
try block: index = 1
Leaving a try block.
try block: index = 0
Exception caught in a catch block.
/ by zero
java.lang.ArithmeticException: / by zero
at TryAndCatchExample2.main(TryAndCatchExample2.java:14)
try block: index = -1
Leaving a try block.
After a try and catch blocks.
ประโยคใน block ของ try จะถูกประมวลผลจนกวา คา ของ index จะเปน 0 จึงจะกระโดดไป
ประมวลผลประโยคท่ีอยูใ น block ของ catch หลังจากนัน้ ก็กลับไปประมวลผลประโยคท่ี
เหลอื อยใู น block ของ try และประโยคทีอ่ ยูทา ยสุดในโปรแกรม อกี ประโยคหน่ึง
จะเหน็ ไดว า เรามีทางเลือกอยูสองทางในการจัดการกบั error ทางแรกคอื ยตุ ิการทํางาน
(terminate) ของโปรแกรม หรอื code สว นนั้น ๆ ท่ีทําใหเ กิด error หรือ ทางที่สอง ซึ่งเปน
ทางเลือกทีท่ าํ ใหโปรแกรม หรือ code สวนนัน้ ๆ กลบั ไปรับการประมวลผลใหม (resumption)
ท้งั สองวธิ เี ปนการตรวจสอบและดักจับ error ทดี่ พี อกนั ทั้งน้ีก็ข้นึ อยูก ับลักษณะของงานท่ีทาํ อยู
ลองมาดูตวั อยา งอีกสกั ตัวหนึง่ ในการใช class NumberFormatException ในการดักจบั error
1: /**
2: Using NumberFormatException
3: */
4:
5: import static java.lang.System.out;
6:
7: class NumFormatException {
8: public static void main(String[] args) {
9: int number, sum = 0;
10:
11: for(int i = 0; i < args.length; i++) {
12: try {
13: number = Integer.parseInt(args[i]);
14: sum += number;
15: }
16: //ignore input that's not a number
17: catch(NumberFormatException e) {
18: e.printStackTrace(System.out);
19: }
20: }
21: out.printf("Sum is %d%n", sum);
22: }
23: }
เรากําหนดใหโปรแกรมของเรารบั ขอมลู จาก command line argument ซง่ึ เปน วธิ กี ารทยี่ อมให
ผูใชใสขอมูลตามหลงั ชื่อของโปรแกรม (ดูจากผลลัพธก าร run) เราจะทําการหาผลรวมของ
ตวั เลขเหลา นนั้ ท้ังหมดจนกวาผใู ชจะพอใจ คือ กดปมุ <enter> หลังจากใสขอความจนพอใจ
ใน catch block เราดกั จับดว ย NumberFormatException ซงึ่ จะไมย อมรบั ขอมูลนําเขาทีไ่ มใช
ตัวเลขทีเ่ ปน int และทุกครั้งท่ีเจอขอมลู แบบนโี้ ปรแกรมจะสงรายละเอียดไปใหผใู ช และจะหา
ผลรวมของขอมูลทถี่ ูกตอ งนัน้ ดงั ท่ีแสดงไวดา นลางน้ี
D:\>java NumFormatException
123r 56ty
java.lang.NumberFormatException: For input string: "r"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at NumFormatException.main(NumFormatException.java:13)
java.lang.NumberFormatException: For input string: "t"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at NumFormatException.main(NumFormatException.java:13)
java.lang.NumberFormatException: For input string: "y"
at java.lang.NumberFormatException.forInputString(Unknown Source)
235
เร่มิ ตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at NumFormatException.main(NumFormatException.java:13)
Sum is 17
ในการสราง block สาํ หรบั การ catch error ทีเ่ กดิ ขนึ้ เราไมจาํ เปน ท่ีจะตองมี catch block เพียง
block เดียว เราอาจมีมากกวา หนง่ึ catch block ไดแตมีขอแมวา การ catch exception ตอ งทาํ
จาก sub class ออกไปหา super class มฉิ ะนน้ั แลว การดักจับในหลาย ๆ block อาจไมเกดิ ขน้ึ
เชน
try {
…
…
}
catch(Exception e) {
…
…
}
catch(ArithmeticException ex) {
…
…
}
เน่อื งจากวา class ArithmeticException เปน class ที่เกิดมาจาก class Exception ดงั นน้ั error
ทเ่ี กดิ ข้นึ ก็จะถูกดกั จับใน catch block ท้ังหมด การดกั จับใน catch block ทีส่ องจึงไมเ กดิ ข้นึ
เรามาลองดูตวั อยา งการดักจบั error ในรูปแบบนีก้ ันดู
1: /**
2: Catching multiple errors
3: */
4:
5: import static java.lang.System.out;
6:
7: class MultipleCatches {
8: public static void main(String[] args) {
9: //force divide by zero at index = 2
10: int []number = {1, 2, 0, 4};
11: int num = 12;
12: int count = 0;
13:
14: //force array index out of bound at index = 4
15: for(int i = 0; i < number.length + 1; i++) {
16: try {
17: num /= number[i];
18: out.printf("result = %d%n", num);
19: }
20: catch(ArithmeticException e) {
21: out.println("error message: " + e.getMessage());
22: }
23: catch(ArrayIndexOutOfBoundsException e) {
24: out.println("error message: " + e.getMessage());
25: }
26: finally {
27: out.printf("In finally block #%d%n", count++);
28: }
29: }
30: out.println("After a for loop.");
31: }
32: }
เราตองการที่จะบังคบั ใหเกิด error สองอยางคือ หารดวยศนู ย และเขาหา index ของ array ที่
ไมม ีอยูจรงิ โดยเรากาํ หนดใหข อ มูลท่ี index = 2 มีคาเปนศนู ย และให for/loop ทาํ งานเกินไป
หน่งึ คร้งั การ run โปรแกรมตวั อยางของเราทําใหเ กดิ ผลลพั ธดังน้คี อื
result = 12
In finally block #0
result = 6
In finally block #1
236
บทที่ 7: การตรวจสอบและดักจบั Error (Exceptions) intro. to Java (FEU.faa)
error message: / by zero
In finally block #2
result = 1
In finally block #3
error message: 4
In finally block #4
After a for loop.
จะเหน็ วาโปรแกรมของเราดักจับ error ไดต ามท่ีเราตง้ั ใจไว การหารดวยศูนย และการอางถงึ
index ของ array ทีไ่ มม อี ยูจ ริง ถกู ดักไวท ั้งสองตัว ถา เปน การจดั การท่ีเปน การพฒั นาโปรแกรม
จรงิ ๆ เราคงทําแคการดักจบั ไมไ ด คงตอ งมีกระบวนการอนื่ ๆ ในการทําใหโ ปรแกรมทาํ งานได
อยางราบรนื่ และกระบวนการจัดการกบั error ทีเ่ กิดขนึ้ ก็ตอ งมีความซบั ซอ นเพ่ิมขน้ึ
Java ยังมี block อกี block หนงึ่ ที่เอาไวดกั จับ error ท่ีเกิดขนึ้ ทีซ่ ่ึงเปน block สดุ ทายของการ
catch ท้ังหมด โดยกําหนดให block น้ีทชี ือ่ วา finally (บรรทัดท่ี 26 ของโปรแกรม
MultileCatches.java)
finally เปน การดักจบั error สดุ ทา ยของการดกั ทง้ั หมด ดังนั้น finally จะอยทู ี่อื่นไมไดน อกจาก
block สุดทา ยของ catch block และ finally block ท่ีเราใชจะถูกประมวลผลเสมอ ไมว าอะไรจะ
เกดิ ขึน้ กต็ ามใน block อ่นื ๆ กอนหนา ดงั ตัวอยา งของผลลัพธท ไี่ ดแ สดงใหด ู
โดยท่ัวไปหนาท่ีหลักของ finally จะเปนการเกบ็ กวาด code ที่โปรแกรมตอ งการประมวลผล
(เชน การปด เปด ไฟล) กอนออกจาก ตัว method main() และกลับออกไปสรู ะบบในท่ีสุด
โปรแกรมตอไปเปนตัวอยา งการใช throws และ try/catch รว มกนั
1: /**
2: Using throw with try/catch block
3: */
4:
5: import java.util.Scanner;
6: import java.io.*;
7: import static java.lang.System.out;
8:
9: class ThrowsWithTry {
10: public static void main(String[] args) throws IOException {
11: Scanner input = new Scanner(System.in);
12: int first, divider;
13:
14: //keep looping until error occur
15: while(true) {
16: out.print("Enter a number: ");
17: //get first number
18: first = input.nextInt();
19: //get second number
20: out.print("Enter a divider: ");
21: divider = input.nextInt();
22: //try dividing first by divider
23: try {
24: double result = first / divider;
25: out.println("Result = " + result);
26: }
27: catch(ArithmeticException e) {
28: out.println("Exception: " + e.getMessage());
29: e.printStackTrace();
30: }
31: }
32: }
33: }
โปรแกรม ThrowsWithTry.java เปนโปรแกรมที่ตองการแสดงการใช throws และ try/catch
ควบคกู นั โดยตัวโปรแกรมเองจะทําการอา นขอมูลสองตวั จาก keyboard ซึง่ กาํ หนดใหขอ มลู ทงั้
สองตวั เปน int และจะทาํ การหาผลลพั ธข องการหารขอมลู ตวั แรก ดวยขอมูลตวั ทส่ี อง
โปรแกรมจะหยดุ การทํางานกต็ อเมอื่ ผูใชใสขอ มลู ท่ไี มใชตวั เลข และจะทําการฟองถาขอมลู ตวั ท่ี
สองของการหารมคี าเปนศูนย ผลลพั ธท ่ไี ดจากการ run คือ
237
เริม่ ตน การเขยี นโปรแกรมดวย Java intro. to Java (FEU.faa)
D:\>java ThrowsWithTry
Enter a number: 23
Enter a divider: 12
Result = 1.0
Enter a number: 45
Enter a divider: 0
Exception: / by zero
java.lang.ArithmeticException: / by zero
at ThrowsWithTry.main(ThrowsWithTry.java:26)
Enter a number: 34
Enter a divider: 65
Result = 0.0
Enter a number: try
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at ThrowsWithTry.main(ThrowsWithTry.java:19)
จากผลลพั ธท ไี่ ดจ ะเหน็ วาโปรแกรมของเราจะฟอ งถามีการหารดว ยศูนย (ทเ่ี กิดจากการดกั จบั
ของเราในบรรทดั ท่ี 27) และหยุดถา ขอมูลไมใช int (ในตวั อยางนี้ผใู ชใสค ําวา "try" ซง่ึ เกิดจาก
การ throws ของ Java) โปรแกรมของเราจะทาํ งานไปเรื่อย ๆ ถา ผใู ชใสข อมลู ท่ีถูกตองตามที่
โปรแกรมไดก าํ หนดไว แตนีไ่ มใ ชก ารตรวจสอบท่ีดีเทา ไรนัก ถาเราตองการทีจ่ ะบอกผูใชวา
ขอ มลู ไมถูกตอ ง และใหใ สขอมูลใหมเ รากต็ อ งแกไ ข code ของเราใหร องรบั การทําใหม ซง่ึ อาจ
ทําไดด งั น้ี
1: /**
2: Using throws and try together
3: */
4:
5: import static java.lang.System.out;
6: import java.util.Scanner;
7: import java.util.InputMismatchException;
8:
9: class ThrowsWithTry1 {
10: public static void main(String[] args) {
11: Scanner input = new Scanner(System.in);
12: int first, divider, result;
13: boolean done = false;
14:
15: //continue till acceptable input is entered
16: while(!done) {
17: try {
18: out.print("Enter a number: ");
19: first = input.nextInt();
20: out.print("Enter a divider: ");
21: divider = input.nextInt();
22:
23: result = first / divider;
24: out.printf("Result is %d%n", result);
25: done = true;
26: }
27: catch(InputMismatchException ie) {
28: out.printf("Exception: %s%n", ie);
29: //discard this input
30: input.nextLine();
31: out.println("Try again.");
32: }
33: catch(ArithmeticException ar) {
34: out.printf("Exception: %s%n", ar);
35: out.println("Zero not accepted.");
36: }
37: }
38: }
39: }
ผลลพั ธทเ่ี ราไดคือ
D:\>java ThrowsWithTry1
Enter a number: 3
238
บทที่ 7: การตรวจสอบและดกั จบั Error (Exceptions) intro. to Java (FEU.faa)
Enter a divider: e
Exception: java.util.InputMismatchException
Try again.
Enter a number: 3
Enter a divider: 0
Exception: java.lang.ArithmeticException: / by zero
Zero not accepted.
Enter a number: 3
Enter a divider: 4
Result is 0
เราดัดแปลงโปรแกรมของเราใหมีการตรวจสอบขอผิดพลาดสองสวนคือ 1) user ใสข อมลู ท่ี
ไมใชต ัวเลข (บรรทัดที่ 27) และ 2) user ใสต ัวหารทีเ่ ปนศูนย (บรรทัดที่ 33) โปรแกรมของเรา
จะบังคับให user ใสข อ มลู จนกวาขอ มลู ทีใ่ สเ ขา มาเปนขอ มลู ท่ถี ูกตอง ถาหากเปนขอ มูลท่ีไมอยู
ในเง่อื นไขทเี่ รากําหนดไว while/loop ของเราก็จะทํางานไปเรอ่ื ย ๆ (ตัวแปร done เปน ตวั
กําหนดการยุตกิ ารทาํ งาน) ผูอา นจะเหน็ ไดจ ากผลลพั ธท่ีเราไดวา ขอ มูลทไ่ี มถกู ตองจะไมมกี าร
ประมวลผลจากโปรแกรม แตโ ปรแกรมจะสงขอความบอกไปยงั ผใู ชใหทราบวา ขอ มูลไมถ กู ตอ ง
พรอมทง้ั บังคบั ใหผ ูใชใ สขอมูลใหมจ นกวา จะถกู ตอง
7.2 การสราง exception ขึน้ มาใชเอง
เราสามารถทจี่ ะเขียน exception ขน้ึ มาใชเองไดถาหากเราเหน็ วาการสงขอความบอกไปยงั
user เกย่ี วกับ error ท่เี กดิ ขน้ึ ไมชดั เจน หรือละเอียดพอ โปรแกรม TestInputValidation.java
เปนโปรแกรมที่เราไดด ัดแปลงมาจากโปรแกรม ThrowsWithTry1.java โดยกาํ หนดใหมกี ารดกั
จับขอมูลท่มี ีคา เปน ศูนยจาก exception ZeroDivideException ทเี่ ราเขยี นขึ้นเอง
1: /**
2: Using user's exception
3: */
4:
5: import java.util.Scanner;
6: import java.util.InputMismatchException;
7: import static java.lang.System.out;
8:
9: class TestInputValidation {
10: public static void main(String[] args) {
11: Scanner input = new Scanner(System.in);
12: int first, divider, result;
13: boolean done = false;
14:
15: //continue till acceptable input is entered
16: while(!done) {
17: try {
18: out.print("Enter a number: ");
19: first = input.nextInt();
20: out.print("Enter a divider: ");
21: divider = input.nextInt();
22:
23: result = divide(first, divider);
24: out.printf("Result is %d%n", result);
25: done = true;
26: }
27: catch(InputMismatchException ie) {
28: out.printf("Exception: %s%n", ie);
29: //discard this input
30: input.nextLine();
31: out.println("Try again.");
32: }
33: catch(ZeroDivideException ar) {
34: out.printf("Exception: %s%n", ar);
35: out.println("Zero not accepted.");
36: }
37: }
38: }
39:
40: //division of two numbers
41: //if n is 0, ZeroDivideException is thrown
42: public static int divide(int m, int n) throws ZeroDivideException {
43: int result;
239
เร่ิมตน การเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
44: try {
45: result = m / n;
46: }
47: catch(ArithmeticException ar) {
48: throw new ZeroDivideException();
49: }
50: return result;
51: }
52: }
เราไดเ ปลย่ี นโปรแกรมกอ นหนา นมี้ ากพอสมควรในการที่จะอานขอมูลใหถูกตอง พรอ มท้ังแสดง
ถงึ การเขียน exception ขน้ึ มาใชเ อง เราเร่ิมดวยการสราง method readInt() ขน้ึ มาใหม โดย
กาํ หนดใหผ ูใชตอ งใสขอ มลู ใหถกู ตอ ง ถา ไมถ ูกเรากจ็ ะวนกลบั ไปถามใหมจ นกวา จะได
Method ตวั ทีส่ องทีเ่ ราสรา งขึ้นมาคอื method divide() ทร่ี ับ parameter 2 ตวั ทําหนา ทใ่ี นการ
หารตัวเลขตัวแรกดว ยตัวเลขตวั ทีส่ อง ภายใน method divide() นเี้ ราจะดักจับ error ทเี่ กิดข้นึ
ผา นทาง ArithmeticException ดว ย การ throw exception ท่เี ราไดส รางข้ึนเอง ดวยคาํ สงั่
catch(ArithmeticException e) {
throw new ZeroDivideException(); //throw new exception
}
แตก อนทเี่ ราจะเรียกใช exception ท่ีวา น้เี ราตองสรา ง code สาํ หรบั exception เสยี กอ น ซง่ึ เรา
ไดออกแบบใหเปน การดักจับแบบงาย ๆ ดว ยการสราง class ZeroDivideException จาก class
Exception เพ่ือทจี่ ะใหเราสามารถทจี่ ะไดรับการถายทอดคณุ สมบตั จิ าก class Exception เรา
กําหนดให code ของ class ZeroDivideException มดี ังน้ี
1: /**
2: Exception for division by zero
3: */
4:
5: class ZeroDivideException extends Exception {
6: //default constructor
7: ZeroDivideException() {
8: super("divide by zero"); //call super class' constructor
9: }
10:
11: ZeroDivideException(String message) {
12: super(message);
13: }
14: }
เราไมไดทําอะไรมากไปกวาเรียกใช constructor ของ class Exception ดวยขอ ความที่เรา
ตอ งการใหปรากฏหาก error ทว่ี านี้เกดิ ขน้ึ (divide by zero) และสว นท่ีสาํ คัญของการดกั จับ
error คือ catch ตวั ทีส่ องท่ีอยูใ นสว นของ code น้ี
…
catch(InputMismatchException ie) {
out.printf("Exception: %s%n", ie);
//discard this input
input.nextLine();
out.println("Try again.");
}
catch(ZeroDivideException ar) {
out.printf("Exception: %s%n", ar);
out.println("Zero not accepted.");
}
เราเรียก method divide() ภายใน try และถาหากการหารทเ่ี กิดขึ้นมี error (หารดวยศนู ย) มันก็
จะถกู จับใน catch block ทเ่ี ราไดเรยี กดวย object ทม่ี าจาก class ZeroDivideException ท่ีเรา
ไดส รางขึน้ หลังจากทล่ี อง run ดเู ราไดผลลัพธดงั นี้
D:\>java TestInputValidation
Enter a number: 23
Enter a divider: 0
Exception: ZeroDivideException: divide by zero
240
บทท่ี 7: การตรวจสอบและดักจับ Error (Exceptions) intro. to Java (FEU.faa)
Zero not accepted.
Enter a number: 3
Enter a divider: t
Exception: java.util.InputMismatchException
Try again.
Enter a number: 4
Enter a divider: 3
Result is 1
ผลลัพธทไี่ ดก็เปน ไปตามท่เี ราไดค าดไว คอื error ถกู ดักจับไวไ ดทัง้ สองตัวคือ ขอ มูลท่ีไมใช
ตัวเลข และขอ มลู ที่เปน ศูนย
ตัวอยา งตอไปน้เี ปนการกาํ หนดให user ใสขอมลู ในกลมุ (range) ทเี่ ราไดกาํ หนดไว ซ่งึ ถา ไม
เปน ไปตามนี้เรากจ็ ะฟองไปยงั ผใู ชทนั ที เหมือนดงั เชนทเ่ี ราไดท ํามากอนหนา นี้
1: /**
2: Catching error within a given range
3: */
4:
5: import java.util.Scanner;
6: import static java.lang.System.out;
7:
8: class CheckRange {
9: public static void main(String[] args) {
10: Scanner input = new Scanner(System.in);
11:
12: try {
13: out.print("Enter start number: ");
14: int first = input.nextInt();
15: out.print("Enter end number: ");
16: int second = input.nextInt();
17: out.print("Enter number to check: ");
18: int third = input.nextInt();
19:
20: //check if the third is between first and second
21: checked(first, second, third);
22: out.printf("Number %d is in [%d, %d]%n", third, first, second);
23: }
24: catch(OutOfRangeException e) {
25: e.printStackTrace(System.err);
26: }
27: }
28:
29: //method to validate range
30: public static void checked(int start, int stop, int num)
throws OutOfRangeException {
31: if(num < start) {
32: String errMsg = new String(num + " < " + start);
33: throw new OutOfRangeException(errMsg, start, stop);
34: }
35: if(num > stop) {
36: String errMsg = new String(num + " > " + stop);
37: throw new OutOfRangeException(errMsg, start, stop);
38: }
39: }
40: }
โปรแกรมตวั อยา งนี้รับขอมูล ที่เปนตวั เลขสามตัว โดยจะทําการตรวจสอบวาตัวเลขตัวทสี่ ามอยู
ระหวางตัวแรกและตัวที่สองหรือไม ถาไมก จ็ ะ throw exception OutOfRangeException ที่ได
ออกแบบไวดังนี้
1: /**
2: OutOfRangeException.java
3: */
4:
5: public class OutOfRangeException extends Exception {
6: //default constructor
7: OutOfRangeException() {}
8:
9: //constructor
241
เริ่มตน การเขยี นโปรแกรมดวย Java
10: OutOfRangeException(String message, int p, int q) { intro. to Java (FEU.faa)
11: super(message);
12: }
13: }
จะเหน็ วา โดยสว นใหญแ ลว เราจะเรยี กใช super class constructor ทาํ งานใหเ รา มากกวาท่จี ะ
เขยี น code ข้ึนมา ซึ่งเปน สง่ิ ทท่ี าํ ใหก ารออกแบบของเราไวข้นึ เราเพยี งแตเขยี นถงึ สง่ิ ทบี่ ง บอก
ถึง error ทเี กิดข้ึนวาเปนอะไรเทานัน้ เอง จากการ run ผลลพั ธท เ่ี ราไดถ าขอมลู ไมถ ูกตองคือ
D:\ >java CheckRange
Enter start number: 34
Enter end number: 56
Enter number to check: 98
OutOfRangeException: 98 > 56
at CheckRange.checked(CheckRange.java:37)
at CheckRange.main(CheckRange.java:21)
7.3 การใช Assertions
โปรแกรมตรวจสอบขอ มูล (CheckRange.java) ทีเ่ ราไดเ ขยี นขนึ้ นน้ั ตองมีการเรยี กใช หรือ
กาํ หนดใหมีการ throw exception ข้ึนแต Java ยงั มีวิธีการอนื่ ทเี่ ราสามารถนาํ มาใชใ นการ
ตรวจสอบ หรือดกั จับ error ที่อาจมีในโปรแกรมของเราได สิ่งที่วาน้นั คือ Assertion
Assertion เปน การตรวจสอบถงึ ขอ มลู หรอื กระบวนการทอ่ี าจไมถูกตองในการประมวลผล (logic
error) ซึง่ Java มีชนิดของ assertion อยูสองแบบคอื 1). Precondition assertion ซง่ึ หมายถงึ
สถานะของโปรแกรมในขณะท่ี method ถกู เรียกใช และ 2). Postcondition assertion ซึ่ง
หมายถึงสถานะของโปรแกรมหลังจากท่ี method ทํางานเสร็จสิน้ แลว ทงั้ สองชนิดมีรูปแบบอยู
สองแบบ คอื
1. assert expression; ซงึ่ จะ throws AssertionError ถา expression มีคาเปน เท็จ
2. assert expression1 : expression2; ซ่งึ จะ throws AssertionError ดวยขอ ความของ
expression2 ถา expression1 มีคาเปนเทจ็
เราจะทดลองใช assertion กับโปรแกรม CheckRange.java ดวยการเปลยี่ นบางสว นของ code
ดงั นี้
1: /**
2: Catching error within a given range
3: */
4:
5: import java.util.Scanner;
6: import static java.lang.System.out;
7:
8: class AssertionTest {
9: public static void main(String[] args) {
10: Scanner input = new Scanner(System.in);
11:
12: out.print("Enter start number: ");
13: int first = input.nextInt();
14: out.print("Enter end number: ");
15: int second = input.nextInt();
16: out.print("Enter number to check: ");
17: int third = input.nextInt();
18:
19: //check if the third input is between first and second
20: assert(third >= first && third <= second) :
message(first, second, third);
21: out.printf("Number %d is in [%d, %d]%n", third, first, second);
22: }
23:
24: //check if p is in [m, n]
25: public static String message(int m, int n, int p) {
26: return String.format("%d is not in [%d, %d]%n", p, m, n);
27: }
28: }
242
บทที่ 7: การตรวจสอบและดกั จับ Error (Exceptions) intro. to Java (FEU.faa)
เราเรยี กใช assert() ในบรรทัดที่ 20 ดว ยการตรวจสอบคาของตวั แปร third วาอยรู ะหวาง first
และ second หรอื ไมซ่ึงถาไมขอความทีเ่ ราไดกําหนดในบรรทัดท่ี 26 จะถูกสง กลับมาจาก
method message() ดังตวั อยา งการ run นี้
D:\>java -ea AssertionTest
Enter start number: 2
Enter end number: 6
Enter number to check: 4
Number 4 is in [2, 6]
D:\>java -ea AssertionTest
Enter start number: 2
Enter end number: 4
Enter number to check: 9
Exception in thread "main" java.lang.AssertionError: 9 is not in [2, 4]
at AssertionTest.main(AssertionTest.java:20)
โดยปกตแิ ลวการใช assert() จะใชในการ debug1 โปรแกรมเพือ่ ตรวจสอบถึง error ทอ่ี าจ
เกิดข้ึน ดงั นนั้ การ run โปรแกรมจึงตองใชข อ กาํ หนด –ea เปน ตัวบอกให Java ทราบถึงการ
เรียกใชดังกลา ว ถาเราไมใช –ea ในการ run โปรแกรมเรากจ็ ะไมเห็นขอความใด ๆ ที่เก่ียวขอ ง
กับ error ทเ่ี กิดข้นึ
สรปุ
ในการเขยี นโปรแกรมท่ดี ีน้นั ผเู ขยี นจะตองคาํ นงึ ถึง error ท่อี าจเกดิ ขน้ึ ในโปรแกรม ซ่งึ ไดแ บง
ออกเปนสองลักษณะใหญ คอื error ทีโ่ ปรแกรมเมอรไมมีทางแกไขได คือ อยนู อกเหนอื การ
ควบคุมของผพู ฒั นาโปรแกรม เชน error ทีเ่ กิดจากหนวยความจาํ ไมพอเพียง สว น error อกี
อันหนึง่ ทผี่ ูเ ขยี นโปรแกรมตองตรวจสอบกค็ ือ error ที่เกดิ ตอน run โปรแกรม เชน error จาก
การหารดว ยศูนย การเขาหา Index ของ array ท่ีไมม ีอยจู ริง การปอนขอมูลทไ่ี มถ กู กับชนดิ ที่
ตองการ อยางนีเ้ ปนตน
Exception ที่ Java มีใหมอี ยมู ากพอสมควร และมากพอท่จี ะเรียกใชไดเ กือบทุกกรณีของการ
เขียนโปรแกรม แตถาผูเ ขยี นโปรแกรมไดพัฒนาโปรแกรมที่ไมส ามารถใช exception ท่ี Java มี
ใหก ส็ ามารถท่ีจะออกแบบ exception ข้นึ มาใชเ องได
ในการดัก error นนั้ ผูเขียนอาจสราง exception ข้ึนมาใชในการดกั จับ error เองได ท้ังน้กี ็ข้นึ อยู
กบั ลักษณะของงานท่ผี ูเ ขียนโปรแกรมกาํ ลงั พัฒนาอยู โดยสรปุ แลวสิ่งทต่ี อ งควรคํานึงในการ
ตรวจจับ error คอื
9 Exception เปน ตัวบง ชีถ้ งึ error ทีเ่ กิดในโปรแกรม
9 Exception เปน object ท่ีเกดิ มาจาก class Throwable
9 เราสามารถทจ่ี ะเรยี กใช exception ที่มาจาก Java โดยตรง หรอื สรางขนึ้ มาใชเ อง
9 ถาเราตองการทจ่ี ะควบคมุ exception ใน method เราตอ งเขียน code ใน try block และไม
จําเปน ท่ีจะตอ งมี try block เพียงหนง่ึ block เทา น้นั อาจมีมากกวา หน่งึ block ได
9 Code ทใี่ ชในการควบคุม หรอื แกไ ข exception จะตอ งทําใน catch block ทตี่ ามหลงั try
block ทันทีและในหนึง่ try block เราสามารถทจี่ ะมี catch block มากกวาหนงึ่ ตัวได
9 Finally เปน block ทายสดุ ทอี่ ยูใน try โดยทว่ั ไปจะใช finally block ในการเก็บกวาดการ
ทาํ งานของโปรแกรม เชน การปดไฟล
9 การเขียน exception ขนึ้ มาใชเอง
9 การเรยี กใช assert() สาํ หรบั การ debug โปรแกรม
แบบฝก หดั
1. จงเขยี นโปรแกรมท่ีรับขอมูลจาก keyboard เฉพาะทีเ่ ปน int เทาน้ันใหใช exception ใน
การดักจบั error ท่ีผใู ชอ าจใสผดิ เชน ใสตวั อกั ษร ใหแสดงขอความฟองทนั ทีทผ่ี ูใชใสผดิ
1 Debug เปน การตรวจสอบขอ ผดิ พลาดที่อาจเกิดขึน้ ในขณะท่มี ีการเขียนโปรแกรมเกิดข้ึน ซง่ึ เปน การตรวจสอบถึงความ
ถกู ตองของโปรแกรมกอนทจ่ี ะเสรจ็ ส้นิ ซง่ึ ตางจากการสง ขอ ความเตือน user (error message) ถึงขน้ั ตอนหรือขอมลู ที่
ไมต รงกับสงิ่ ทีโ่ ปรแกรมตอ งการ
243
เร่ิมตน การเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
2. จงปรบั ปรุงโปรแกรมทีเ่ ขียนข้ึนในขอหน่ึง โดยเพิ่มการตรวจสอบทีไ่ มรบั ตวั เลขทต่ี าํ่ กวาศนู ย
3. จงเขียนโปรแกรมทีร่ ับขอ มลู จาก keyboard เปน ตวั เลขสามตวั โดยกาํ หนดให ตวั แรกเปน
จดุ เรม่ิ ตน ตวั ท่สี องเปน จดุ จบ ของคา ขององศา Celsius และตัวท่สี ามเปน ตวั กําหนดการ
เพม่ิ คา (step) ใหโปรแกรมทําการคํานวณหา องศา Fahrenheit ตามขอ มลู ที่กาํ หนดไวใน
สองตวั แรก และใหท ําการเพิ่มข้นึ ตามคาของขอมลู ตัวท่สี าม ดังตัวอยางผลลัพธทแ่ี สดงใหด ู
น้ี
>java Temperature 0 100 10
CELSIUS FAHRENHEIT
0 32.0
10 50.0
20 68.0
30 86.0
40 104.0
50 122.0
60 140.0
70 158.0
80 176.0
90 194.0
100 212.0
ใหทําการตรวจสอบ และดักจับ error ท่อี าจเกิดขน้ึ จากการใสขอมูลที่ไมถูกตอง เชน คา
ของการเพ่มิ เปนตัวเลขทีน่ อ ยกวา ศนู ย (negative number) คา เริม่ ตน มากกวา คาสดุ ทา ย
และจาํ นวนขอมลู ทนี่ ําเขา มจี าํ นวนไมค รบตามท่กี ําหนด ตัวอยางของ error ที่เกิดข้ึน
>java Temperature 0 100 -5
3rd arg < 0 NUMBER = -5
>java Temperature 40 20 5
Ordering Err FIRST = 40 SECOND = 20
>java Temperature 10 40
java.lang.ArrayIndexOutOfBoundsException:
at Temperature.main(Temperature.java:41)
4. จงเขียนโปรแกรมท่ีหาคาของ mn โดยกําหนดใหท ้ัง m และ n มาจาก command line
argument list ใหท ําการตรวจสอบและดักจับ error ทุก ๆ กรณที อ่ี าจทาํ ใหโปรแกรมไม
ทํางาน
5. จงปรบั ปรงุ class Account ในบทที่หกใหม ีการตรวจสอบและดักจับ error ที่อาจเกดิ ขึน้ ใน
การ ถอนเงนิ ฝากเงิน และ คดิ ดอกเบย้ี ถา method ใด ๆ ที่ทําหนา ทดี่ ังกลา วไมม ี ใหเ ขยี น
ขึ้นใหม พรอมทั้งเขยี นโปรแกรมทดสอบ
6. จงปรับปรงุ โปรแกรมในขอ เจ็ด แปด และ เกา ในบทที่หา ใหมีการตรวจสอบและดกั จับ
error พรอ มท้ังเขียนโปรแกรมทดสอบ
244
ในบททแ่ี ปดนีเ้ ราจะพูดถึงการอา น และเขยี นขอ มูลผา นทาง stream หรือชองทางการสงขอมลู intro. to Java (FEU.faa)
เราจะดูถงึ วิธกี าร กระบวนการตาง ๆ ทเ่ี กีย่ วของกบั ขอมูลนาํ เขา และการนาํ ขอมูลออก
หลังจากจบบทนี้แลว ผอู านจะไดทราบถงึ
o ความหมายของ stream
o Class ตาง ๆ ท่ี Java มีใหในการประมวลผลดว ย stream
o การสรา ง directory
o การสราง file การเปด และปด file การอา นและเขยี น file
o ขอแตกตา งระหวา ง text file และ binary file
ในการทาํ งานท่ีเกี่ยวขอ งกบั ไฟลใน Java น้ันจะตองทําผานทาง stream ซ่งึ เปน ตวั แทนของ
อุปกรณทน่ี ําเขา (input) หรือสงออก (output) ขอ มลู เราสามารถเขยี น และอานขอ มูลผานทาง
stream ดว ยวิธกี ารตาง ๆ ในรูปแบบตา ง ๆ กนั เชน อา นขอ มูลจาก keyboard ทลี ะหนึง่ ตัวอกั ษร
หรอื ทีละ 10 byte
โดยท่วั ไป ขอ มูลนาํ เขา จะมาจาก keyboard หนวยความจําสํารอง (disk) หรอื อปุ กรณอ่ืน ๆ
เชน scanner light-pen memory-card แตโดยสวนใหญแ ลว มักจะมาจาก keyboard และ disk
ในบทนี้เราจะใชอ ุปกรณท ั้งสองท่ีไดก ลาวมา เปนชองทางหลักในการนาํ เขาขอมลู และจะใช
ชองทางสงออกเพยี งสองทางคือ จอ (monitor) และ เครือ่ งพิมพ (printer)
8.1 Streams
รปู แบบพืน้ ฐานของขอมลู ท่ี Java รจู กั มีอยูสองลกั ษณะคือ binary streams และ character
streams ซ่งึ มคี วามแตกตางกนั ในรปู แบบของการจัดเก็บ ถา เราเขยี นขอมูลเขา สู stream โดย
เขยี นทลี ะ byte หรือ ทีละหลาย ๆ byte เราเรียกขอ มูลเหลานีว้ า binary data การเขยี นจะไมม ี
กระบวนการอ่นื ใดมายงุ เก่ยี ว (เชน การเปล่ยี นขอ มลู ใหอยูใ นรูปแบบอ่ืนกอนการจดั เกบ็ ) ขอ มลู จะ
ถูกสง เขาสู stream ตามท่ปี รากฏอยใู น memory เชน ถา memory สวนน้เี ก็บขอ มลู ท่ีเปน
ตัวเลขอยู ตัวเลขเหลา นี้จะถูกสง เขาสู streams ตามทีป่ รากฏใน memory
ในการเกบ็ ขอมูลทีเ่ ปน character streams น้นั โดยท่ัวไปจะทาํ กับขอ มูลทเ่ี ปนตวั อักษร (text)
เราจะใช character streams ในการอานไฟลท่ีเปน text ตวั เลขท่อี ยูในไฟลจ ะถูกเปล่ยี นใหอยู
ในรูปแบบที่ Java ไดก ําหนดขึน้ การอานตวั เลขดว ยการใช character streams เปนกระบวนการ
ทย่ี งุ ยากมาก เพราะเราตองรวู าตวั อกั ษรทีเ่ ปนตัวแทนของตวั เลขนน้ั ใชก่ีตวั อักษรในการเก็บ เชน
ถา เราสงตวั เลข 17 ผา นทาง character stream ตวั เลขนจ้ี ะถกู เปลีย่ นใหเ ปนคา ASCII ของ '1'
และ '7' หรอื 0x310x37 (เลขฐาน 16) และสมมติวา เราเขียนเลข 727 อกี ตัวใน stream ของเรา
ก็จะมขี อมลู เปน 0x310x370x370x320x37 การอานตัวเลขทงั้ สองตัวออกมาจะทาํ ไดยากมาก
เพราะเราไมรวู าจะตองอานตวั อักษรทีละกีต่ ัวถงึ จะไดขอ มูลท่ีถกู ตอ งเหมือกบั ท่ีไดเขียนไว
เราไดท ราบแลว วา Java เก็บขอ มูลในรปู แบบของ Unicode ดงั น้ันในการเขียนขอ มูลเขาสู
stream ในรปู แบบของ character ขอ มูลจะถูกเปล่ียน (โดยอัตโนมตั )ิ ใหอ ยใู นรปู แบบของการ
เก็บ (local code) ตามทีเ่ ครื่องนนั้ ใชอ ยู เชน ถา เครอ่ื งของเราใชภาษาไทยเปน ภาษาหลกั
รูปแบบของการเกบ็ ก็จะเปน code ของภาษาไทย (Java เรยี กระบบน้วี า localization) ในการ
อานขอมลู น้นั Java จะเปล่ียนขอ มูลท่ีถูกจดั เก็บในรปู แบบของ local code ใหเ ปน Unicode
กอน โดยสรปุ แลวในการเขยี น และอานน้นั Java จะเปลี่ยนขอมลู ใหเ ปน Unicode สว นการ
จดั เก็บนัน้ จะจัดเก็บในรูปแบบของภาษาทใ่ี ชอยใู นเครือ่ ง
เรม่ิ ตนการเขียนโปรแกรมดว ย Java
เราจะมาดูตัวอยางทเ่ี กี่ยวขอ งกบั ไฟล ในหลาย ๆ รปู แบบเพ่ือทําใหเ กิดความเขา ใจถงึ วิธีการ intro. to Java (FEU.faa)
และกระบวนการตา ง ๆ ท่เี กย่ี วขอ งกบั input และ output และกอ นที่เราจะสรางไฟลในรูปแบบ
ตาง ๆ เราจะมาดกู ันถึงการใช class ท่เี ออ้ื ถึงการดูขอ มูลที่เกีย่ วขอ งกับไฟล หรือ directory
8.2 การเรยี กใช class File
Class File เปน class ท่ีมไี วเ พื่อใหเ ราสามารถดึงขอ มลู ทเี่ ก่ยี วของกบั ไฟล หรอื directory ออก
จากหนวยความจําสํารอง (disk) Object ท่ีสรางมาจาก class File ไมสามารถเปดไฟลห รือ
ประมวลผลขอมลู ที่อยูในไฟลไ ด จะใชรว มกับ class ที่เกยี่ วของกบั ไฟลอื่น ๆ ท่ี Java มีให
Class File มี constructor อยูส ามตวั ทีเ่ ราสามารถเรยี กใชได คือ
1. File(File parent, String child) จะเรียกใชไฟล object directory (parent) ท่ีมี
อยแู ลว ในการคน หาไฟล หรอื directory ที่กําหนดใหจากตวั แปร child
2. File(String pathname) จะเรยี กใช pathname ในการคน หาไฟล หรอื directory
ซ่งึ pathname ทีว่ า จะเปน absolute path1 หรอื relative path2 กไ็ ด
3. File(String parent, String child) จะเรยี กใช parent ในการคนหาไฟล หรือ
directory ที่กําหนดใหจ ากตวั แปร child
4. File(URI uri) เปน การคนหาไฟลจ าก URI3 เชน file:/D:/temp/chapter7.txt
โปรแกรมตวั อยางทเี่ ห็นน้ีเปน การแสดงขอ มูลทเี่ กีย่ วกับไฟลท ่กี ําหนดให
1: /**
2: Get inofrmation about file
3: */
4:
5: import java.io.*;
6: import static java.lang.System.out;
7:
8: class FileInfo {
9: public static void main(String[] args) {
10: //get path from command-line argument
11: File path = new File(args[0]);
12:
13: //display some info. about this file
14: if(path.exists()) {
15: out.println(path + " does exist.");
16: out.println("Readable : " + statusOk(path.canRead()));
17: out.println("Writable : " + statusOk(path.canWrite()));
18: out.println("Directory? : " + statusOk(path.isDirectory()));
19: out.println("File? : " + statusOk(path.isFile()));
20: out.println("Hidden? : " + statusOk(path.isHidden()));
21: }
22: else
23: out.println(path + " does not exist.");
24: }
25:
26: //return "Yes" or "No"
27: public static String statusOk(boolean yes) {
28: return yes ? "Yes" : "No";
29: }
30: }
โปรแกรมเร่ิมตนดวยการสรา ง object path จาก class File ดวยขอมูลท่มี าจาก command-line
argument ซงึ่ อาจอยใู นรูปแบบ
e:\bc221Book\source
e:\bc221Book\source
\source
\bc221Book\source\FileInfo.java
1 Path ท่เี ร่มิ ตน จาก root directory ไปจนถงึ ไฟล เชน C:\javaBook\revision2\chapter2.doc
2 Path ทเี่ รม่ิ ภายใน directory ที่มีโปรแกรมอยู เชน ถา เราทาํ งานใน D:\temp ไฟลท เี่ ราคนหาจะอยูใน directory นี้
3 URI หมายถึง Uniform Resource Identifier ซ่ึงเปน อีกรูปแบบหน่ึงของ URL (Uniform Resource Relocator) ทีใ่ ช
ในการคนหา web site
246