คำแนะนำเกี่ยวกับ Static Keyword ใน Java

1. บทนำ

ในบทความนี้เราจะสำรวจคำหลักแบบคงที่ของภาษา Java โดยละเอียด เราจะพบว่าเราสามารถใช้คีย์เวิร์ดสแตติกกับตัวแปรเมธอดบล็อกคลาสที่ซ้อนกันได้อย่างไรและสร้างความแตกต่างอย่างไร

2. กายวิภาคของคำหลักแบบคงที่

ในภาษาการเขียนโปรแกรม Java คีย์เวิร์ดstaticระบุว่าสมาชิกเฉพาะนั้นเป็นของชนิดเองแทนที่จะเป็นอินสแตนซ์ของประเภทนั้น

ซึ่งหมายความว่ามีเพียงอินสแตนซ์เดียวของสมาชิกแบบคงที่เท่านั้นที่ถูกสร้างขึ้นซึ่งใช้ร่วมกันในทุกอินสแตนซ์ของคลาส

คีย์เวิร์ดสามารถใช้ได้กับตัวแปรวิธีการบล็อกและคลาสที่ซ้อนกัน

3. ฟิลด์คงที่ (หรือตัวแปรคลาส)

ใน Java ถ้าเขตข้อมูลถูกประกาศแบบคงที่สำเนาเดียวของฟิลด์นั้นจะถูกสร้างและแบ่งใช้ระหว่างอินสแตนซ์ทั้งหมดของคลาสนั้น ไม่สำคัญว่าเราจะเริ่มต้นคลาสกี่ครั้ง จะมีเพียงสำเนาเดียวของเขตข้อมูลคงที่เป็นของมัน ค่าของฟิลด์คงที่นี้จะถูกแบ่งใช้กับอ็อบเจ็กต์ทั้งหมดของคลาสเดียวกัน

จากมุมมองของหน่วยความจำตัวแปรแบบคงที่จะอยู่ในพูลเฉพาะในหน่วยความจำ JVM ที่เรียกว่า Metaspace (ก่อน Java 8 พูลนี้เรียกว่า Permanent Generation หรือ PermGen ซึ่งถูกลบออกทั้งหมดและแทนที่ด้วย Metaspace)

3.1. ตัวอย่างของสนามคงที่

สมมติว่าเรามีรถชั้นที่มีคุณลักษณะหลายคน (เช่นตัวแปร) เมื่อใดก็ตามที่วัตถุใหม่เริ่มต้นจากพิมพ์เขียวรถนี้วัตถุใหม่แต่ละชิ้นจะมีสำเนาที่แตกต่างกันของตัวแปรอินสแตนซ์เหล่านี้

อย่างไรก็ตามสมมติว่าเรากำลังมองหาตัวแปรที่เก็บจำนวนของจำนวนวัตถุรถที่เริ่มต้นและใช้ร่วมกันในทุกอินสแตนซ์เพื่อให้สามารถเข้าถึงและเพิ่มได้เมื่อเริ่มต้น

นั่นคือที่มาของตัวแปรคงที่ :

public class Car { private String name; private String engine; public static int numberOfCars; public Car(String name, String engine) { this.name = name; this.engine = engine; numberOfCars++; } // getters and setters }

ตอนนี้สำหรับทุกออบเจ็กต์ของคลาสนี้ที่เริ่มต้นสำเนาเดียวกันของตัวแปรnumberOfCarsจะเพิ่มขึ้น ดังนั้นสำหรับกรณีนี้คำยืนยันต่อไปนี้จะเป็นจริง:

@Test public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() { new Car("Jaguar", "V8"); new Car("Bugatti", "W16"); assertEquals(2, Car.numberOfCars); }

3.2. เหตุผลที่น่าสนใจในการใช้ฟิลด์แบบคงที่

  • เมื่อค่าของตัวแปรไม่ขึ้นอยู่กับวัตถุ
  • เมื่อควรแชร์ค่ากับวัตถุทั้งหมด

3.3. ประเด็นสำคัญที่ต้องจำ

