سؤال

بقدر ما أفهم أنه يستخدم "كتلة التهيئة الثابتة" لتعيين قيم الحقل الثابت إذا تعذر القيام به في سطر واحد.

لكنني لا أفهم لماذا نحتاج إلى كتلة خاصة لذلك. على سبيل المثال، نعلن حقلا ثابتا (بدون مهمة قيمة). ثم اكتب عدة أسطر من التعليمات البرمجية التي تولد وتعيين قيمة للحقل الثابت المعلن أعلاه.

لماذا نحتاج إلى هذه الخطوط في كتلة خاصة مثل: static {...}?

هل كانت مفيدة؟

المحلول

ال كتلة غير ثابتة:

{
    // 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

نصائح أخرى

إذا لم تكن في كتلة تهيئة ثابتة، فأين تكون؟ كيف تعلن متغير كان من المفترض أن يكون محليا فقط لأغراض التهيئة، وتميزه عن حقل؟ على سبيل المثال، كيف أنت تريد أن تكتب:

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;
    }
}

... ولكن هذا لا يعمل عندما يكون هناك متغيرات متعددة ترغب في تعيينها داخل الكتلة نفسها، أو لا شيء (على سبيل المثال، إذا كنت ترغب فقط في تسجيل شيء - أو ربما تهيئة مكتبة أصلية).

إليك مثال:

  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");
  }

سيتم تنفيذ التعليمات البرمجية في القسم (الأقسام) "الثابت" في وقت تحميل الفصل، قبل إنشاء أي مثيلات من الفئة (وقبل استدعاء أي طرق ثابتة من مكان آخر). وبهذه الطريقة يمكنك التأكد من أن موارد الفصل جاهزة للاستخدام.

من الممكن أيضا الحصول على كتل تهيئة غير ثابتة. يتصرف أولئك الذين يتصرفون مثل ملحقات من أساليب المنشئ المحددة للفئة. تبدو تماما مثل كتل التهيئة الثابتة، باستثناء الكلمات الرئيسية "ثابت" يتم إيقافها.

من المفيد أيضا عندما لا ترغب في الواقع في تعيين القيمة إلى أي شيء، مثل تحميل بعض الفئة مرة واحدة فقط أثناء وقت التشغيل.

على سبيل المثال

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

مهلا، هناك فائدة أخرى، يمكنك استخدامها للتعامل مع الاستثناءات. تخيل ذلك getStuff() هنا يلقي Exception أيّ هل حقا ينتمي في كتلة الصيد:

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. وبعد انظر أيضا هذه و هذه إجابه.

أود أن أقول static block هو مجرد السكر النحوي. لا يوجد شيء يمكنك القيام به static كتلة وليس مع أي شيء آخر.

لإعادة استخدام بعض الأمثلة المنشورة هنا.

يمكن إعادة كتابة هذه القطعة هذه دون استخدام static المهيئ.

الطريقة رقم 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;
}

هناك عدد قليل من الأسباب الفعلية التي يجب أن تكون موجودة

  1. جار تهيئة static final الأعضاء الذين قد تهيئة تهيئة الاستثناء
  2. جار تهيئة static final أعضاء مع القيم المحسوبة

الناس يميلون إلى استخدام static {} كتل كوسيلة مريحة لتهيئة الأشياء التي يعتمدها الفصل على ضمن وقت التشغيل أيضا - مثل ضمان تحميل فئة معينة (على سبيل المثال، برامج تشغيل JDBC). يمكن القيام به بطرق أخرى؛ ومع ذلك، يمكن القيام بالأشياء التي أذكرها أعلاه إلا مع بناء مثل static {} منع.

يمكنك تنفيذ أجزاء من التعليمات البرمجية مرة واحدة لفصل قبل إنشاء كائن في الكتل الثابتة.

على سبيل المثال

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());
  }
}

من المفهوم الخاطئ الشائع أن نعتقد أن كتلة ثابتة لديها فقط الوصول إلى الحقول الثابتة. ولهذا أود إظهار أدناه جزء من التعليمات البرمجية التي استخدمت في كثير من الأحيان في مشاريع الحياة الحقيقية (نسخ جزئيا من إجابة أخرى في سياق مختلف قليلا):

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); 
  } 
} 

