स्थैतिक संशोधक इस कोड को कैसे प्रभावित करता है?


109

यहाँ मेरा कोड है:

class A {
    static A obj = new A();
    static int num1;
    static int num2=0;

    private A() {
        num1++;
        num2++;
    }
    public static A getInstance() {
        return obj;
    }
}

public class Main{
    public static void main(String[] arg) {
        A obj = A.getInstance();
        System.out.println(obj.num1);
        System.out.println(obj.num2);
    }
}

आउटपुट है 1 0, लेकिन मैं समझ नहीं पा रहा हूं।

क्या कोई मुझे यह समझा सकता है?


10
अच्छा प्रश्न! हमें इससे क्या सीखना चाहिए: यह मत करो! ;)
isnot2bad

जवाबों:


116

जावा में दो चरण होते हैं: 1. पहचान, 2. निष्पादन

  1. में पहचान चरण सभी स्थैतिक चर का पता चला और मूलभूत मूल्यों के साथ प्रारंभ कर रहे हैं।

    तो अब मूल्य हैं:
    A obj=null
    num1=0
    num2=0

  2. दूसरा चरण, निष्पादन , ऊपर से नीचे शुरू होता है। जावा में, निष्पादन पहले स्थैतिक सदस्यों से शुरू होता है।
    यहां आपका पहला स्टैटिक वैरिएबल है static A obj = new A();, इसलिए सबसे पहले यह उस वैरिएबल के ऑब्जेक्ट को बनाएगा और कंस्ट्रक्टर को कॉल करेगा, इसलिए इसका वैल्यू num1और num2बन जाता है 1
    और फिर, फिर से static int num2=0;निष्पादित किया जाएगा, जो बनाता है num2 = 0;

अब मान लीजिए कि आपका कंस्ट्रक्टर इस तरह है:

 private A(){
    num1++;
    num2++;
    System.out.println(obj.toString());
 }

यह फेंक देगा NullPointerExceptionक्योंकि objअभी भी इसका संदर्भ नहीं मिला है class A


11
मैं विस्तार करूंगा: static A obj = new A();नीचे दी गई लाइन को आगे बढ़ाएं static int num2=0;और आपको 1 और 1.
थॉमस