  • เนื่องจากตัวแปรคงเป็นของคลาสจึงสามารถเข้าถึงได้โดยตรงโดยใช้ชื่อคลาสและไม่ต้องการการอ้างอิงวัตถุใด ๆ
  • ตัวแปรคงที่สามารถประกาศได้ในระดับคลาสเท่านั้น
  • สามารถเข้าถึงฟิลด์แบบคงที่ได้โดยไม่ต้องเริ่มต้นอ็อบเจ็กต์
  • แม้ว่าเราจะสามารถเข้าถึงฟิลด์แบบคงที่โดยใช้การอ้างอิงอ็อบเจ็กต์ (เช่นford.numberOfCars ++ ) แต่เราก็ควรละเว้นจากการใช้งานเนื่องจากในกรณีนี้จะยากที่จะคิดว่าเป็นตัวแปรอินสแตนซ์หรือตัวแปรคลาส แทนเราควรอ้างถึงตัวแปรคงที่โดยใช้ชื่อคลาส (เช่นในกรณีนี้คือCar.numberOfCars ++ )

4. วิธีการคงที่ (หรือวิธีการคลาส)

คล้ายกับแบบคงที่เขตคงวิธีการยังอยู่ในชั้นเรียนแทนของวัตถุและเพื่อให้พวกเขาสามารถเรียกได้ว่าไม่ต้องสร้างวัตถุของคลาสที่พวกเขาอาศัยอยู่ พวกเขามีไว้เพื่อใช้โดยไม่ต้องสร้างวัตถุของคลาส

4.1. ตัวอย่างของวิธีการแบบคงที่

โดยทั่วไปจะใช้วิธีการแบบคงที่เพื่อดำเนินการที่ไม่ขึ้นอยู่กับการสร้างอินสแตนซ์

หากมีรหัสที่ควรจะใช้ร่วมกันในทุกอินสแตนซ์ของคลาสนั้นให้เขียนโค้ดนั้นด้วยวิธีการแบบคงที่ :

public static void setNumberOfCars(int numberOfCars) { Car.numberOfCars = numberOfCars; }

วิธีการคงที่ยังใช้กันอย่างแพร่หลายในการสร้างยูทิลิตี้หรือคลาสตัวช่วยเพื่อให้สามารถรับได้โดยไม่ต้องสร้างอ็อบเจ็กต์ใหม่ของคลาสเหล่านี้

เพียงแค่ดูที่คอลเลกชันหรือคณิตศาสตร์ยูทิลิตี้การเรียนจาก JDK ที่ StringUtils จาก Apache หรือ CollectionUtils จากกรอบฤดูใบไม้ผลิและแจ้งให้ทราบว่าวิธีการทั้งหมดจะคงที่

4.2. เหตุผลที่น่าสนใจในการใช้วิธีการคงที่

  • เพื่อเข้าถึง / จัดการตัวแปรคงที่และวิธีการคงที่อื่น ๆ ที่ไม่ขึ้นอยู่กับวัตถุ
  • วิธีการคงที่ใช้กันอย่างแพร่หลายในยูทิลิตี้และคลาสผู้ช่วย

4.3. ประเด็นสำคัญที่ต้องจำ