هنا يتم استخدام المهيمة للحفاظ على فهرس (ALIAS_MAP)، لتعيين مجموعة من الأسماء المستعارة إلى نوع المعمنة الأصلي. من المقصود كملحق لطريقة النقاط ذات القيمة المدمجة التي يوفرها Enum بحد ذاتها.

كما ترون، فإن البرهي الثابت يصل حتى private ميدان aliases. وبعد من المهم أن نفهم أن static كتلة لديها بالفعل الوصول إلى Enum مثيلات القيمة (على سبيل المثال ENGLISH). هذا بسبب ترتيب التهيئة والتنفيذ في حالة Enum أنواع, ، كما لو كان static private تم تهيئة الحقول مع مثيلات قبل static تم استدعاء كتل:

  1. ال 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 في الطريقة الرئيسية، يؤدي إلى تحميل الفئة والتهيئة الثابتة للبدء. ولكن كجزء من التهيئة الثابتة نسمح مرة أخرى منشئين للحقول الثابتة، وبعد ذلك يستأنف التهيئة الثابتة، وإكمال المنشئ يسمى من داخل الطريقة الرئيسية. وضع معقد إلى حد ما الذي آمل أن يكون في الترميز الطبيعي لن يتعين علينا التعامل معه.

لمزيد من المعلومات حول هذا انظر الكتاب "جاوة فعالة".

إذا كانت المتغيرات الثابتة تحتاج إلى تعيين في وقت التشغيل ثم static {...} كتلة مفيدة للغاية.

على سبيل المثال، إذا كنت بحاجة إلى تعيين العضو الثابت إلى قيمة يتم تخزينها في ملف التكوين أو قاعدة البيانات.

مفيد أيضا عندما تريد إضافة قيم إلى ثابت Map عضو كما لا يمكنك إضافة هذه القيم في إعلان الأعضاء الأولي.

لذلك لديك حقل ثابت (يطلق عليه أيضا "متغير الفئة" لأنه ينتمي إلى الفصل بدلا من مثيل الفصل. وبعبارة أخرى مرتبطة بالصف بدلا من أي كائن) وترغب في تهيئة ذلك. لذلك إذا كنت لا ترغب في إنشاء مثيل من هذه الفئة، فأنت تريد معالجة هذا الحقل الثابت، يمكنك القيام بذلك بثلاث طرق:

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
 }

}

كما تكميلية، مثل نشرة قال

سيتم تنفيذ التعليمات البرمجية في القسم (الأقسام) "الثابت" في وقت تحميل الفصل، قبل إنشاء أي مثيلات من الفئة (وقبل استدعاء أي طرق ثابتة من مكان آخر).

من المفترض أن تضيف System.loadLibrary("I_am_native_library") في كتلة ثابتة.

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

سوف يضمن عدم استدعاء طريقة أصلية قبل تحميل المكتبة ذات الصلة في الذاكرة.

بالنسبة الى loadlibrary من أوراكل:

إذا كانت هذه الطريقة تسمى أكثر من مرة مع نفس اسم المكتبة، يتم تجاهل المكالمات الثانية واللاحقة.

لذلك بشكل غير متوقع للغاية، لا يستخدم وضع النظام. لا يستخدم تحميل المكتبة متعددة مرات.

تحتاج أولا إلى فهم أن فئات التطبيق الخاصة بك أنفسهم مثيل لهم 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 هو 1" إلى وحدة التحكم. لاحظ أنني لم أقنت مثيل أي فئة.

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");
    } 
}

يتم استخدام كتلة ثابتة لأي تكنولوجيا لتهيئة عضو البيانات الثابتة بطريقة ديناميكية، أو يمكننا أن نقول من أجل التهيئة الديناميكية للكتلة الثابتة لعضو البيانات الثابتة. أي مكان يمكننا تهيئة عضو البيانات الثابتة ديناميكيا

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);
        }
        }

الآن سيقوم Static Int X بتهيئة الدين الديناميك.

}

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top