บล็อกการเริ่มต้นคงที่


265

เท่าที่ฉันเข้าใจ "บล็อกการเริ่มต้นคงที่" จะใช้ในการตั้งค่าของสนามคงที่หากไม่สามารถทำได้ในหนึ่งบรรทัด

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

ทำไมเราต้องสายนี้ในบล็อกพิเศษเช่น: static {...}?


6
ข้อเสนอแนะเล็ก ๆ น้อย ๆ แต่มันจะช่วยถ้าคุณสามารถโปรดระบุสมมติฐานของคุณอย่างชัดเจนและด้วยเหตุนี้ชี้แจงว่าคำตอบที่ถูกต้อง ครั้งแรกที่ผมอ่านคำถามของคุณผมผิดพลาดเข้าใจและคิดว่าคุณรู้ว่าความแตกต่างระหว่างVS{...} static {...}(ในกรณีนี้ Jon Skeet ตอบคำถามของคุณได้ดีขึ้นอย่างแน่นอน)
David T.

1
คำถามนี้ไม่ชัดเจน คุณมีผู้ตอบที่ตะลุมบอนและคาดเดาสิ่งที่คุณหมายถึง ลองเขียนตัวอย่างการกำหนดค่าเริ่มต้นแบบคงที่ไว้ในใจและทางเลือกของคุณอย่างชัดเจนเพื่อให้ผู้คนมีคำตอบที่ชัดเจน?
Don Hatch

คำตอบ:


430

บล็อกไม่คงที่:

{
    // Do Something...
}

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

ตัวอย่าง:

public class Test {

    static{
        System.out.println("Static");
    }

    {
        System.out.println("Non-static block");
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test t2 = new Test();
    }
}

ภาพพิมพ์นี้:

Static
Non-static block
Non-static block

107
ทำไมนี่เป็นคำตอบที่ยอมรับได้? มันไม่ได้ตอบคำถามด้วยซ้ำ
Paul Bellora

43
มันตอบคำถาม: "สิ่งนี้ถูกเรียกทุกครั้งที่สร้างคลาสบล็อกแบบสแตติกจะถูกเรียกเพียงครั้งเดียวไม่ว่าคุณจะสร้างวัตถุประเภทใดจำนวนเท่าใด"
Adam Arold

83
สำหรับผู้อ่านที่อยากรู้อยากเห็นบล็อกไม่คงที่จะถูกคัดลอกจริงโดยคอมไพเลอร์ Java ลงในตัวสร้างทุกชั้นมี ( แหล่งที่มา ) ดังนั้นยังคงเป็นหน้าที่ของผู้สร้างในการเริ่มต้นเขตข้อมูล
Martin Andersson

2
คำตอบที่ได้รับการยอมรับที่ควรจะเป็นนี้: stackoverflow.com/a/2420404/363573 คำตอบนี้นำเสนอตัวอย่างชีวิตจริงที่คุณต้องการบล็อกคงที่
เตฟาน

16
ทำไมคำตอบนี้จึงถูกลดระดับลงอย่างกระทันหัน คุณอาจไม่เห็นด้วยกับสิ่งนี้ว่าเป็นคำตอบที่ยอมรับได้ แต่มันก็ไม่ได้ผิดหรือทำให้เข้าใจผิด มันเป็นเพียงการพยายามช่วยทำความเข้าใจเกี่ยวกับโครงสร้างภาษาเหล่านี้ด้วยตัวอย่างง่ายๆ
Frederik Wordenskjold

133

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

public class Foo {
    private static final int widgets;

    static {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        widgets = first + second;
    }
}

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

ในกรณีนี้คุณสามารถใช้วิธีการคงที่แทน:

public class Foo {
    private static final int widgets = getWidgets();

    static int getWidgets() {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        return first + second;
    }
}

... แต่นั่นไม่ได้ผลเมื่อมีตัวแปรหลายตัวที่คุณต้องการกำหนดให้อยู่ในบล็อกเดียวกันหรือไม่มีเลย (เช่นถ้าคุณต้องการบันทึกบางอย่างหรืออาจเริ่มต้นไลบรารีดั้งเดิม)


1
บล็อกแบบสแตติกเกิดขึ้นก่อนที่จะกำหนดตัวแปรสแตติกหรือหลังจากนั้น private static int widgets = 0; static{widgets = 2;}
Weishi Zeng

