जावा में स्टेटिक ब्लॉक निष्पादित नहीं किया गया


87
class Test {
    public static void main(String arg[]) {    
        System.out.println("**MAIN METHOD");
        System.out.println(Mno.VAL); // SOP(9090);
        System.out.println(Mno.VAL + 100); // SOP(9190);
    }

}

class Mno {
    final static int VAL = 9090;
    static {
        System.out.println("**STATIC BLOCK OF Mno\t: " + VAL);
    }
}

मुझे पता है कि staticक्लास लोड होने पर एक ब्लॉक निष्पादित होता है। लेकिन इस मामले में वर्ग के अंदर उदाहरण चर Mnoहै final, क्योंकि staticब्लॉक निष्पादित नहीं कर रहा है।

ऐसा क्यों हैं? और अगर मैं हटा देता final, तो क्या यह ठीक होता?

कौन सी मेमोरी पहले आवंटित की जाएगी, static finalचर या staticब्लॉक?

यदि finalपहुंच संशोधक के कारण कक्षा लोड नहीं होती है, तो चर को मेमोरी कैसे मिल सकती है?


1
आपको प्राप्त होने वाली सटीक त्रुटि और संदेश क्या है?
पताशु

@Patashu, वहाँ कोई त्रुटि इसकी एक संदेह नहीं है,
Sthita

जवाबों:


134
  1. एक static final intक्षेत्र एक संकलन-समय स्थिर है और इसका मूल्य गंतव्य वर्ग में इसकी उत्पत्ति के संदर्भ के बिना हार्डकोड किया गया है;
  2. इसलिए आपका मुख्य वर्ग फ़ील्ड वाले लोडिंग को ट्रिगर नहीं करता है;
  3. इसलिए उस वर्ग में स्थिर इनिशियलाइज़र को निष्पादित नहीं किया जाता है।

विशिष्ट विवरण में, संकलित बायटेकोड इसी से मेल खाता है:

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(9090)
    System.out.println(9190)
}

जैसे ही हटाओगे final , यह अब एक संकलन-समय स्थिर नहीं है और ऊपर वर्णित विशेष व्यवहार लागू नहीं होता है। Mnoवर्ग के रूप में आप उम्मीद और भरी हुई है कार्यान्वित प्रारंभकर्ता इसके स्थिर।


1
लेकिन, तब वर्ग को लोड किए बिना वर्ग में अंतिम चर का मूल्य कैसे मूल्यांकन किया जाता है?
सुमित देसाई

18
सभी मूल्यांकन संकलन समय पर होते हैं और अंतिम परिणाम उन सभी स्थानों पर हार्डकोड किया जाता है जो चर का संदर्भ देते हैं।
मार्को टोपोलनिक

1
इसलिए, यदि एक आदिम चर के बजाय, यह कुछ ऑब्जेक्ट है, तो ऐसा हार्डकोडिंग संभव नहीं होगा। है ना? तो क्या उस स्थिति में, उस वर्ग को लोड किया जाएगा और स्थिर ब्लॉक निष्पादित किया जाएगा?
सुमित देसाई

2
मार्को, सुमित का शक सही भी है अगर आदिम के बजाय यह कुछ ऑब्जेक्ट है, तो ऐसे हार्डकोडिंग संभव नहीं होगा। है ना? तो, उस स्थिति में, क्या उस वर्ग को लोड किया जाएगा और स्थिर ब्लॉक निष्पादित किया जाएगा?
Sthita

8
@SumitDesai वास्तव में, यह केवल आदिम मूल्यों और स्ट्रिंग शाब्दिक के लिए काम करता है। पूर्ण विवरण के लिए जावा लैंग्वेज स्पेसिफिकेशन में संबंधित अध्याय
मार्को टॉपोलनिक

8

कारण है कि वर्ग लोड नहीं है वह यह है कि VALहै final और इसके साथ initialised है एक निरंतर अभिव्यक्ति (9090)। यदि, और केवल अगर, उन दो शर्तों को पूरा किया जाता है, तो निरंतरता का संकलन समय पर किया जाता है और जहां "हार्डकोड" की आवश्यकता होती है।

संकलित समय पर अभिव्यक्ति का मूल्यांकन करने से रोकने के लिए (और JVM को आपकी कक्षा लोड करने के लिए), आप या तो कर सकते हैं:

  • अंतिम कीवर्ड निकालें:

    static int VAL = 9090; //not a constant variable any more
    
  • या दाएँ हाथ की अभिव्यक्ति को कुछ अचर्य (भले ही चर अभी भी अंतिम हो) बदल दें:

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    

5

यदि आप उत्पन्न बायोटेक का उपयोग करते हुए देखते हैं javap -v Test.class, तो मुख्य () बाहर आता है:

public static void main(java.lang.String[]) throws java.lang.Exception;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String **MAIN METHOD
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: sipush        9090
        14: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        17: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        20: sipush        9190
        23: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        26: return        

आप स्पष्ट रूप से " 11: sipush 9090" देख सकते हैं कि स्थिर अंतिम मूल्य का सीधा उपयोग किया जाता है, क्योंकि Mno.VAL एक संकलन समय स्थिर है। इसलिए Mno वर्ग को लोड करना आवश्यक नहीं है। इसलिए Mno के स्थिर ब्लॉक को निष्पादित नहीं किया गया है।

आप नीचे Mno को मैन्युअल रूप से लोड करके स्थिर ब्लॉक निष्पादित कर सकते हैं:

class Test{
    public static void main(String arg[]) throws Exception {
        System.out.println("**MAIN METHOD");
        Class.forName("Mno");                 // Load Mno
        System.out.println(Mno.VAL);
        System.out.println(Mno.VAL+100);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}

1
  1. वास्तव में आपने उस Mno वर्ग का विस्तार नहीं किया है, इसलिए जब संकलन शुरू होता है तो यह वैरिएबल वैल की निरंतरता उत्पन्न करेगा और जब निष्पादन शुरू होता है, तो उस चर को मेमोरी से लोड होने की आवश्यकता होती है। तो इसकी आवश्यकता नहीं है कि आपके वर्ग का संदर्भ ताकि स्थिर बॉक निष्पादित न हो।

  2. यदि कक्षा का Aविस्तार होता है Mno, तो स्थिर ब्लॉक को कक्षा में शामिल किया जाता है Aयदि आप ऐसा करते हैं तो उस स्थिर ब्लॉक को निष्पादित किया जाता है। उदाहरण के लिए..

    public class A extends Mno {
    
        public static void main(String arg[]){    
            System.out.println("**MAIN METHOD");
            System.out.println(Mno.VAL);//SOP(9090);
            System.out.println(Mno.VAL+100);//SOP(9190);
        }
    
    }
    
    class Mno {
        final static int VAL=9090;
        static {
            System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
        }
    }
    

0

जहां तक ​​मुझे पता है, इसे उपस्थिति के क्रम में निष्पादित किया जाएगा। उदाहरण के लिए :

 public class Statique {
     public static final String value1 = init1();

     static {
         System.out.println("trace middle");
     }
     public static final String value2 = init2();


     public static String init1() {
         System.out.println("trace init1");
         return "1";
     }
     public static String init2() {
         System.out.println("trace init2");
         return "2";
     }
 }

छप जाएगा

  trace init1
  trace middle
  trace init2

मैंने अभी इसका परीक्षण किया और स्टैटिक्स को इनिशियलाइज़ (=> प्रिंट) किया जाता है जब क्लास "स्टेटिक" का वास्तव में उपयोग किया जाता है और कोड के एक अन्य टुकड़े में "निष्पादित" होता है (मेरा मामला मैंने "नया स्टेटिक ()" किया था)।


2
आपको यह आउटपुट इसलिए मिल रहा है क्योंकि आप Statiqueक्लास को लोड करके कर रहे हैं new Statique()। जबकि पूछे गए प्रश्न में, Mnoक्लास बिल्कुल लोड नहीं है।
आरएएस

@ फैबेन, अगर मैं टेस्ट क्लास में मोनो की वस्तु इस तरह बना रहा हूँ: Mno anc = New Mno (); तो इसका ठीक है, लेकिन वर्तमान परिदृश्य मैं ऐसा नहीं कर रहा हूं, मेरा संदेह है अगर मैं अंतिम हटा रहा हूं तो स्थिर ब्लॉक ठीक निष्पादित करता है अन्यथा यह निष्पादित नहीं करता है, ऐसा क्यों?
Sthita

1
नीचे जवाब हां एकदम सही है। मेन.क्लास के बाइटकोड में (Mno.VAL का उपयोग करके), 9090 हार्ड कोडित पाया जाता है। अंतिम निकालें, संकलन करें, फिर javap Main का उपयोग करें, आप getstatic # 16 देखेंगे ; // फ़ील्ड स्टेटिकवीएएल: मैं । अंतिम रूप दें, संकलित करें, फिर javap Main का उपयोग करें, आपको sipush 9090 दिखाई देगा
फैबिन

1
क्योंकि यह Main.class में हार्डकोड है, इसलिए क्लास MNO को लोड करने का कोई कारण नहीं है, इसलिए कोई स्थैतिक आरंभ नहीं है।
फेबिन

यह दूसरे प्रश्न का उत्तर देता है: "कौन सी मेमोरी पहले आवंटित की जाएगी, स्थिर अंतिम चर या स्थिर ब्लॉक?" (लेक्सिकल ऑर्डर)
हौके इंगमार श्मिट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.