2009-03-04 7 views
67

मुझे यकीन है कि आप सभी को मेरा मतलब है - कोड जैसे:एक उदाहरण के माध्यम से जावा कंपाइलर के लिए एक त्रुटि के माध्यम से स्थिर विधि क्यों नहीं बुला रहा है?

Thread thread = new Thread(); 
int activeCount = thread.activeCount(); 

एक कंपाइलर चेतावनी को उत्तेजित करता है। यह एक त्रुटि क्यों नहीं है?

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

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

String hello = "hello"; 
String number123AsString = hello.valueOf(123); 

जो ऐसा लगता है कि प्रत्येक स्ट्रिंग इंस्टेंस "स्ट्रिंग वैल्यूऑफ (int i)" विधि के साथ आता है।

+11

अपने बिंदु पर विस्तार करने के लिए, अनावश्यक उदाहरण भी शून्य हो सकता है: 'स्ट्रिंग हैलो = शून्य; हैलो.वल्यूऑफ (123); 'काम करता है! – Thilo

उत्तर

71

असल में मेरा मानना ​​है कि जावा डिजाइनरों ने भाषा तैयार करते समय गलती की है, और इसमें शामिल संगतता मुद्दों के कारण इसे ठीक करने में बहुत देर हो चुकी है। हां, यह बहुत भ्रामक कोड का कारण बन सकता है। हाँ, आपको इससे बचना चाहिए। हां, आपको यह सुनिश्चित करना चाहिए कि आपका आईडीई इसे एक त्रुटि, आईएमओ के रूप में इलाज के लिए कॉन्फ़िगर किया गया है। क्या तुमने कभी एक भाषा अपने आप को डिजाइन करना चाहिए, कुछ ऐसी बातें करने का एक उदाहरण के रूप में मन में यह सहन से बचने के लिए :)

बस DJClayworth की बात करने के लिए प्रतिक्रिया करने के लिए, यहाँ क्या सी # में अनुमति दी है:

public class Foo 
{ 
    public static void Bar() 
    { 
    } 
} 

public class Abc 
{ 
    public void Test() 
    { 
     // Static methods in the same class and base classes 
     // (and outer classes) are available, with no 
     // qualification 
     Def(); 

     // Static methods in other classes are available via 
     // the class name 
     Foo.Bar(); 

     Abc abc = new Abc(); 

     // This would *not* be legal. It being legal has no benefit, 
     // and just allows misleading code 
     // abc.Def(); 
    } 

    public static void Def() 
    { 
    } 
} 

क्यों मुझे लगता है कि यह भ्रामक है? क्योंकि अगर मैं कोड someVariable.SomeMethod() पर देखता हूं तो मुझे उम्मीद है कि someVariable के मान का उपयोग करें। यदि SomeMethod() एक स्थिर विधि है, तो उम्मीद अमान्य है; कोड मुझे धोखा दे रहा है। यह संभवतः अच्छा चीज़ कैसे हो सकता है?

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

संपादित करें: यह संपादन क्लेटन के उत्तर की प्रतिक्रिया है, जिसका दावा है कि यह स्थैतिक तरीकों के लिए विरासत की अनुमति देता है। यह नहीं है स्टेटिक विधियां सिर्फ पॉलिमॉर्फिक नहीं हैं।

class Base 
{ 
    static void foo() 
    { 
     System.out.println("Base.foo()"); 
    } 
} 

class Derived extends Base 
{ 
    static void foo() 
    { 
     System.out.println("Derived.foo()"); 
    } 
} 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     Base b = new Derived(); 
     b.foo(); // Prints "Base.foo()" 
     b = null; 
     b.foo(); // Still prints "Base.foo()" 
    } 
} 

आप देख सकते हैं, b के निष्पादन के समय मूल्य पूरी तरह से नजरअंदाज कर दिया है: यहाँ है कि प्रदर्शन करने के लिए एक छोटा लेकिन पूरा कार्यक्रम है।

+3

केवल अगर मैंने जावा डिज़ाइन किया था! जबरदस्त हंसी! –

+0

मुझे लगता है कि आप कुछ खो सकते हैं। मेरी पोस्ट देखें – DJClayworth

+1

@ डीजेक्लेवर्थ: नहीं। सी # में इसकी अनुमति है, लेकिन कुछInstanceOfMyClass.doComplexCalculation() नहीं होगा। –

13

क्योंकि भाषा की कल्पना इसे अनुमति देती है :) बस वीबी करता है और सी # नहीं करता है।

+1

spec इसे अनुमति देता है - लेकिन क्या ऐसा कोई मामला है जहां इसे करने के लिए यह समझ में आता है? – tmtest

+1

