एक स्थिर और एक गैर-स्थैतिक आरंभीकरण कोड ब्लॉक के बीच अंतर क्या है


357

मेरा प्रश्न स्थैतिक कीवर्ड के एक विशेष उपयोग के बारे में है। staticएक वर्ग के भीतर कोड ब्लॉक को कवर करने के लिए कीवर्ड का उपयोग करना संभव है जो किसी भी फ़ंक्शन से संबंधित नहीं है। उदाहरण के लिए कोड संकलन निम्नलिखित हैं:

public class Test {
    private static final int a;    
    static {
        a = 5;
        doSomething(a);
    }
    private static int doSomething(int x) {
        return (x+5);
    }
}

यदि आप staticकीवर्ड को हटाते हैं तो यह शिकायत करता है क्योंकि चर aहै final। हालांकि यह दोनों दूर करने के लिए संभव है finalऔर staticकीवर्ड्स और यह संकलन बनाते हैं।

यह मेरे लिए दोनों तरह से भ्रामक है। मुझे एक ऐसा कोड अनुभाग कैसे प्राप्त करना चाहिए जो किसी भी विधि से संबंधित नहीं है? इसे कैसे लागू करना संभव है? सामान्य तौर पर, इस उपयोग का उद्देश्य क्या है? या बेहतर, मैं इस बारे में दस्तावेज कहां से पा सकता हूं?

जवाबों:


403

स्थिर संशोधक के साथ कोड ब्लॉक एक क्लास इनिशियलाइज़र को दर्शाता है ; स्थिर बिना संशोधक कोड ब्लॉक एक है उदाहरण के प्रारंभकर्ता।

वर्ग आरम्भकों को उस क्रम में निष्पादित किया जाता है जिस क्रम में उन्हें परिभाषित किया जाता है (ऊपर नीचे, साधारण चर प्रथमाक्षरों की तरह) जब कक्षा को लोड किया जाता है (वास्तव में, जब इसे हल किया जाता है, लेकिन यह एक तकनीकी है)।

इंस्टेंसेस इनिशियलाइज़र को तब परिभाषित किया जाता है, जब क्लास को तुरंत तैयार किया जाता है, सुपर कंस्ट्रक्टर के मंगलाचरण के तुरंत बाद, कंस्ट्रक्टर कोड निष्पादित होने से पहले।

यदि आप इससे निकालते staticहैं int a, तो यह एक इंस्टेंस वेरिएबल बन जाता है, जिसे आप स्टैटिक इनिशियलाइज़र ब्लॉक से एक्सेस नहीं कर पाते हैं। यह त्रुटि के साथ संकलन करने में विफल होगा "गैर-स्थैतिक चर एक स्थिर संदर्भ से संदर्भित नहीं किया जा सकता है"।

यदि आप भी staticइनिलाइज़र ब्लॉक से हटाते हैं , तो यह एक उदाहरण इनिशियलाइज़र बन जाता है और इसलिए int aनिर्माण पर आरंभीकृत किया जाता है।


स्थिर इनिशियलाइज़र वास्तव में बाद में लागू किया जाता है, जब क्लास को इनिशियलाइज़ किया जाता है, उसके बाद इसे लोड और लिंक किया जाता है। ऐसा तब होता है जब आप किसी कक्षा की किसी वस्तु को तुरंत भेज देते हैं या कक्षा पर एक स्थिर चर या विधि का उपयोग करते हैं। वास्तव में अगर आपके पास एक स्टैटिक इनिशियलाइज़र और एक विधि है public static void staticMethod(){}, यदि आप निष्पादित करते हैं TestStatic.class.getMethod("staticMethod");। स्थिर इनिशियलाइज़र को लागू नहीं किया जाएगा। अधिक जानकारी यहाँ docs.oracle.com/javase/specs/jvms/se10/html/...
टोटो

