count
ฟิลด์เป็นแบบคงที่ในCounter
คลาส หมายความว่าคุณสามารถอ้างอิงตัวแปรด้วยนิพจน์ต่อไปนี้Counter.count
: แน่นอนว่าต้องพิจารณาตัวดัดแปลงการเข้าถึง ตัวอย่างเช่นprivate
ฟิลด์จะพร้อมใช้งานภายในคลาสที่มีการประกาศเท่านั้น และprotected
ฟิลด์จะพร้อมใช้งานสำหรับทุกคลาสภายในแพ็คเกจ เช่นเดียวกับคลาสย่อยทั้งหมดที่อยู่นอกแพ็คเกจ สมมติว่าCounter
คลาสมีincrement()
เมธอดแบบสแตติกซึ่งมีหน้าที่เพิ่มค่าcount
สนาม. ในการเรียกใช้เมธอดนี้ คุณสามารถใช้Counter.increment()
. ไม่จำเป็นต้องสร้างอินสแตนซ์ของCounter
คลาสเพื่อเข้าถึงฟิลด์หรือเมธอดแบบสแตติก นี่คือความแตกต่างพื้นฐานระหว่างตัวแปรและเมธอดแบบสแตติก (คลาส) และตัวแปรและเมธอดแบบไม่คงที่ (อินสแตนซ์) หมายเหตุสำคัญ อย่าลืมว่าสมาชิกคงที่ของคลาสเป็นของคลาสโดยตรง ไม่ใช่ตัวอย่างใดๆ ของคลาส นั่นคือค่าของตัวแปรคงcount
ที่จะเหมือนกันสำหรับCounter
วัตถุ ทั้งหมด ในบทความนี้ เราจะพิจารณาลักษณะพื้นฐานของการใช้สแตติกโมดิฟายเออร์ใน Java รวมถึงคุณสมบัติบางอย่างที่จะช่วยให้คุณเข้าใจแนวคิดหลักในการเขียนโปรแกรม
สิ่งที่โปรแกรมเมอร์ทุกคนควรรู้เกี่ยวกับ Static Modifier ใน Java
ในส่วนนี้ เราจะพิจารณาประเด็นหลักของการใช้เมธอด ฟิลด์ และคลาสแบบสแตติก เริ่มจากตัวแปรกันก่อน-
คุณไม่สามารถเข้าถึงสมาชิกที่ไม่ใช่สแตติกของคลาสภายในบริบทสแตติก เช่น เมธอดหรือบล็อกสแตติก การคอมไพล์โค้ดด้านล่างจะทำให้เกิดข้อผิดพลาด:
public class Counter { private int count; public static void main(String args []) { System.out.println(count); // Compile time error } }
นี่เป็นข้อผิดพลาดที่พบบ่อยที่สุดอย่างหนึ่งของโปรแกรมเมอร์ Java โดยเฉพาะมือใหม่ เนื่องจาก
main
เมธอดเป็นแบบสแตติกและcount
ไม่ใช่ตัวแปร การใช้println
เมธอดภายในmain
เมธอดจะทำให้เกิด "ข้อผิดพลาดในการคอมไพล์" -
ไม่เหมือนกับตัวแปรโลคัล ฟิลด์สแตติกและเมธอดไม่มี
thread safe
ใน Java ในทางปฏิบัติ นี่เป็นหนึ่งในสาเหตุที่พบบ่อยที่สุดของปัญหาด้านความปลอดภัยในการเขียนโปรแกรมแบบมัลติเธรด เมื่อพิจารณาว่าแต่ละอินสแตนซ์ของคลาสอ้างอิงสำเนาเดียวกันของตัวแปรสแตติก ตัวแปรดังกล่าวจำเป็นต้องได้รับการป้องกันหรือ "ล็อค" โดยคลาส ดังนั้น เมื่อใช้ตัวแปรสแต ติกต้องแน่ใจว่าถูกต้องsynchronized
เพื่อหลีกเลี่ยงปัญหา เช่นrace conditions
-
เมธอดแบบสแตติกมีข้อได้เปรียบในทางปฏิบัติตรงที่ไม่จำเป็นต้องสร้างออบเจกต์ใหม่ทุกครั้งที่คุณต้องการเรียกใช้ สามารถเรียกใช้เมธอดแบบสแตติกได้โดยใช้ชื่อของคลาสที่ประกาศ นั่นเป็นเหตุผลที่วิธีการเหล่านี้เหมาะสำหรับ
factory
วิธีการและutility
วิธีการต่างๆ คลาส นี้java.lang.Math
เป็นตัวอย่างที่ยอดเยี่ยม: เมธอดเกือบทั้งหมดเป็นแบบสแตติก คลาสยูทิลิตี้ของ Java ถูกทำเครื่องหมายfinal
ด้วยเหตุผลเดียวกัน -
จุดสำคัญอีกประการหนึ่งคือคุณไม่สามารถแทนที่ (
@Override
) เมธอดแบบสแตติกได้ หากคุณประกาศเมธอดดังกล่าวใน asubclass
คือเมธอดที่มีชื่อและลายเซ็นเดียวกัน คุณเพียงแค่ "ซ่อน" เมธอดของ thesuperclass
แทนที่จะแทนที่เมธอดนั้น ปรากฏการณ์นี้เรียกmethod hiding
ว่า ซึ่งหมายความว่าหากมีการประกาศเมธอดสแตติกทั้งในคลาสพาเรนต์และคลาสย่อย เมธอดที่เรียกจะขึ้นอยู่กับประเภทตัวแปรเสมอในเวลาคอมไพล์ ซึ่งแตกต่างจากการแทนที่เมธอด เมธอดดังกล่าวจะไม่ทำงานเมื่อโปรแกรมทำงาน ลองพิจารณาตัวอย่าง:class Vehicle { public static void kmToMiles(int km) { System.out.println("Inside the parent class / static method"); } } class Car extends Vehicle { public static void kmToMiles(int km) { System.out.println("Inside the child class / static method"); } } public class Demo { public static void main(String args []) { Vehicle v = new Car(); v.kmToMiles(10); } }
เอาต์พุตคอนโซล:
ภายในคลาสพาเรนต์ / เมธอดสแตติก
รหัสแสดงให้เห็นอย่างชัดเจนว่าแม้ว่าวัตถุจะเป็น a ก็ตาม
Car
วิธีการแบบสแตติกในVehicle
คลาสนั้นถูกเรียก เนื่องจากเมธอดถูกเรียกในเวลาคอมไพล์ และโปรดทราบว่าไม่มีข้อผิดพลาดในการรวบรวม! -
ยิ่งไปกว่านั้น นอกจากคลาสระดับบนสุดแล้ว คุณสามารถประกาศคลาสแบบสแตติกได้ คลาสดังกล่าวเรียก
nested static classes
ว่า พวกมันมีประโยชน์สำหรับการประสานกันที่ดีขึ้น ตัวอย่างที่โดดเด่นของคลาสสแตติกที่ซ้อนกันคือHashMap.Entry
ซึ่งเป็นโครงสร้างข้อมูลHashMap
ภายใน เป็นที่น่าสังเกตว่าเช่นเดียวกับคลาสภายใน คลาสที่ซ้อนกันแบบสแตติกจะถูกประกาศในไฟล์ .class แยกต่างหาก ดังนั้น หากคุณประกาศคลาสที่ซ้อนกัน 5 คลาสในคลาสหลัก คุณจะมีไฟล์ 6 ไฟล์ที่มีนามสกุล .class อีกตัวอย่างหนึ่งคือการประกาศของเราเองComparator
เช่น ตัวเปรียบเทียบอายุ (AgeComparator
) ในEmployee
ชั้นเรียน -
นอกจากนี้ยังสามารถระบุตัวดัดแปลงแบบคงที่ในบล็อกแบบคงที่หรือที่รู้จักกันดีในชื่อ "บล็อกการกำหนดค่าเริ่มต้นแบบคงที่" ซึ่งจะดำเนินการเมื่อโหลดคลาส หากคุณไม่ประกาศบล็อกดังกล่าว Java จะรวบรวมฟิลด์สแตติกทั้งหมดไว้ในรายการเดียวและเริ่มต้นเมื่อคลาสถูกโหลด บล็อกแบบคงที่ไม่สามารถโยนข้อยกเว้นที่ตรวจสอบได้ แต่สามารถโยนข้อยกเว้นที่ไม่ได้ตรวจสอบได้ ในกรณีนี้
ExceptionInInitializerError
จะเกิดขึ้น ในทางปฏิบัติ ข้อยกเว้นใดๆ ที่เกิดขึ้นระหว่างการเริ่มต้นของฟิลด์สแตติกจะถูกรวมไว้ในข้อผิดพลาดนี้โดย Java นี่เป็นสาเหตุที่พบบ่อยที่สุดของNoClassDefFoundError
เนื่องจากคลาสจะไม่อยู่ในหน่วยความจำเมื่อมีการอ้างอิง -
การรู้ว่าเมธอดสแตติกถูกเชื่อมโยงในเวลาคอมไพล์ ซึ่งต่างจากการลิงก์เมธอดเสมือนหรือไม่ใช่สแตติก ซึ่งจะเชื่อมโยงในขณะรันเมื่อเรียกบนอ็อบเจกต์จริง มีประโยชน์ ดังนั้นจึงไม่สามารถแทนที่เมธอดสแตติกใน Java ได้ เนื่องจากโพลิมอร์ฟิซึมไม่ได้ใช้กับเมธอดเหล่านี้ในขณะรันไทม์ นี่เป็นข้อจำกัดที่สำคัญที่ต้องพิจารณาเมื่อประกาศเมธอดสแตติก การทำเช่นนั้นสมเหตุสมผลก็ต่อเมื่อไม่มีความสามารถหรือจำเป็นต้องแทนที่เมธอดในคลาสย่อย วิธีการจากโรงงานและวิธีการยูทิลิตี้เป็นตัวอย่างที่ดีของการใช้ตัวแก้ไขแบบคงที่อย่างเหมาะสม Joshua Blochชี้ให้เห็นข้อดีหลายประการที่วิธีการแบบโรงงานแบบคงที่มีมากกว่าตัวสร้างในหนังสือ Java ของเขาที่มีประสิทธิภาพ ซึ่งเป็นข้อบังคับสำหรับโปรแกรมเมอร์ Java ทุกคน
-
การเริ่มต้นเป็นสิ่งสำคัญของบล็อกแบบคงที่ ฟิลด์หรือตัวแปรสแตติกจะถูกเตรียมใช้งานหลังจากโหลดคลาสลงในหน่วยความจำ ลำดับของการเริ่มต้นคือจากบนลงล่าง ตามลำดับเดียวกับที่ประกาศไว้ในซอร์สไฟล์ของคลาส Java เนื่องจากฟิลด์สแตติกถูกเตรียมใช้งานในลักษณะที่ปลอดภัยสำหรับเธรด กระบวนการนี้จึงถูกใช้เพื่อนำ
Singleton
รูปแบบ ไปใช้ด้วย หากคุณไม่ได้ใช้ anEnum
ด้วยSingleton
เหตุผลบางประการ แสดงว่าคุณมีทางเลือกอื่นที่ดี แต่ในกรณีนี้ คุณต้องคำนึงว่านี่ไม่ใช่การเริ่มต้นที่ "ขี้เกียจ" ซึ่งหมายความว่าฟิลด์สแตติกจะเริ่มต้นได้ก่อนที่จะมีคน "ขอ" ให้ หากออบเจกต์ใช้ทรัพยากรจำนวนมากหรือไม่ค่อยได้ใช้ การเริ่มต้นวัตถุนั้นในบล็อกแบบสแตติกจะไม่เป็นประโยชน์กับคุณ -
ในระหว่างการทำให้เป็นอนุกรม ฟิลด์สแตติก เช่น
transient
ตัวแปร จะไม่ถูกทำให้เป็นอนุกรม แน่นอน หากคุณบันทึกข้อมูลใดๆ ลงในฟิลด์สแตติก ข้อมูลนั้นจะมีค่าเริ่มต้น (ดีฟอลต์) หลังจากดีซีเรียลไลเซชัน ตัวอย่างเช่น ถ้าฟิลด์สแตติกเป็น ค่าint
ของฟิลด์นั้นจะเป็นศูนย์หลังจากการดีซีเรียลไลเซชัน หากเป็นประเภทfloat
ค่าจะเป็น 0.0 ถ้าฟิลด์เป็น anObject
ค่าจะnull
เป็น พูดตามตรง นี่เป็นคำถามที่พบบ่อยที่สุดคำถามหนึ่งเกี่ยวกับการออกหมายเลขกำกับในการสัมภาษณ์ตำแหน่งงาน Java อย่าเก็บข้อมูลอ็อบเจกต์ที่จำเป็นในฟิลด์คงที่! -
สุดท้ายเรามาพูดถึงการนำเข้าแบบคงที่ โมดิฟายเออร์นี้มีหลายอย่างที่เหมือนกันกับ
import
คำสั่งมาตรฐาน แต่จะแตกต่างกันตรงที่อนุญาตให้คุณนำเข้าสมาชิกคลาสสแตติกหนึ่งหรือทั้งหมด เมื่ออิมพอร์ตเมธอดสแตติกแล้ว จะสามารถเข้าถึงได้เหมือนกับว่าประกาศไว้ในคลาสเดียวกัน ในทำนองเดียวกัน โดยการนำเข้าฟิลด์สแตติก เราสามารถเข้าถึงได้โดยไม่ต้องระบุชื่อคลาส คุณลักษณะนี้ปรากฏใน Java 1.5 และปรับปรุงการอ่านรหัสเมื่อใช้อย่างถูกต้อง โครงสร้างนี้พบบ่อยที่สุดในการทดสอบ JUnit เนื่องจากผู้พัฒนาทดสอบเกือบทั้งหมดใช้การนำเข้าแบบคงที่สำหรับวิธีการยืนยัน เช่นassertEquals()
และตัวแปรที่โอเวอร์โหลด -
นั่นคือทั้งหมดที่สำหรับตอนนี้. โปรแกรมเมอร์ Java ทุกคนจำเป็นต้องรู้ทุกแง่มุมของสแตติกโมดิฟายเออร์ที่กล่าวถึงข้างต้น บทความนี้ทบทวนข้อมูลพื้นฐานเกี่ยวกับตัวแปรคงที่ ฟิลด์ วิธีการ บล็อกการเริ่มต้น และการนำเข้า นอกจากนี้ยังกล่าวถึงคุณสมบัติที่สำคัญบางอย่างที่จำเป็นในการเขียนและทำความเข้าใจโปรแกรม Java ฉันหวังว่านักพัฒนาซอฟต์แวร์ทุกคนจะใช้สมาชิกแบบคงที่อย่างมีทักษะได้อย่างสมบูรณ์แบบ เพราะมันสำคัญมากสำหรับการพัฒนาซอฟต์แวร์อย่างจริงจัง"
GO TO FULL VERSION