इसे कॉल करने का यह एक और तरीका है। जैसे आप 'इस' कीवर्ड के साथ या उसके बिना सदस्य फ़ील्ड तक पहुंच सकते हैं। या किसी भी वर्ग के नाम को निर्दिष्ट किए बिना उसी वर्ग में स्थैतिक विधियों को बुलाएं। मुझे सी # रास्ता बहुत बेहतर लगता है और कभी ऐसा कोड नहीं लिखता है, लेकिन भाषा डिजाइनरों ने इसे इस तरह डिज़ाइन किया है। –

+0

@tmtest: foo() {bar (नया बेस()); } चिड़ियाघर() {बार (नया व्युत्पन्न()); } बार (बेस बी) {b.staticOverriddenInDerived(); } आप बेस (बेस) को बेस.स्टैटिक ओवरराइड इनडिएव(); कॉल करने के लिए नहीं चाहते हैं; क्योंकि रनटाइम बी पर एक ओवरराइड स्थैतिक विधि के साथ व्युत्पन्न हो सकता है। यह संदिग्ध नोटेशन है, लेकिन उदाहरण के लिए सदस्यों को एक उदाहरण विधि में संदर्भित करने की इजाजत दी जा रही है, जो सदस्यों को स्थानीय रूप से केवल उस विधि (या इसमें एक ब्लॉक में, नेस्टेड क्लास समेत) से अलग किए गए नामों से अलग किया जा सकता है। – Matthew

5

संक्षिप्त उत्तर - भाषा इसे अनुमति देती है, इसलिए इसकी कोई त्रुटि नहीं है।

8

वे पहले से मौजूद सभी कोड के कारण अब यह कोई त्रुटि नहीं कर सकते हैं।

मैं आपके साथ हूं कि यह एक त्रुटि होनी चाहिए। शायद कुछ चेतावनियों को त्रुटियों में अपग्रेड करने के लिए कंपाइलर के लिए एक विकल्प/प्रोफ़ाइल होना चाहिए।

अद्यतन: जब वे 1.4 में ज़ोर कीवर्ड है, जो पुराने कोड के साथ इसी तरह संभावित संगतता समस्याओं है शुरू की है, वे इसे available only if you explicitly set the source mode to "1.4" बनाया है। मुझे लगता है कि कोई इसे एक नए स्रोत मोड "जावा 7" में एक त्रुटि बना सकता है। लेकिन मुझे संदेह है कि वे ऐसा करेंगे, इस पर विचार करते हुए कि यह सभी परेशानी का कारण होगा। जैसा कि अन्य ने बताया है, आपको भ्रमित कोड लिखने से रोकने के लिए कड़ाई से जरूरी नहीं है। और जावा में भाषा परिवर्तन इस बिंदु पर कड़ाई से जरूरी तक सीमित होना चाहिए। (> संकलक - -> त्रुटियाँ/चेतावनी ग्रहण वरीयताओं में - जावा>)

+0

ग्रहण संकलक में इस तरह के विकल्प (indirectStatic, http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_api_compile.htm) नहीं है –

+1

लेकिन उन्होंने किया यह जब उन्होंने जावा 1.4 में जोरदार कीवर्ड पेश किया। वे फिर से ऐसा क्यों नहीं कर सकते हैं? –

+0

आप सही हैं। आवेषण के लिए, आपको विशेष रूप से कंपाइलर स्तर 1.4 पर सेट करना होगा, अन्यथा यह अभी भी बिना किसी जोर के संकलन करता है। मुझे लगता है कि 1.5 एनोटेशन और जेनेरिक एक ही काम करते हैं। तो एक जावा 7 संकलन स्तर हो सकता है, जो इसे एक त्रुटि बना देगा। – Thilo

1

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

0

इसके लिए विकल्प नहीं है

1

ही तार्किक के लिए संभावना यह नहीं एक त्रुटि है कि बनाता है:

public class X 
{ 
    public static void foo() 
    { 
    } 

    public void bar() 
    { 
     foo(); // no need to do X.foo(); 
    } 
} 
2

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

12

यह एक त्रुटि क्यों होनी चाहिए? उदाहरण के सभी स्थैतिक तरीकों तक पहुंच है। स्थिर विधियां उदाहरण की स्थिति को बदल नहीं सकती हैं ( एक संकलन त्रुटि की कोशिश कर रहा है)।

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

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

+8

यह * आवृत्ति * के लिए अप्रासंगिक है। एकमात्र चीज चर के * घोषित प्रकार * है। यह एक भयानक, भयानक शरारत और भाषा डिजाइनरों, आईएमओ के हिस्से पर एक गलती है। –

+1

हां, यह उदाहरण के लिए अप्रासंगिक है, लेकिन मुझे नहीं लगता कि एक आवृत्ति से स्थिर विधि को कॉल करना एक पूर्ण त्रुटि होनी चाहिए। यह सिर्फ वास्तव में खराब शैली है। आईएमएचओ, एक वर्ग या तो सभी स्थैतिक तरीकों से होना चाहिए, या स्थैतिक विधियों को निजी होना चाहिए, लेकिन मैं नहीं चाहता कि संकलक इसे लागू करे। –