@ टोट @: हाँ, यही है कि कक्षा का रिज़ॉल्यूशन उलट जाता है (कम से कम वे इसे तब संदर्भित करते थे जब लिंक + इनिट "रिज़ॉल्यूशन" के रूप में वापस आ जाता है)। मुझे आश्चर्य नहीं है कि आप किसी वर्ग के बारे में चीजों को खोजने के लिए प्रतिबिंब का उपयोग कर सकते हैं, बिना हल किए।
लॉरेंस डॉल

166

उफ़! स्टैटिक इनिशियलाइज़र क्या है?

स्टैटिक इनिशियलाइज़र static {}जावा क्लास के अंदर कोड का एक ब्लॉक है, और कंस्ट्रक्टर या मुख्य विधि को कॉल करने से पहले केवल एक बार चलाएं।

ठीक! मुझे और बताओ...

  • static { ... }किसी भी जावा वर्ग के अंदर कोड का एक ब्लॉक है । और आभासी मशीन द्वारा निष्पादित जब कक्षा कहा जाता है।
  • कोई returnकथन समर्थित नहीं है।
  • कोई तर्क समर्थित नहीं हैं।
  • नहीं thisया superसमर्थित हैं।

हम्म मैं इसका इस्तेमाल कहां कर सकता हूं?

इस्तेमाल किया जा सकता है कहीं भी आप ठीक लग रहा है :) कि सरल। लेकिन मैं ज्यादातर समय इसका उपयोग डेटाबेस कनेक्शन, एपीआई इनिट, लॉगिंग और आदि करते समय देखता हूं।

सिर्फ छाल मत करो! उदाहरण कहाँ है?

package com.example.learnjava;

import java.util.ArrayList;

public class Fruit {

    static {
        System.out.println("Inside Static Initializer.");

        // fruits array
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Pear");

        // print fruits
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        System.out.println("End Static Initializer.\n");
    }

    public static void main(String[] args) {
        System.out.println("Inside Main Method.");
    }
}

आउटपुट ???

स्टैटिक इनिशियलाइज़र के अंदर।

सेब

संतरा

नाशपाती

एंड स्टेटिक इनिशिएटिव।

मुख्य विधि के अंदर।

उम्मीद है की यह मदद करेगा!


धन्यवाद मदन! क्या स्थैतिक ब्लॉक का उपयोग किया जा सकता afterPropertiesSet()है InitializingBean?
अलेक्जेंडर सुरफेल

3
हाँ तुम कर सकते हो! जब क्लास को jvm द्वारा लोड किया जाता है, तो स्टेटिक इनिशियलाइज़र कहा जाता है। तो इसका वास्तव में पहला चरण जहां कोड निष्पादित होता है। यदि आपके पास एक कंस्ट्रक्टर भी है, तो ऑर्डर होगा: स्टैटिक इनिशियलाइज़र, कंस्ट्रक्टर, afterPropertiesSet
मार्टिन बॉमगार्टनर

57

staticब्लॉक एक "स्थिर प्रारंभकर्ता" है।

जब क्लास लोड हो जाती है, तो यह स्वचालित रूप से लागू होता है, और इसे लागू करने का कोई अन्य तरीका नहीं है (यहां तक ​​कि प्रतिबिंब के माध्यम से भी नहीं)।

मैंने JNI कोड लिखते समय केवल व्यक्तिगत रूप से कभी इसका उपयोग किया है:

class JNIGlue {
    static {
        System.loadLibrary("foo");
    }
}

6
नहींं, इसे लागू करने का कोई स्पष्ट तरीका नहीं है, वर्ग इनिशियलाइज़र को कभी भी एक Methodउदाहरण द्वारा प्रस्तुत नहीं किया जाता है, लेकिन केवल जावा वर्चुअल मशीन द्वारा इनवॉइस किया जाता है।
राफेल विंटरहेल्टर

46

यह सीधे http://www.programcreek.com/2011/10/java-class-instance-initializers/ से है

1. निष्पादन आदेश

निम्नलिखित वर्ग को देखें, क्या आप जानते हैं कि कौन सा पहले निष्पादित होता है?