  • วิธีการแบบคงที่ใน Java ได้รับการแก้ไขในเวลาคอมไพล์ เนื่องจากการแทนที่เมธอดเป็นส่วนหนึ่งของ Runtime Polymorphism ดังนั้นจึงไม่สามารถแทนที่เมธอดแบบคงที่ได้
  • วิธีนามธรรมไม่สามารถคงที่
  • คงวิธีการไม่สามารถใช้นี้หรือซุปเปอร์คำหลัก
  • ชุดค่าผสมของอินสแตนซ์เมธอดคลาสและตัวแปรต่อไปนี้ใช้ได้:
    1. วิธีการอินสแตนซ์สามารถเข้าถึงทั้งวิธีการของอินสแตนซ์และตัวแปรอินสแตนซ์ได้โดยตรง
    2. วิธีการเช่นนี้ยังสามารถเข้าถึงได้คงที่ตัวแปรและคงวิธีการโดยตรง
    3. วิธีการคงที่สามารถเข้าถึงตัวแปรคงที่ทั้งหมดและวิธีการคงที่อื่น ๆ
    4. คงวิธีการไม่สามารถตัวแปรเช่นการเข้าถึงและวิธีการเช่นโดยตรง ; พวกเขาต้องการการอ้างอิงวัตถุเพื่อดำเนินการดังกล่าว

5. บล็อกคงที่

คงบล็อกจะใช้สำหรับการเริ่มต้นคงที่ตัวแปร แม้ว่าตัวแปรคงที่สามารถเริ่มต้นได้โดยตรงในระหว่างการประกาศ แต่ก็มีสถานการณ์ที่เราจำเป็นต้องดำเนินการประมวลผลหลายบรรทัด

ในกรณีเช่นนี้บล็อกคงที่มีประโยชน์

If static variables require additional, multi-statement logic while initialization, then a static block can be used.

5.1. The static Block Example

Suppose we want to initialize a list object with some pre-defined values.

This becomes easy with static blocks:

public class StaticBlockDemo { public static List ranks = new LinkedList(); static { ranks.add("Lieutenant"); ranks.add("Captain"); ranks.add("Major"); } static { ranks.add("Colonel"); ranks.add("General"); } }

In this example, it wouldn't be possible to initialize List object with all the initial values along with declaration; and that's why we've utilized the static block here.

5.2. Compelling Reasons to Use static Blocks

  • If initialization of static variables requires some additional logic except the assignment
  • If the initialization of static variables is error-prone and requires exception handling

5.3. Key Points to Remember

  • A class can have multiple static blocks
  • static fields and static blocks are resolved and executed in the same order as they are present in the class

6. A static Class

Java programming language allows us to create a class within a class. It provides a compelling way of grouping elements that are only going to be used in one place, this helps to keep our code more organized and readable.

The nested class architecture is divided into two:

  • nested classes that are declared static are called static nested classes whereas,
  • nested classes that are non-static are called inner classes

The main difference between these two is that the inner classes have access to all member of the enclosing class (including private), whereas the static nested classes only have access to static members of the outer class.

In fact, static nested classes behaved exactly like any other top-level class but enclosed in the only class which will access it, to provide better packaging convenience.

6.1. Example of static Class

The most widely used approach to create singleton objects is through static nested class is it doesn't require any synchronization and is easy to learn and implement:

public class Singleton { private Singleton() {} private static class SingletonHolder { public static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }

6.2. Compelling Reasons to Use a static Inner Class

  • Grouping classes that will be used only in one place increases encapsulation
  • The code is brought closer to the place that will be only one to use it; this increases readability and code is more maintainable
  • If nested class doesn't require any access to it's enclosing class instance members, then it's better to declare it as static because this way, it won't be coupled to the outer class and hence will be more optimal as they won't require any heap or stack memory

6.3. Key Points to Remember

  • static nested classes do not have access to any instance members of the enclosing outer class; it can only access them through an object's reference
  • คลาสที่ซ้อนกันแบบคงที่สามารถเข้าถึงสมาชิกแบบคงที่ทั้งหมดของคลาสที่ปิดล้อมรวมถึงไพรเวต
  • ข้อกำหนดการเขียนโปรแกรม Java ไม่อนุญาตให้เราจะประกาศชั้นระดับบนสุดเป็นแบบคงที่ ; เฉพาะคลาสภายในคลาสเท่านั้น (คลาสที่ซ้อนกัน) สามารถทำให้เป็นแบบคงที่ได้

7. สรุป

ในบทความนี้เราเห็นคำหลักคงที่ในการทำงาน นอกจากนี้เรายังอ่านเกี่ยวกับเหตุผลและข้อดีของการใช้ฟิลด์แบบคงที่วิธีการแบบคงที่บล็อกแบบคงที่และคลาสภายในแบบคงที่

เช่นเคยเราสามารถค้นหาโค้ดทั้งหมดได้ที่ GitHub