2
अभी भी मुझे भ्रमित करता है कि तथ्य यह है कि भले ही num1 में एक स्पष्ट आरंभीकरण नहीं है, यह IS (
अनुमानित

@not2bad "निहित आरोपण" घोषणा के हिस्से के रूप में होता है। घोषणा कोई बात नहीं क्या आप उन्हें में पेश आदेश असाइनमेंट से पहले होता है। A obj = new A(); int num1; int num2 = 0;इस में बदल जाता है: A obj; int num1; int num2; obj = new A(); num2 = 0;। जावा ऐसा करता है num1, num2जब आप new A()कंस्ट्रक्टर तक पहुंचते हैं तब तक इसे परिभाषित किया जाता है ।
हंस जेड

31

staticएक चर घोषणा पर लागू होने पर संशोधक का क्या अर्थ है कि चर एक उदाहरण चर के बजाय एक वर्ग चर है। दूसरे शब्दों में ... केवल एक num1चर है, और केवल एक num2चर है।

(एक तरफ: एक स्थिर वैरिएबल कुछ अन्य भाषाओं में एक वैश्विक वैरिएबल की तरह है, सिवाय इसके कि इसका नाम हर जगह दिखाई नहीं देता है। यहां तक ​​कि अगर इसे एक के रूप में घोषित किया गया है public static, तो अयोग्य नाम केवल तभी दिखाई देता है जब इसे वर्तमान वर्ग या सुपरक्लास में घोषित किया जाता है। , या अगर यह एक स्थिर आयात का उपयोग करके आयात किया जाता है। यह भेद है। एक सच्चा वैश्विक कहीं भी योग्यता के बिना दिखाई देता है।)

इसलिए जब आप संदर्भित करते हैं obj.num1और obj.num2, आप वास्तव में उन स्टैटिक वेरिएबल्स का उल्लेख कर रहे हैं जिनके वास्तविक पदनाम हैं A.num1और A.num2। और इसी तरह, जब निर्माता वेतन वृद्धि करता है num1और num2, यह समान चर (क्रमशः) बढ़ाता है।

आपके उदाहरण में भ्रमित करने वाली शिकन कक्षा आरंभीकरण में है। एक क्लास को सभी स्टैटिक वेरिएबल्स को पहले डिफॉल्ट इनिशियलाइज़ करके इनिशियलाइज़ किया जाता है , और फिर क्लास में दिखाई देने वाले क्रम में घोषित स्टैटिक इनिशियलाइज़र (और स्टैटिक इनिशलाइज़र ब्लॉक) को निष्पादित किया जाता है। इस मामले में, आपके पास यह है:

static A obj = new A();
static int num1;
static int num2=0;

यह इस तरह होता है:

  1. स्टेटिक्स उनके डिफ़ॉल्ट प्रारंभिक मूल्यों के साथ शुरू होता है; A.objहै nullऔर A.num1/ A.num2शून्य हैं।

  2. पहले घोषणा ( A.obj) का एक उदाहरण बनाता है A(), और के लिए निर्माता Aवेतन वृद्धि A.num1और A.num2। जब घोषणा पूरी हो जाती है, A.num1और A.num2दोनों हैं 1, और A.objनवनिर्मित Aउदाहरण को संदर्भित करता है ।

  3. दूसरी घोषणा ( A.num1) में कोई इनिशियलाइज़र नहीं है, इसलिए A.num1यह परिवर्तित नहीं होता है।

  4. तीसरे घोषणा ( A.num2) में एक इनिशियलाइज़र है जो शून्य से असाइन करता है A.num2

इस प्रकार, वर्ग प्रारंभ के अंत में, A.num1है 1और A.num2है 0... और कहा कि क्या आपके प्रिंट बयान दिखा।

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


16

1,0 सही है।

जब कक्षा को लोड किया जाता है तो सभी स्थिर डेटा को ओडर में आरंभिक रूप से घोषित किया जाता है। डिफ़ॉल्ट रूप से int 0 है।

  • पहला A बनाया गया है। num1 और num2 बनना 1 और 1 है
  • की तुलना में static int num1;कुछ नहीं करता है
  • की तुलना में static int num2=0;यह 0 से num2 लिखता है

9

यह स्थैतिक इनिशियलाइजर्स के आदेश के कारण है। कक्षाओं में स्थैतिक अभिव्यक्तियों का मूल्यांकन टॉप-डाउन क्रम में किया जाता है।

कहा जाने वाला पहला, का निर्माता है A, जो सेट करता है num1और num2दोनों 1:

static A obj = new A();

फिर,

static int num2=0;

कहा जाता है और फिर से num2 = 0 सेट करता है।

इसीलिए num11 है और num20 है।

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


6

जेएलएस में एक खंड पाया जा सकता है: in12.4.2

विस्तृत प्रारंभिक प्रक्रिया:

9. अगला, या तो वर्ग चर initializers और वर्ग के स्थिर initializers, या इंटरफ़ेस के क्षेत्र initializers, पाठ क्रम में, हालांकि वे एक ही ब्लॉक थे, कि अंतिम वर्ग चर और इंटरफेस के क्षेत्र जिसका मान संकलित है को छोड़कर निष्पादित समय से पहले स्थिरांक शुरू होते हैं

अतः तीन स्थैतिक चर को एक-एक करके क्रमबद्ध रूप से आरंभ किया जाएगा।

इसलिए

static A obj = new A();
//num1 = 1, num2 = 1;
static int num1;
//this is initilized first, see below.
static int num2=0;
//num1 = 1, num2 = 0;

यदि मैं आदेश को इसमें परिवर्तित करता हूं:

static int num1;
static int num2=0;
static A obj = new A();

परिणाम होगा 1,1

ध्यान दें कि static int num1;चर वेरिएबल नहीं है क्योंकि ( .28.3.2 ):

यदि किसी क्षेत्र घोषणाकर्ता में एक वैरिएबल इनिशियलाइज़र होता है, तो उसके पास घोषित चर के लिए असाइनमेंट (.215.26) का शब्दार्थ होता है, और: यदि डिक्लेयर एक वर्ग चर (यानी, एक स्थिर क्षेत्र) के लिए है, तो वैरिएबल इनिशियलाइज़र है मूल्यांकन और असाइनमेंट बिल्कुल एक बार प्रदर्शन किया, जब कक्षा आरंभीकृत की जाती है

और यह क्लास वेरिएबल इनिशियलाइज्ड होता है जब क्लास बनाई जाती है। यह पहले ( .124.12.5 ) होता है ।

किसी प्रोग्राम के हर वेरिएबल का वैल्यू यूज़ होने से पहले एक वैल्यू होनी चाहिए: प्रत्येक क्लास वेरिएबल, इंस्टेंस वेरिएबल, या एरे कंपोनेंट को डिफॉल्ट वैल्यू के साथ इनिशियलाइज़ किया जाता है जब इसे बनाया जाता है (§15.9, .1015.10): टाइप बाइट के लिए, डिफॉल्ट वैल्यू शून्य है, अर्थात, (बाइट) का मान 0 है। छोटे प्रकार के लिए, डिफ़ॉल्ट मान शून्य है, अर्थात (छोटा) 0 का मान। टाइप इंट के लिए, डिफ़ॉल्ट मान शून्य है, अर्थात, प्रकार लंबे समय के लिए, डिफ़ॉल्ट मान शून्य है, अर्थात 0 एल। प्रकार फ़्लोट के लिए, डिफ़ॉल्ट मान सकारात्मक शून्य है, अर्थात 0.0f है। टाइप डबल के लिए, डिफ़ॉल्ट मान धनात्मक शून्य है, अर्थात 0.0 डी। प्रकार चार के लिए, डिफ़ॉल्ट मान अशक्त वर्ण है, अर्थात '\ u0000'। प्रकार बूलियन के लिए, डिफ़ॉल्ट मान गलत है। सभी संदर्भ प्रकारों (.34.3) के लिए, डिफ़ॉल्ट मान शून्य है।


2

शायद इसे इस तरह से सोचने में मदद मिलेगी।

कक्षाएं वस्तुओं के लिए ब्लूप्रिंट हैं।

ऑब्जेक्ट्स का चर तब हो सकता है जब वे त्वरित होते हैं।

कक्षाओं में भी चर हो सकते हैं। इन्हें स्थैतिक घोषित किया गया है। इसलिए वे ऑब्जेक्ट इंस्टेंस के बजाय कक्षा में सेट किए जाते हैं।

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

यहां "डॉग" वर्ग का उदाहरण और उदाहरण है जो इसके द्वारा बनाए गए उदाहरणों की संख्या को ट्रैक करने के लिए स्थिर चर का उपयोग करता है।

"डॉग" क्लास क्लाउड है जबकि ऑरेंज बॉक्स "डॉग" उदाहरण हैं।

कुत्ता वर्ग

अधिक पढ़ें

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

यदि आप कुछ सामान्य ज्ञान की तरह महसूस करते हैं, तो यह विचार पहली बार प्लेटो द्वारा पेश किया गया था


1

स्टैटिक कीवर्ड का उपयोग जावा में मुख्य रूप से मेमोरी मैनेजमेंट के लिए किया जाता है। हम चर, विधियों, ब्लॉक और नेस्टेड क्लास के साथ स्थैतिक कीवर्ड लागू कर सकते हैं। स्थिर कीवर्ड वर्ग के उदाहरण से वर्ग का है। स्थैतिक कीवर्ड के बारे में संक्षिप्त विवरण के लिए:

http://www.javatpoint.com/static-keyword-in-java


0

ऊपर दिए गए कई उत्तर सही हैं। लेकिन वास्तव में यह बताने के लिए कि क्या हो रहा है मैंने नीचे कुछ छोटे संशोधन किए हैं।

जैसा कि ऊपर कई बार उल्लेख किया गया है, जो हो रहा है वह वर्ग ए का उदाहरण है जिसे कक्षा ए पूरी तरह से लोड होने से पहले बनाया जा रहा है। तो क्या माना जाता है कि सामान्य 'व्यवहार' नहीं मनाया जाता है। यह एक निर्माणकर्ता से कॉल करने के तरीकों के लिए बहुत भिन्न नहीं है जिसे ओवरराइड किया जा सकता है। उस स्थिति में, उदाहरण चर एक सहज स्थिति में नहीं हो सकता है। इस उदाहरण में वर्ग चर एक सहज स्थिति में नहीं हैं।

class A {
    static A obj = new A();
    static int num1;
    static int num2;
    static {
        System.out.println("Setting num2 to 0");
        num2 = 0;
    }

    private A() {
        System.out.println("Constructing singleton instance of A");
        num1++;
        num2++;
    }

    public static A getInstance() {
        return obj;
    }
}

public class Main {

    public static void main(String[] arg) {
        A obj = A.getInstance();
        System.out.println(obj.num1);
        System.out.println(obj.num2);
    }
}

आउटपुट है

Constructing singleton instance of A
Setting num2 to 0
1
0

0

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

इसलिए ताकि यहाँ जब num1 और num2 को मुख्य रूप से बुलाया जाएगा तो यह मूल्यों के साथ आरंभीकृत हो जाएगा

संख्या 1 = 0 + 1; तथा

NUM2 = 0;

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.