1
อยากรู้ว่าบล็อกคงเกิดขึ้นก่อนที่จะได้รับมอบหมายตัวแปรคงที่หรือหลัง เช่นprivate static int widgets = 0; static{widgets = 2;}พบว่าการมอบหมาย '=' เกิดขึ้นตามลำดับซึ่งหมายถึงการใส่ '=' ก่อนจะได้รับมอบหมายก่อน ตัวอย่างข้างต้นจะให้ค่า 'วิดเจ็ต' เป็นค่า 2 (PS ไม่ทราบว่าสามารถแก้ไขความคิดเห็นได้ใน 5 นาที ... )
Weishi Zeng

@ WeishiZeng: ใช่นี่เป็นเอกสารในdocs.oracle.com/javase/specs/jls/se8/html/… - จุด 9
Jon Skeet

แต่คุณไม่สามารถใช้วิธีการคงที่ส่วนตัวที่มีรหัสเดียวกันกับบล็อกการเริ่มต้นคงที่และกำหนดเครื่องมือให้กับวิธีการคงที่ส่วนตัว?
Zachary Kraus

1
@Zachary: คุณหมายถึงคืนค่าและกำหนดผลลัพธ์ของการเรียกใช้เมธอดหรือไม่? ถ้าเป็นเช่นนั้นใช่ - เมื่อคุณได้รับการกำหนดให้ตรงตัวแปรหนึ่งเป็นผลมาจากบล็อก จะแก้ไขคำตอบของฉันพร้อมรายละเอียดในเวลาประมาณ 7 ชั่วโมง ...
Jon Skeet

103

นี่คือตัวอย่าง:

  private static final HashMap<String, String> MAP = new HashMap<String, String>();
  static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

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

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


4
สำหรับตัวอย่างเฉพาะนั้นบางครั้งรูปแบบวงเล็บปีกกาคู่นั้นถูก "ถูกทารุณกรรม" :)
BalusC

มันสามารถถูกทารุณกรรมได้ แต่ในทางกลับกันมันจะทำความสะอาดความยุ่งเหยิงและทำให้โค้ดบางประเภท "แข็ง" อีกเล็กน้อย ฉันเขียนโปรแกรมใน Erlang เพื่อความสนุกและคุณจะติดงอมแงมโดยไม่ต้องใช้ตัวแปรในท้องถิ่น :-)
Pointy

1
<< รหัสในส่วน "คงที่" จะถูกดำเนินการที่เวลาในการโหลดคลาสก่อนที่อินสแตนซ์ใด ๆ ของคลาสจะถูกสร้างขึ้น (และก่อนที่จะเรียกใช้วิธีการคงที่จากที่อื่น) ด้วยวิธีนี้คุณสามารถตรวจสอบให้แน่ใจว่าทรัพยากรคลาสพร้อมใช้งานแล้ว >> (ซึ่งคำตอบที่ "ชี้" ซึ่งกล่าวถึงในคำตอบข้างต้น) นี่คือจุดสำคัญมากที่จะต้องสังเกตเมื่อมันมาถึงการดำเนินการบล็อกแบบคงที่
ผู้เรียน

เราสามารถทำได้ด้วยการใช้ InitializingBean ใน after afterPropertiesSet วิธี?
egemen

48

นอกจากนี้ยังมีประโยชน์เมื่อคุณไม่ต้องการกำหนดค่าให้กับสิ่งใด ๆ เช่นการโหลดบางคลาสเพียงครั้งเดียวในระหว่างการใช้งานจริง

เช่น

