The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.

Introduction to Programming Java Language

Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by ปิติ เกตุ, 2021-03-22 04:12:52

Introduction to Programming Java Language

Introduction to Programming Java Language

บทที่ 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


Click to View FlipBook Version