+1

@ बिल: मुझे नहीं लगता कि यह शुरुआती दिनों में चेतावनी भी देता है। चेतावनी को जोड़ा गया क्योंकि यह लोगों को गुमराह कर रहा था।इसे अनुमति देने में * लाभ * क्या है? –

3

यह कोई त्रुटि नहीं है क्योंकि यह कल्पना का हिस्सा है, लेकिन आप स्पष्ट रूप से तर्क के बारे में पूछ रहे हैं, जिसे हम सभी अनुमान लगा सकते हैं।

मेरा अनुमान है कि इसका स्रोत वास्तव में कक्षा में किसी विधि को बिना किसी परेशानी के एक स्थिर विधि का आह्वान करने की अनुमति देना है। चूंकि एक्स() को कॉल करना कानूनी है (यहां तक ​​कि स्वयं वर्ग के नाम के बिना), यह .x() को कॉल करना भी कानूनी होना चाहिए, और इसलिए किसी ऑब्जेक्ट के माध्यम से कॉल करना कानूनी भी बनाया गया था।

यह उपयोगकर्ताओं को राज्य में बदलाव नहीं करने पर निजी कार्यों को स्थिर में बदलने में भी मदद करता है।

इसके अलावा, compilers आम तौर पर त्रुटियों की घोषणा जब वहाँ कोई रास्ता नहीं है कि यह एक प्रत्यक्ष त्रुटि का कारण बन सकता है से बचने की कोशिश। चूंकि स्थैतिक विधि राज्य या आविष्कार वस्तु के बारे में परवाह नहीं करती है, इसलिए यह अनुमति देने के लिए वास्तविक त्रुटि (केवल भ्रम) का कारण नहीं बनती है। एक चेतावनी पर्याप्त है।

+2

@ यूरी: कक्षा के नाम को निर्दिष्ट किए बिना इसे मौजूदा कक्षा में उपलब्ध कराने में काफी आसान है। सी # ने इसे प्रबंधित किया, और जावा कंपाइलर्स अंतर को बताने में कामयाब रहे (क्योंकि आपको उस मामले में कोई चेतावनी नहीं मिलेगी) तो इसे इस तरह क्यों निर्दिष्ट किया जाना चाहिए? –

2

उदाहरण चर संदर्भ के प्रयोजन ही प्रकार जो स्थिर encloses आपूर्ति है। आप instance.staticMethod या EnclosingClass.staticMethod के माध्यम से एक स्थिर लागू बाइट कोड को देखें, तो एक ही आह्वान स्थिर विधि बाईटकोड पैदा करता है। उदाहरण के लिए कोई संदर्भ प्रकट होता है।

भी कारण है कि यह वहाँ में है के रूप में जवाब है, अच्छी तरह से यह सिर्फ है। जब तक आप कक्षा का उपयोग करते हैं। और एक उदाहरण के माध्यम से आप भविष्य में भ्रम से बचने में मदद करेंगे।

-9

मैं सिर्फ इस पर विचार करें:

instanceVar.staticMethod(); 

इस के लिए आशुलिपि होने के लिए:

instanceVar.getClass().staticMethod(); 

आप हमेशा यह करने के लिए किया था, तो:

SomeClass.staticMethod(); 

तो आप नहीं होगा स्थिर तरीकों के लिए विरासत का लाभ उठाने में सक्षम।

यह है कि, उदाहरण के माध्यम से स्थैतिक विधि को कॉल करके आपको यह जानने की आवश्यकता नहीं है कि उदाहरण किस संकलित वर्ग को संकलित समय पर है, केवल यह है कि यह विरासत श्रृंखला के साथ कहीं भी staticMethod() लागू करता है।

संपादित करें: यह जवाब गलत है। विवरण के लिए टिप्पणियां देखें।

+1

अच्छा, यह एक और कारण है कि इसकी अनुमति क्यों नहीं दी जानी चाहिए - क्योंकि आप भी गुमराह हो रहे हैं। यह कार्य नहीं करता है जैसा आप चाहते हैं। यह * केवल * आपके उदाहरण में * घोषित * प्रकार "instanceVar" का उपयोग करेगा। बिल्ली, उदाहरण वार का मूल्य भी शून्य हो सकता है। –

+0

@ जोन: मैं इस धारणा के तहत था कि getClass() आपको ऑब्जेक्ट का वास्तविक वर्ग देगा, न कि परिवर्तनीय घोषित प्रकार। जावाडोक इस मुद्दे पर अस्पष्ट है, इसलिए मैं इसका परीक्षण करने जा रहा हूं। – Clayton

+1

@ क्लेटन: हाँ, लेकिन यह getClass() को कॉल नहीं करता है। मैं एक उदाहरण के साथ अपना जवाब संपादित करूंगा। –

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

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