static {
    try {
        Class.forName("com.example.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
    }
}

เฮ้มีประโยชน์อื่นคุณสามารถใช้มันเพื่อจัดการกับข้อยกเว้น ลองนึกภาพว่าที่getStuff()นี่มีExceptionสิ่งที่อยู่ในบล็อก catch จริงๆ :

private static Object stuff = getStuff(); // Won't compile: unhandled exception.

ดังนั้นเครื่องมือstaticเริ่มต้นมีประโยชน์ที่นี่ คุณสามารถจัดการข้อยกเว้นที่นั่น

อีกตัวอย่างหนึ่งคือการทำสิ่งต่าง ๆ ซึ่งไม่สามารถทำได้ในระหว่างการมอบหมาย:

private static Properties config = new Properties();

static {
    try { 
        config.load(Thread.currentThread().getClassLoader().getResourceAsStream("config.properties");
    } catch (IOException e) {
        throw new ExceptionInInitializerError("Cannot load properties file.", e);
    }
}

ที่จะกลับมาตัวอย่างไดรเวอร์ JDBC ใด ๆ ไดรเวอร์ JDBC ที่ดีของตัวเองนอกจากนี้ยังทำให้การใช้งานของการเริ่มต้นที่จะลงทะเบียนตัวเองในstatic DriverManagerดูสิ่งนี้และคำตอบนี้ด้วย


2
ตรงนี้เองที่วูดูอันตราย ... initializers คงที่จะดำเนินการใน clinit สังเคราะห์ () วิธีการซึ่งเป็นข้อมูลให้ตรงกันโดยปริยาย ซึ่งหมายความว่า JVM จะได้รับการล็อคในไฟล์คลาสที่เป็นปัญหา สิ่งนี้สามารถนำไปสู่การหยุดชะงักในสภาพแวดล้อมแบบมัลติเธรดหากสองคลาสพยายามโหลดซึ่งกันและกันและแต่ละอันเริ่มโหลดในเธรดอื่น ดูwww-01.ibm.com/support/docview.wss?uid=swg1IV48872
Ajax

@ Ajax: ฉันจะพิจารณาข้อผิดพลาดนี้ในไดรเวอร์ JDBC ที่เป็นปัญหาหรือในรหัสแอปพลิเคชันที่รับผิดชอบในการโหลด โดยทั่วไปแล้วในกรณีที่ไดรเวอร์ JDBC เหมาะสมตราบใดที่คุณโหลดเพียงครั้งเดียวทั่วทั้งแอปพลิเคชั่นระหว่างการเริ่มต้นแอปพลิเคชันจะไม่มีอะไรเกิดขึ้น
BalusC

แน่นอนว่ามันจะเป็นข้อผิดพลาด แต่ไม่ใช่ความผิดทั้งหมดของไดรเวอร์ JDBC บางทีไดรเวอร์อย่างไร้เดียงสามี initializers คงที่ของตัวเองและบางทีคุณอาจเริ่มต้นคลาสนี้พร้อมกับคนอื่น ๆ ในแอพของคุณและไม่ต้องเรียนบางอย่างที่ไม่คาดคิดโหลดรอบกันและตอนนี้แอพของคุณหยุดชะงัก ฉันค้นพบสิ่งนี้ด้วยการหยุดชะงักระหว่าง java.awt.AWTEvent และ sun.util.logging.PlatformLogger ฉันแตะ AWTEvent เพียงเพื่อบอกให้เรียกใช้หัวขาดและ lib อื่น ๆ โหลดการโหลด PlatformLogger ... ซึ่ง AWTEvent โหลด
Ajax

1
ทั้งชั้นเรียนทำข้อมูลให้ตรงกันในหัวข้อที่แตกต่างกันและงานสร้างของฉันหยุดชะงักไปประมาณ 1/150 ครั้ง ดังนั้นตอนนี้ฉันระมัดระวังมากขึ้นในการโหลดคลาสในบล็อกแบบสแตติก ในกรณีที่ฉันกล่าวถึงข้างต้นโดยใช้รูปแบบตัวให้บริการที่เลื่อนเวลาซึ่งฉันสามารถสร้างคลาสตัวให้บริการระหว่างกาลได้ทันที (โดยไม่มีโอกาสเกิดการชะงักงัน) เริ่มต้นเขตข้อมูลและจากนั้นเมื่อมีการเข้าถึงจริง จากนั้นฉันก็โหลดคลาสที่สามารถทำให้เกิดการหยุดชะงัก
Ajax

11

ฉันจะบอกว่าstatic blockเป็นเพียงน้ำตาลวากยสัมพันธ์ ไม่มีอะไรที่คุณสามารถทำได้กับstaticบล็อกและไม่ได้มีอะไรอย่างอื่น

หากต้องการใช้ตัวอย่างที่โพสต์ที่นี่อีกครั้ง

โค้ดนี้สามารถเขียนใหม่ได้โดยไม่ต้องใช้staticinitializer

วิธีที่ # 1: ด้วย static

private static final HashMap<String, String> MAP;
static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

วิธีที่ # 2: ไม่ static

private static final HashMap<String, String> MAP = getMap();
private static HashMap<String, String> getMap()
{
    HashMap<String, String> ret = new HashMap<>();
    ret.put("banana", "honey");
    ret.put("peanut butter", "jelly");
    ret.put("rice", "beans");
    return ret;
}

10

มีเหตุผลจริงสองสามประการที่จำเป็นต้องมีอยู่:

  1. การเริ่มต้นstatic finalสมาชิกที่การเตรียมใช้งานอาจมีข้อผิดพลาด
  2. การเริ่มต้นstatic finalสมาชิกด้วยค่าที่คำนวณได้

ผู้คนมักจะใช้static {}บล็อคเป็นวิธีที่สะดวกในการเริ่มต้นสิ่งต่าง ๆ ที่คลาสขึ้นอยู่กับในรันไทม์เช่นกัน - เพื่อให้แน่ใจว่ามีการโหลดคลาสเฉพาะ (เช่นไดรเวอร์ JDBC) สามารถทำได้ในรูปแบบอื่น อย่างไรก็ตามสองสิ่งที่ฉันพูดถึงข้างต้นสามารถทำได้โดยการสร้างเช่นstatic {}บล็อกเท่านั้น


8

คุณสามารถดำเนินการบิตของรหัสหนึ่งครั้งสำหรับคลาสก่อนที่วัตถุจะถูกสร้างขึ้นในบล็อกคงที่

เช่น

class A {
  static int var1 = 6;
  static int var2 = 9;
  static int var3;
  static long var4;

  static Date date1;
  static Date date2;

  static {
    date1 = new Date();

    for(int cnt = 0; cnt < var2; cnt++){
      var3 += var1;
    }

    System.out.println("End first static init: " + new Date());
  }
}

7

เป็นความเข้าใจผิดที่พบโดยทั่วไปว่าบล็อกคงมีเพียงการเข้าถึงฟิลด์คงที่ สำหรับสิ่งนี้ฉันต้องการแสดงโค้ดด้านล่างซึ่งฉันมักใช้ในโครงการในชีวิตจริง (คัดลอกบางส่วนจากคำตอบอื่นในบริบทที่แตกต่างกันเล็กน้อย):

public enum Language { 
  ENGLISH("eng", "en", "en_GB", "en_US"),   
  GERMAN("de", "ge"),   
  CROATIAN("hr", "cro"),   
  RUSSIAN("ru"),
  BELGIAN("be",";-)");

  static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>(); 
  static { 
    for (Language l:Language.values()) { 
      // ignoring the case by normalizing to uppercase
      ALIAS_MAP.put(l.name().toUpperCase(),l); 
      for (String alias:l.aliases) ALIAS_MAP.put(alias.toUpperCase(),l); 
    } 
  } 

  static public boolean has(String value) { 
    // ignoring the case by normalizing to uppercase
    return ALIAS_MAP.containsKey(value.toUpper()); 
  } 

  static public Language fromString(String value) { 
    if (value == null) throw new NullPointerException("alias null"); 
    Language l = ALIAS_MAP.get(value); 
    if (l == null) throw new IllegalArgumentException("Not an alias: "+value); 
    return l; 
  } 

  private List<String> aliases; 
  private Language(String... aliases) { 
    this.aliases = Arrays.asList(aliases); 
  } 
} 

ที่นี่ initializer จะใช้ในการรักษาดัชนี ( ALIAS_MAP) เพื่อแมปชุดของชื่อแทนกลับไปที่ประเภท Enum ดั้งเดิม มันมีวัตถุประสงค์เพื่อเป็นส่วนขยายไปยังวิธีการ valueOf ในตัวที่จัดทำโดยEnumตัวมันเอง

ในขณะที่คุณสามารถดู initializer คงเข้าถึงแม้ฟิลด์private aliasesสิ่งสำคัญคือต้องเข้าใจว่าstaticบล็อกนั้นมีการเข้าถึงEnumอินสแตนซ์ของค่า (เช่นENGLISH) นี่เป็นเพราะลำดับของการเริ่มต้นและการดำเนินการในกรณีที่เป็นEnumประเภทเช่นเดียวกับstatic privateเขตข้อมูลที่ได้รับการเริ่มต้นด้วยอินสแตนซ์ก่อนที่จะstaticมีการเรียกบล็อก:

  1. Enumค่าคงที่ซึ่งเป็นสาขาที่คงที่โดยปริยาย สิ่งนี้ต้องใช้คอนสตรัคเตอร์ Enum และอินสแตนซ์บล็อกและการเริ่มต้นอินสแตนซ์ให้เกิดขึ้นก่อนเช่นกัน
  2. static บล็อกและการเริ่มต้นของฟิลด์คงที่ในลำดับของการเกิดขึ้น

การกำหนดค่าเริ่มต้นที่staticไม่เป็นไปตามคำสั่ง (ตัวสร้างก่อนบล็อก) เป็นสิ่งสำคัญที่ควรทราบ นอกจากนี้ยังเกิดขึ้นเมื่อเราเริ่มต้นเขตข้อมูลคงที่ด้วยอินสแตนซ์ที่คล้ายกับ Singleton (ทำให้เข้าใจง่าย):

public class Foo {
  static { System.out.println("Static Block 1"); }
  public static final Foo FOO = new Foo();
  static { System.out.println("Static Block 2"); }
  public Foo() { System.out.println("Constructor"); }
  static public void main(String p[]) {
    System.out.println("In Main");
    new Foo();
  }
}

สิ่งที่เราเห็นคือผลลัพธ์ต่อไปนี้:

Static Block 1
Constructor
Static Block 2
In Main
Constructor

ชัดเจนว่าการเริ่มต้นคงที่สามารถเกิดขึ้นจริงก่อนที่จะสร้างและแม้หลังจาก:

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ดูหนังสือ " Java ที่มีประสิทธิภาพ "


1
การเข้าถึงaliasesไม่ได้หมายความว่าบล็อกแบบสแตติกสามารถเข้าถึงสมาชิกที่ไม่ใช่สมาชิก aliasesถูกเข้าถึงผ่านLanguageค่าที่ส่งคืนโดย / static / values()method ดังที่คุณพูดถึงความจริงที่ว่าตัวแปร enum นั้นมีอยู่แล้ว ณ จุดนั้นคือบิตที่ผิดปกติ - สมาชิกที่ไม่คงที่ของคลาสปกติจะไม่สามารถเข้าถึงได้ในสถานการณ์นี้
Ignazio

บล็อกแบบสแตติกยังคงเข้าถึงเฉพาะฟิลด์แบบคงที่ (ในกรณีของ enum ENGLISH, GERMAN, ... ) ซึ่งในกรณีนี้เป็นวัตถุ เนื่องจากฟิลด์สแตติกเป็นวัตถุเองคุณสามารถเข้าถึงฟิลด์อินสแตนซ์ของวัตถุแบบสแตติก
สวามี PR

1
class Foo { static final Foo Inst1; static final Foo Inst2; static{ Inst1 = new Foo("Inst1"); Inst2 = new Foo("Inst2"); } static { System.out.println("Inst1: " + Inst1.member); System.out.println("Inst2: " + Inst2.member); } private final String member; private Foo(String member){ this.member = member; } } โค้ดด้านบนไม่แตกต่างจากตัวอย่าง enum และยังอนุญาตให้เข้าถึงตัวแปรอินสแตนซ์ภายในบล็อกแบบคงที่
Swami PR

@SwamiPR แน่นอนมันรวบรวมแปลกใจของฉันและฉันต้องยอมรับว่ารหัสในหลักการไม่แตกต่างกัน ฉันต้องอ่านข้อกำหนด Java อีกครั้งฉันรู้สึกว่ามีบางอย่างที่ฉันพลาด ตอบรับที่ดีขอบคุณ
YoYo

@SwamiPR Enumปัญหาจริงๆก็คือว่าเราควรจะใช้ มันเป็นวิธีที่ดีที่สุดที่จะรับประกันว่าเราจะชี้ไปที่กรณีเอกพจน์ - ดูที่นี่ และสำหรับคะแนนของคุณฉันได้ทำการอัปเดตหลายครั้ง
YoYo

3

หากจำเป็นต้องตั้งค่าตัวแปรสแตติกของคุณตอนรันไทม์การstatic {...}บล็อกจะมีประโยชน์มาก

ตัวอย่างเช่นหากคุณต้องการตั้งค่าสมาชิกแบบสแตติกเป็นค่าที่เก็บไว้ในไฟล์ config หรือฐานข้อมูล

ยังมีประโยชน์เมื่อคุณต้องการเพิ่มค่าให้กับMapสมาชิกแบบคงที่เนื่องจากคุณไม่สามารถเพิ่มค่าเหล่านี้ในการประกาศสมาชิกเริ่มต้น


3

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

1- เพียงเริ่มต้นเมื่อคุณประกาศตัวแปร:

static int x = 3;

2- มีบล็อกการเริ่มต้นแบบคงที่:

static int x;

static {
 x=3;
}

3- มีวิธีการเรียน (วิธีการคงที่) ที่เข้าถึงตัวแปรระดับและเริ่มต้นมัน: นี่คือทางเลือกในการบล็อกคงข้างต้น; คุณสามารถเขียนวิธีการคงที่ส่วนตัว:

public static int x=initializeX();

private static int initializeX(){
 return 3;
}

ทีนี้ทำไมคุณถึงต้องใช้การเริ่มต้นบล็อกแบบคงที่แทนที่จะเป็นวิธีการแบบคงที่?

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

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

หมายเหตุ: บล็อกแบบสแตติกจะถูกเรียกตามลำดับที่ปรากฏในรหัส

ตัวอย่างที่ 1:

class A{
 public static int a =f();

// this is a static method
 private static int f(){
  return 3;
 }

// this is a static block
 static {
  a=5;
 }

 public static void main(String args[]) {
// As I mentioned, you do not need to create an instance of the class to use the class variable
  System.out.print(A.a); // this will print 5
 }

}

ตัวอย่างที่ 2:

class A{
 static {
  a=5;
 }
 public static int a =f();

 private static int f(){
  return 3;
 }

 public static void main(String args[]) {
  System.out.print(A.a); // this will print 3
 }

}

0

ในฐานะที่เป็นส่วนเสริมเช่น @Pointy กล่าว

รหัสในส่วน "คงที่" จะถูกดำเนินการที่เวลาในการโหลดคลาสก่อนที่อินสแตนซ์ใด ๆ ของคลาสจะถูกสร้างขึ้น

มันควรจะเพิ่มSystem.loadLibrary("I_am_native_library")ลงในบล็อกคงที่

static{
    System.loadLibrary("I_am_a_library");
}

มันจะรับประกันว่าจะไม่มีการเรียกใช้วิธีดั้งเดิมก่อนที่จะโหลดไลบรารีที่เกี่ยวข้องลงในหน่วยความจำ

ตามloadLibrary จาก oracle :

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

ดังนั้นค่อนข้างคาดไม่ถึงการวาง System.loadLibrary ไม่ได้ใช้เพื่อหลีกเลี่ยงการโหลดไลบรารีหลายครั้ง


0

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

public class Main {

    private static int myInt;

    static {
        myInt = 1;
        System.out.println("myInt is 1");
    }

    //  needed only to run this class
    public static void main(String[] args) {
    }

}

และมันจะพิมพ์ "myInt is 1" ไปยังคอนโซล โปรดทราบว่าฉันไม่ได้ยกตัวอย่างคลาสใด ๆ


0
static int B,H;
static boolean flag = true;
static{
    Scanner scan = new Scanner(System.in);
    B = scan.nextInt();
    scan.nextLine();
    H = scan.nextInt();

    if(B < 0 || H < 0){
        flag = false;
        System.out.println("java.lang.Exception: Breadth and height must be positive");
    } 
}

-1

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

Eg:-class Solution{
         // static int x=10;
           static int x;
       static{
        try{
          x=System.out.println();
          }
         catch(Exception e){}
        }
       }

     class Solution1{
      public static void main(String a[]){
      System.out.println(Solution.x);
        }
        }

ตอนนี้ int แบบคงที่ของฉัน x จะเริ่มต้นแบบไดนามิก .. BCOz เมื่อคอมไพเลอร์จะไปที่ Solution.x มันจะโหลด Solution Class และโหลดบล็อกคงที่ในเวลาที่โหลดระดับ .. ดังนั้นเราสามารถเริ่มต้นสมาชิกแบบคงที่ข้อมูลแบบไดนามิก ..

}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.