[Java] Java ไม่มี Pass by Reference
ผมเองเข้าใจมาตลอดว่า Java นั้นมี pass by reference ประกอบกับหนังสือภาษาไทยของดร.ท่านหนึ่งก็ได้กล่าวไว้อย่างนั้นเช่นกัน แต่ไม่นานมานี้ ผมก็ได้พบกับความจริงว่ามันไม่ได้เป็นอย่างนั้นเลย
ก่อนที่ผมจะเริ่มการอธิบายที่คาดว่าจะเยอะ ขอแนะนำเลยครับว่า ถ้างง อยากให้ค่อยๆอ่านครับ เพราะผมเองก็งงเหมือนกันในช่วงแรกๆ แต่พอได้เห็นตัวอย่าง ได้ลองทำตาม ลองจินตนาการดู ผมก็เข้าใจแล้วครับว่า มันเป็นแบบที่เขาว่าจริงๆนั่นแหละ
จากบทความที่ผมเคยเขียนนี้ http://lordgiftblog.blogspot.com/2012/07/java-pass-by-reference-pass-by-value.html ทำให้ผมรู้ว่า ผมเคยเข้าใจผิด และไม่แปลกที่จะสงสัยมัน โดยในบทความที่ว่านี้ผมพยายามจะอธิบายว่า Java มัน pass by reference อยู่เบื้องหลัง แต่ถ้ามันทำ pass by reference จริงๆ มันก็ต้องมี pointer เข้ามาเกี่ยวข้องด้วย จริงไหมครับ ทีนี้ก็จะมีอีกคำหนึ่งที่ทำให้เรารู้สึกขัดแย้งขึ้นมาก็คือ "java ไม่มี pointer" หลายคนอาจจะเคยได้ยินมา(เป็นเหตุผลนึงที่แรกๆ ผมอยากเขียน Java แต่...)
เอาล่ะ ผมจะเริ่มอธิบายด้วยโค้ดภาษา C++ อย่างง่ายๆ พอให้เห็นภาพนะครับ
โปรแกรมนี้ผมสร้างตัวแปรปกติ แต่ตอนเรียกฟังก์ชันผมส่ง address หรือ reference เข้าไป ซึ่งแน่นอนว่าถ้าส่ง address มาต้องมีการรับ parameter ด้วย pointer จากนั้นจับมันเท่ากับ
ก่อนที่ผมจะเริ่มการอธิบายที่คาดว่าจะเยอะ ขอแนะนำเลยครับว่า ถ้างง อยากให้ค่อยๆอ่านครับ เพราะผมเองก็งงเหมือนกันในช่วงแรกๆ แต่พอได้เห็นตัวอย่าง ได้ลองทำตาม ลองจินตนาการดู ผมก็เข้าใจแล้วครับว่า มันเป็นแบบที่เขาว่าจริงๆนั่นแหละ
จากบทความที่ผมเคยเขียนนี้ http://lordgiftblog.blogspot.com/2012/07/java-pass-by-reference-pass-by-value.html ทำให้ผมรู้ว่า ผมเคยเข้าใจผิด และไม่แปลกที่จะสงสัยมัน โดยในบทความที่ว่านี้ผมพยายามจะอธิบายว่า Java มัน pass by reference อยู่เบื้องหลัง แต่ถ้ามันทำ pass by reference จริงๆ มันก็ต้องมี pointer เข้ามาเกี่ยวข้องด้วย จริงไหมครับ ทีนี้ก็จะมีอีกคำหนึ่งที่ทำให้เรารู้สึกขัดแย้งขึ้นมาก็คือ "java ไม่มี pointer" หลายคนอาจจะเคยได้ยินมา(เป็นเหตุผลนึงที่แรกๆ ผมอยากเขียน Java แต่...)
เอาล่ะ ผมจะเริ่มอธิบายด้วยโค้ดภาษา C++ อย่างง่ายๆ พอให้เห็นภาพนะครับ
C++ Pass by reference |
"string changed"
ถ้ามันทำ pass by reference ได้จริง ค่า str
ที่แสดงออกมาจะต้องเป็น "string changed"
ทั้งคู่ครับ
ทีนี้มาดูฝั่งของ Java บ้างครับ ทำงานคล้ายๆ กัน
Java : pass by value(Primitive type) |
ความแตกต่างระหว่าง 2 โปรแกรมด้านบนนี้แน่นอนว่ามันคือการส่ง parameter โดยโปรแกรมแรก(C++) เป็นการส่งแบบ pass by reference ส่วนโปรแกรมที่สอง(Java) เป็นการส่งแบบ pass by value ครับ
ทั้งสองโปรแกรมนี้ผมลัพธ์ไม่เหมือนกันอย่างแน่นอน เพราะ
เอาล่ะ โปรแกรมนี้ผมตั้งใจจะให้เกิด
การกระทำแบบนี้ address หรือ reference นั้น คิดซะว่ามันคือ attribute พิเศษตัวหนึ่งใน Bean และมันถูกส่งไปด้วยเหมือนกับค่าอื่นๆ reference ตัวนี้แหละทำหน้าที่ให้ pointer มาชี้มัน เพื่อเอาชุดข้อมูลที่เราต้องการ การที่เรา set ค่าให้กับ Bean ไป pointer ตัวไหนชี้อยู่ก็แปลว่าจะเป็นค่าเป็นอย่างเดียวกัน
กลับไปที่ C++ นิดนึงครับ เซียน C++ อาจบอกว่า ถ้าแบบนี้มันก็เปลี่ยน pointer ให้ชี้ไปที่อื่นได้เหมือนกันหนิ คำตอบคือ ใช่ครับ นั่นแหละกระบวนการด้านหลังของ Java มันเลือกที่จะเปลี่ยนหรือไม่เปลี่ยนเอง bean ในโปรแกรมสุดท้าย อาจเป็น pointer ก็ได้ หรือเป็น object ใหม่ก็ได้ ด้วย operator "=" เพียงตัวเดียว
สรุปๆๆ ถึงแม้ว่าเราอาจจะคุ้นหูกับคำว่า java ไม่มี pointer หรืออ่านบทความนี้ไปแล้วติดใจว่า java ไม่มี pass by reference แต่ก็ไม่ได้หมายความว่าเราจะไม่ได้ยุ่งกับมันครับ ลึกๆแล้วมันก็ยังทำงานลักษณะนี้ ยังไงก็ยังทิ้งไม่ได้นะครับ หวังว่าคงเข้าใจกันมากขึ้น ถ้าผมผิดพลาดอะไรยังไง รบกวนแนะนำได้เลยนะครับ ^^
#ความรู้ผมยังด้อยเร่งศึกษา เมื่อเติบใหญ่ผมจะได้มีวิชา...
ทั้งสองโปรแกรมนี้ผมลัพธ์ไม่เหมือนกันอย่างแน่นอน เพราะ
str
ที่รับเข้ามาและถูกเปลี่ยนไปใน method นั้น ตัวที่ส่งก็ไม่ได้เปลี่ยนไปตาม โดยหลักการก็ไม่เหมือนกันอยู่แล้ว ทีนี้มาลองดูโปรแกรมถัดไปครับJava : passing parameter with Bean(Class type) |
ก่อนที่จะลองเขียนโค้ดตาม อยากให้ลองเดาดูครับว่า ผลลัพธ์ที่ได้จะเป็นอย่างไร ในที่นี้
Bean
ของผมมีแค่ setter/getter นะครับ
มาถึงจุดนี้ ผมคิดว่าหลายคนอาจจะคิดอยู่ในหัวถึงคำว่า "Pass by reference" แล้ว และนี่แหละคือประเด็นที่เป็นที่มาของหัวข้อ "Java ไม่มี pass by reference" และผมกำลังพยายามเข้าใจมันอยู่เหมือนกัน ^^
ถ้ายังเข้าใจอยู่ว่า "เฮ้ย! ค่ามันก็เปลี่ยนนะ pass by ref. ชัวร์" นี่คือสิ่งที่ผมคิดครับ แต่ผมได้รับคำยืนยันมาจากผู้รู้มาว่ามันคือ pass by value เท่านั้น ผมก็เลยลองกลับมาทบทวนดู จากนั้นผมก็ตอบตัวเองครับว่า เราเขียน Java จนเราลืมไปเลยว่า pointer, pass by ref. คืออะไร ลองดูโปรแกรมนนี้ครับ(สุดท้ายแล้ว)
Java : changing pointer |
NullPointerException
เพราะถ้ามันทำ pass by ref. จริง Bean
จะต้องถูกเปลี่ยนให้เป็น null
แต่เปล่าเลยครับ โปรแกรมทำงานได้ปกติ จุดนี้เองที่ทำให้ผมคิดได้ว่า ถ้ามันทำ pass by ref. จริง แปลว่า bean ที่รับเข้ามาจะต้องเป็น pointer(และมันเป็นแบบนั้นจริงๆ) แต่ก็ไม่ได้หมายความว่า pointer ตัวนี้มันจะ point ไปที่อื่นไม่ได้ การที่เราจับมันเท่ากับ null
นั้นก็เป็นเพียงเปลี่ยน pointer ของ parameter ตัวนี้แค่นั้นเอง ตัวเดิมก็คือที่เดิม แปลว่า "bean value"
จะถูกแสดงออกมาการกระทำแบบนี้ address หรือ reference นั้น คิดซะว่ามันคือ attribute พิเศษตัวหนึ่งใน Bean และมันถูกส่งไปด้วยเหมือนกับค่าอื่นๆ reference ตัวนี้แหละทำหน้าที่ให้ pointer มาชี้มัน เพื่อเอาชุดข้อมูลที่เราต้องการ การที่เรา set ค่าให้กับ Bean ไป pointer ตัวไหนชี้อยู่ก็แปลว่าจะเป็นค่าเป็นอย่างเดียวกัน
กลับไปที่ C++ นิดนึงครับ เซียน C++ อาจบอกว่า ถ้าแบบนี้มันก็เปลี่ยน pointer ให้ชี้ไปที่อื่นได้เหมือนกันหนิ คำตอบคือ ใช่ครับ นั่นแหละกระบวนการด้านหลังของ Java มันเลือกที่จะเปลี่ยนหรือไม่เปลี่ยนเอง bean ในโปรแกรมสุดท้าย อาจเป็น pointer ก็ได้ หรือเป็น object ใหม่ก็ได้ ด้วย operator "=" เพียงตัวเดียว
สรุปๆๆ ถึงแม้ว่าเราอาจจะคุ้นหูกับคำว่า java ไม่มี pointer หรืออ่านบทความนี้ไปแล้วติดใจว่า java ไม่มี pass by reference แต่ก็ไม่ได้หมายความว่าเราจะไม่ได้ยุ่งกับมันครับ ลึกๆแล้วมันก็ยังทำงานลักษณะนี้ ยังไงก็ยังทิ้งไม่ได้นะครับ หวังว่าคงเข้าใจกันมากขึ้น ถ้าผมผิดพลาดอะไรยังไง รบกวนแนะนำได้เลยนะครับ ^^
#ความรู้ผมยังด้อยเร่งศึกษา เมื่อเติบใหญ่ผมจะได้มีวิชา...