public class Foo {

    //instance variable initializer
    String s = "abc";

    //constructor
    public Foo() {
        System.out.println("constructor called");
    }

    //static initializer
    static {
        System.out.println("static initializer called");
    }

    //instance initializer
    {
        System.out.println("instance initializer called");
    }

    public static void main(String[] args) {
        new Foo();
        new Foo();
    }
}

आउटपुट:

स्टैटिक इनिशियलाइज़र कहलाता है

उदाहरण इनिशाइज़र कहा जाता है

कंस्ट्रक्टर कहा जाता है

उदाहरण इनिशाइज़र कहा जाता है

कंस्ट्रक्टर कहा जाता है

2. जावा इंस्टालाइज़र कैसे काम करता है?

ऊपर दिए गए उदाहरण इनिशलाइज़र में एक प्रिंटल स्टेटमेंट होता है। यह समझने के लिए कि यह कैसे काम करता है, हम इसे एक चर असाइनमेंट स्टेटमेंट के रूप में मान सकते हैं, जैसे,b = 0 । यह समझना अधिक स्पष्ट कर सकता है।

के बजाय

int b = 0, आप लिख सकते हैं

int b;
b = 0;

इसलिए, उदाहरण के शुरुआती और उदाहरण चर शुरुआती बहुत अधिक हैं।

3. उदाहरण के लिए इनिशियलाइज़र कब उपयोगी होते हैं?

उदाहरण इनिशियलएज़र का उपयोग दुर्लभ है, लेकिन फिर भी यह वैरिएबल इनिशियलाइज़र के लिए एक उपयोगी विकल्प हो सकता है यदि:

  1. शुरुआती कोड को अपवादों को संभालना होगा
  2. ऐसी गणनाएँ करें जिन्हें एक उदाहरण चर आरंभीकरण के साथ व्यक्त नहीं किया जा सकता है।

बेशक, इस तरह के कोड को कंस्ट्रक्टरों में लिखा जा सकता है। लेकिन यदि किसी वर्ग के पास कई कंस्ट्रक्टर हैं, तो आपको प्रत्येक कंस्ट्रक्टर में कोड दोहराना होगा।

एक उदाहरण इनिशलाइज़र के साथ, आप बस एक बार कोड लिख सकते हैं, और यह निष्पादित किया जाएगा कि कोई फर्क नहीं पड़ता कि क्या निर्माता का उपयोग ऑब्जेक्ट बनाने के लिए किया जाता है। (मुझे लगता है कि यह सिर्फ एक अवधारणा है, और इसका उपयोग अक्सर नहीं किया जाता है।)

एक और मामला जिसमें उदाहरण के लिए शुरुआती उपयोगी होते हैं, अनाम आंतरिक वर्ग होते हैं, जो किसी भी निर्माता को बिल्कुल भी घोषित नहीं कर सकते हैं। (क्या यह लॉगिंग फंक्शन लगाने के लिए एक अच्छी जगह होगी?)

डेहरिन को धन्यवाद।

यह भी ध्यान दें कि इंटरफेस को लागू करने वाले बेनामी वर्गों [1] का कोई निर्माता नहीं है। इसलिए निर्माण के समय किसी भी प्रकार के भाव को निष्पादित करने के लिए उदाहरण के लिए इनिशियलाइज़र की आवश्यकता होती है।


12

"अंतिम" इस बात की गारंटी देता है कि ऑब्जेक्ट इनिशियल कोड के अंत से पहले एक वैरिएबल को इनिशियलाइज़ किया जाना चाहिए। इसी तरह "स्टैटिक फाइनल" की गारंटी है कि एक वैरिएबल को क्लास इनिशियलाइज़ेशन कोड के अंत में इनिशियलाइज़ किया जाएगा। अपने इनिशियलाइज़ेशन कोड से "स्टैटिक" को स्वीकार करने से यह ऑब्जेक्ट इनिशियलाइज़ेशन कोड में बदल जाता है; इस प्रकार आपका चर अब इसकी गारंटी को संतुष्ट नहीं करता है।


