मैं कुछ जावा व्यवहार के बारे में बहुत उलझन में हूं, खासकर क्योंकि जावा की मेरी पिछली समझ यह थी कि यह सख्ती से पास-दर-मूल्य था।

अगर मैं किसी ऑब्जेक्ट को किसी विधि में पास करता हूं, तो कॉलिंग थ्रेड में उस ऑब्जेक्ट को शून्य कर देता हूं, मैं उम्मीद करता हूं कि ऑब्जेक्ट अभी भी मौजूद होगा और विधि में संचालित होने में सक्षम होगा, लेकिन ऐसा नहीं है।

यहाँ कुछ नमूना कोड है:

public class methodTest {

    boolean bool;
    boolean secondBool;
    Test    list;

    public static void main(String[] args) {
        new methodTest().run();
    }

    public void run() {
        list = new Test();
        new Thread(() -> {
            func(list);
        }).start();
        list = null;
        bool = true;
        while (!secondBool) {
            // block
        }
        System.gc();
    }

    public void func(Test big) {
        while (!bool) {
            // block
        }
        System.out.println(big);
        secondBool = true;
    }

    class Test {
        @Override
        protected void finalize() throws Throwable {
            System.out.println("I'm getting cleaned up!");
        }

        @Override
        public String toString() {
            return "Test!";
        }
    }
}

यह कोड प्रिंट करता है

null
I'm getting cleaned up!

जब मैं इसे प्रिंट करने की अपेक्षा करता हूं:

Test!
I'm getting cleaned up!

मैंने अंत में कचरा संग्रह कॉल और कक्षा में अंतिम विधि को शामिल किया ताकि यह सुनिश्चित किया जा सके कि जीसी चर list को फ़ंक्शन प्रिंट करने से पहले नहीं मिल रहा था, लेकिन इसके बिना भी वही प्रभाव होता है।

इस व्यवहार के लिए स्पष्टीकरण क्या है?

संपादित करें:

इसका एक अन्य उदाहरण यह होगा कि यदि आपने रन विधि में list = null लाइन को list = new Test() में बदल दिया है, तो toString को Test उदाहरणों की संख्या गिनने के लिए थोड़ा संशोधित किया है। प्रोग्राम "टेस्ट 1" के बजाय "टेस्ट 2" प्रिंट करेगा, क्योंकि func में पैरामीटर का मान कॉलिंग थ्रेड में ओवरराइड किया गया था, भले ही जावा के पास-बाय-वैल्यू सिस्टम की मेरी समझ में, ऐसा नहीं होना चाहिए .

0
BeyondPerception 12 जून 2020, 00:06

4 जवाब

सबसे बढ़िया उत्तर

यह शून्य प्रिंट करता है क्योंकि दौड़ की स्थिति होती है और नया धागा ज्यादातर समय खो देता है।

समय इस प्रकार है:

  1. मुख्य धागा (चलने वाला methodTest.run()) एक नया Thread ऑब्जेक्ट बनाता है और नया थ्रेड शुरू करता है (जिसका अर्थ है कि यह एक नया linux/windows थ्रेड बनाता है और इसे सूचित करता है कि यह चलना शुरू कर सकता है)
  2. अगले चरण के रूप में यह आवृत्ति चर list को शून्य पर सेट करता है
  3. चरण 2 के समानांतर में दूसरा धागा चलना शुरू होता है और अंततः लैम्ब्डा तक पहुंचता है () -> { func(list); }
  4. केवल जब दूसरा थ्रेड निष्पादित होता है func(list); क्या यह इंस्टेंस वेरिएबल list को पढ़ेगा

पैरामीटर big के रूप में func में क्या पारित किया जाता है, इसलिए पूरी तरह से निर्भर करता है

  • मुख्य थ्रेड को निष्पादित करने के लिए कितना समय चाहिए list = null;
  • दूसरे थ्रेड को निष्पादित करने के लिए ओएस को कितना समय चाहिए और दूसरे थ्रेड के लिए उस बिंदु तक पहुंचने के लिए जहां वह func(list); कहता है

आपके अवलोकन से दूसरे धागे को उस बिंदु तक पहुंचने के लिए अधिक समय की आवश्यकता होती है जहां func(list); निष्पादित किया जाता है, मुख्य धागे को निष्पादित करने की आवश्यकता होती है list = null;

1
Thomas Kläger 12 जून 2020, 08:26

"अगर मैं किसी ऑब्जेक्ट को किसी विधि में पास करता हूं," हां, लेकिन आप ऐसा नहीं कर रहे हैं। रन () कॉल में शून्य पैरामीटर हैं। इसके बजाय, आपकी रन विधि आपके ऑब्जेक्ट में वेरिएबल को संदर्भित कर रही है।

अपने कोड की तुलना करें और आप वहां क्या देखते हैं

public sstatic void myTest(Test t) {
  t = null;
}

public static void main(String[] args) {
  list = ...;
  myTest();
  System.out.println("Null? " + list == null); // //print test will print false
}
0
ControlAltDel 12 जून 2020, 00:13

अगर मुझे जावा सही ढंग से याद है, तो यह उपयोगकर्ता परिभाषित कक्षाओं के लिए मान बदल देता है। तो यदि आप आदिम डेटा प्रकारों और पहले से परिभाषित कक्षाओं जैसे int, string, आदि का उपयोग करते हैं तो यह आपको इस समस्या का कारण नहीं बनता है। लेकिन यहां आप अपनी खुद की कक्षा का उपयोग कर रहे हैं, इसलिए यह किसी कारण से संदर्भ द्वारा पारित किया गया है।

-2
Sedeeki 12 जून 2020, 00:12

ठीक है, मुझे लगता है कि मैंने इसे समझ लिया है, हालांकि मुझे इसकी पुष्टि करने के लिए स्रोत खोजने में मुश्किल हो रही है।

ऐसा लगता है कि जावा केवल list के मान को big में कॉपी कर रहा है जब big को पहली बार संदर्भित किया गया है। मैं अनुमान लगा रहा हूं कि यदि पैरामीटर का कभी भी उपयोग नहीं किया जाता है तो प्रतिलिपि बनाने के ऊपरी हिस्से को कम करना है, लेकिन यह ध्यान में रखना एक अच्छी बात है, खासकर यदि आप बहु-थ्रेडेड एप्लिकेशन पर काम कर रहे हैं।

0
BeyondPerception 12 जून 2020, 05:19