2011-02-01 24 views
17

ग्रहण में इस खोजबग चेतावनी के साथ मैं यहां थोड़ा उलझन में हूं।एक आवृत्ति विधि में एक स्थिर चर के लिए लिखना, यह एक बुरा अभ्यास क्यों है?

public class MyClass { 
    public static String myString; 
} 


public class AnotherClass { 
    public void doSomething() { 
     MyClass.myString = "something"; 
    } 
} 

यह मैं एक FindBugs चेतावनी "उदाहरण विधि से स्थिर क्षेत्र के लिए लिखना", हालांकि यह मेरे लिए एक चेतावनी नहीं देता है देता है:

public class MyClass { 
    public static String myString; 
} 


public class AnotherClass { 
    public void doSomething() { 
     doAnotherThing(); 
    } 
    public static doAnotherThing() { 
     MyClass.myString = "something"; 
    } 
} 

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

मुझे पता है कि यह वैरिएबल अंतिम होना चाहिए, लेकिन मैं गुण फ़ाइल से मूल्य लोड कर रहा हूं।

उत्तर

18

इसका एक रूप एलियासिंग का, जो प्रतिद्वंद्वी हो सकता है। काउंटर-अंतर्ज्ञानी कोड हैम्पर्स रखरखाव में आसानी।

तार्किक रूप से, हम उदाहरण के तरीकों को उस उदाहरण के डेटा को प्रभावित करने की अपेक्षा करते हैं। हम स्थैतिक तरीकों को स्थिर डेटा को प्रभावित करने की अपेक्षा करते हैं।

... 
a.initialize(); 
... 
b.initialize(); 
... 

इस कोड के पाठक तुरंत एहसास नहीं हो सकता है कि a और b के उदाहरण वास्तव में एक ही डेटा को प्रभावित कर रहे हैं:

के doSomethinginitialize को नाम बदलने करते हैं। यह एक बग हो सकता है क्योंकि हम एक ही मेमोरी को दो बार शुरू कर रहे हैं, लेकिन यह स्पष्ट नहीं है क्योंकि यह उचित लगता है कि हमें प्रत्येक उदाहरण पर initialize पर कॉल करने की आवश्यकता हो सकती है।

हालांकि, कोड थे:

... 
MyClass.initialize(); 
... 
MyClass.initialize(); 
... 

इस मामले में, अपने अधिक सहज ज्ञान युक्त है कि हम संभावना एक ही स्थिर डेटा को प्रभावित कर रहे हैं और यह संभावना एक बग है।

यह एलियासिंग के सामान्य संस्करण के समान है जहां एक ही दायरे में दो चर एक ही उदाहरण के लिए इंगित करते हैं।


अपने पिछले उदाहरण के लिए,

  • एक उदाहरण एक स्थिर विधि

    तथ्य यह है कि एक उदाहरण विधि एक स्थिर विधि बुला रहा है झंडे को बढ़ाने के लिए की उम्मीद नहीं है कहते हैं। उदाहरण थे कि यह बहुत उपयोगी है जहां इसकी संभावना एक समस्या है।

  • एक वर्ग का एक स्थिर विधि एक अर्थ में एक और वर्ग 'स्थिर डेटा

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

ध्यान रखें कि FindBugs बस आपके संभावित कोड में संभावित संभावित समस्याओं को ध्वजांकित करने की कोशिश कर रहा है, हर संभव समस्या नहीं। आपका पहला उदाहरण संभवतः एक संभावित रखरखाव मुद्दा है जिसे आपको यह जांचने की आवश्यकता है कि यह वास्तविक समस्या है या नहीं। आपका दूसरा उदाहरण संभवतः कोई समस्या नहीं है या यह एक वास्तविक समस्या है जो उपयोग मामलों के समान है जहां यह कोई समस्या नहीं है।

+1

मुझे सिंक्रनाइज़ेशन के बजाय अंतर्निहित तर्क के रूप में आसानी से समझने और स्पष्टता पर जोर देना पसंद है (जो कि विधि स्थिर है या नहीं, इस पर ध्यान दिए बिना समस्याग्रस्त है)। –

+0

@ स्टेव - धन्यवाद –

1

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

4

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

सभी मामलों में 99% में, आप अपने इंस्टेंस विधियों को केवल गैर स्थैतिक फ़ील्ड को बदलने के लिए चाहते हैं, यही कारण है कि खोजबग आपको चेतावनी देते हैं।

और FindBugs काफी चालाक अपने उदाहरण विधि अप्रत्यक्ष रूप से आपके दूसरे उदाहरण :) में क्षेत्र बदलने के बारे में पता लगाने के लिए नहीं है

0

क्योंकि स्थिर क्षेत्र को बदलने से यह सभी मामलों के लिए बदल जाता है, अगर अनियमित समस्याएं ठीक से सिंक्रनाइज़ नहीं होती हैं।

यदि आप साझा फ़ील्ड सेट करने के लिए प्रॉपर्टी फ़ाइल में पढ़ रहे हैं, तो इसे एक स्थिर विधि में करें। वैकल्पिक रूप से, फ़ील्ड को एक अलग सिंगलटन उदाहरण में दोबारा दोहराएं कि अन्य वर्ग केवल पढ़ सकता है। यदि आपके पास केवल एक उदाहरण होगा, तो सिंगलटन पैटर्न का उपयोग करें और फ़ील्ड को गैर स्थैतिक बनाएं।

स्टेटिक विधियों को केवल स्थिर डेटा को प्रभावित करना चाहिए, और उदाहरण विधियों को केवल इंस्टेंस डेटा को प्रभावित करना चाहिए।

0

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

चेतावनी का कारण (FindBugs प्रलेखन द्वारा बहुत अच्छी तरह से समझाया नहीं गया है), मुझे लगता है, कुछ उत्तरों से संकेत मिलता है: यह संदिग्ध और संभवतः एक गलती है। जोकन बेडर्सडॉर्फर की तरह, कहा गया है कि ऐसे कई उपयोग मामले नहीं हैं जहां आप एक वर्ग में एक स्थिर चर को किसी अन्य विधि में एक विधि से असाइन करना चाहते हैं। वैसे ही जैसे

while (x = y) { 
    // ... 
} 

तकनीकी रूप से कोई त्रुटि नहीं है (और वास्तव में कानूनी जावा यदि x और y बूलियन हैं), यह लगभग हमेशा एक गलती है। इसी तरह, फाइंडबग के लेखकों को विषय के मामले के बारे में भी यही लगा।

संबंधित मुद्दे