8

आप एक स्थिर ब्लॉक में कोड नहीं लिखेंगे जिसे आपके कार्यक्रम में कहीं भी लागू करने की आवश्यकता है। यदि कोड का उद्देश्य लागू करना है तो आपको इसे एक विधि में रखना होगा।

जब क्लास लोड होती है तो आप स्थिर वैरिएबल ब्लॉक करने के लिए स्टैटिक इनिशियलाइज़र ब्लॉक लिख सकते हैं लेकिन यह कोड अधिक जटिल हो सकता है।

एक स्टैटिक इनिशियलाइज़र ब्लॉक बिना नाम, कोई तर्क और कोई वापसी प्रकार के साथ एक विधि की तरह दिखता है। चूंकि आप इसे कभी नहीं कहते हैं, इसलिए इसे एक नाम की आवश्यकता नहीं है। वर्चुअल मशीन क्लास को लोड करने के समय केवल इसका नाम है।


6

जब कोई डेवलपर एक इनिलाइज़र ब्लॉक का उपयोग करता है, तो जावा कंपाइलर इनिशियलाइज़र को वर्तमान क्लास के प्रत्येक कंस्ट्रक्टर में कॉपी करता है।

उदाहरण:

निम्नलिखित कोड:

class MyClass {

    private int myField = 3;
    {
        myField = myField + 2;
        //myField is worth 5 for all instance
    }

    public MyClass() {
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

के बराबर है:

class MyClass {

    private int myField = 3;

    public MyClass() {
        myField = myField + 2;
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        myField = myField + 2;
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

मुझे आशा है कि मेरा उदाहरण डेवलपर्स द्वारा समझा गया है।


4

स्थिर कोड ब्लॉक का उपयोग क्लास चर (ऑब्जेक्ट चर के विपरीत) को आरंभ या आरंभ करने के लिए किया जा सकता है। इसलिए "स्थिर" घोषित करने का मतलब है कि सभी टेस्ट ऑब्जेक्ट्स द्वारा केवल एक साझा किया जाता है, और स्टैटिक कोड ब्लॉक "ए" को केवल एक बार ही इनिशियलाइज़ करता है, जब टेस्ट क्लास पहली बार भरी जाती है, चाहे कितनी भी टेस्ट ऑब्जेक्ट्स बनी हों।


अनुवर्ती के रूप में, यदि मैं ऑब्जेक्ट का उदाहरण नहीं बनाता हूं, लेकिन इसके बजाय मैं एक सार्वजनिक स्थैतिक फ़ंक्शन को कॉल करता हूं। क्या इसका मतलब यह है कि इस सार्वजनिक फ़ंक्शन के कॉल से पहले इस ब्लॉक को निष्पादित करने की गारंटी है? धन्यवाद।
सजेरा दियारी

यदि आप कक्षा का सार्वजनिक स्थैतिक कार्य कहते हैं, तो कक्षा को पहले लोड करने की आवश्यकता है, इसलिए हाँ, स्टैटिक इनिशियलाइज़र पहले निष्पादित करेगा।
पॉल टॉम्बलिन

जब तक कि यह क्लास इनिशियलाइज़ेशन नहीं था (अप्रत्यक्ष रूप से) उस कोड को कहते थे जो इसे इस्तेमाल करने की कोशिश कर रहा है। IFYSWIM। परिपत्र निर्भरता और वह सब।
टॉम हॉल्टिन - 21

1
@ टॉम सही है - ऐसा कुछ लिखना संभव है जहां एक स्टैटिक इनिशियलाइज़र एक स्टैटिक विधि को कॉल करता है, इससे पहले कि कोई अन्य स्टैटिक इनिशियलाइज़र कहलाए, लेकिन मेरा मन इस विचार को याद करता है इसलिए मैंने कभी इस पर विचार नहीं किया।
पॉल टॉमब्लिन 21
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.