अंतिम स्थिर विधि का व्यवहार


123

मैं स्थिर पद्धति के साथ संशोधक के साथ खेल रहा हूं और एक अजीब व्यवहार के साथ आया हूं।

जैसा कि हम जानते हैं, स्थिर तरीकों को ओवरराइड नहीं किया जा सकता है, क्योंकि वे उदाहरण के बजाय कक्षा से जुड़े होते हैं।

तो अगर मैं नीचे स्निपेट है, यह ठीक संकलन करता है

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

लेकिन अगर मैं अंतिम संशोधनकर्ता को कक्षा A में स्थिर विधि में शामिल करता हूं, तो संकलन विफल रहता है ts () में B, t को ओवरराइड नहीं कर सकता () A में; ओवरराइड विधि स्थिर अंतिम है

ऐसा क्यों हो रहा है जब स्थैतिक विधि को ओवरराइड नहीं किया जा सकता है?


2
यह अजीब लगता है, प्रश्न के लिए +1, लेकिन अब तक कोई भी उत्तर संतोषजनक नहीं है।
राकेश जुयाल

1
यह ओवरराइड नहीं है। यह अभी भी ए। () पर है।
एलेक्स फेनमैन

जवाबों:


166

स्थैतिक तरीकों को ओवरराइड नहीं किया जा सकता है लेकिन उन्हें छिपाया जा सकता है। ts()बी की विधि अधिभावी नहीं है (बहुरूपता के अधीन नहीं) ts()एक की लेकिन यह छिपा दिया जाएगा। यदि आप ts()बी में कॉल करते हैं (नहीं A.ts()या B.ts()... बस ts()), बी ts()में से एक को कॉल किया जाएगा और ए नहीं। क्योंकि यह बहुरूपता के अधीन नहीं है, तो ए में कॉल कभी भी बी में एक को पुनर्निर्देशित नहीं किया जाएगा।

कीवर्ड finalछिपाए जाने से विधि को अक्षम कर देगा। इसलिए उन्हें छिपाया नहीं जा सकता है और ऐसा करने का प्रयास एक संकलक त्रुटि का परिणाम देगा।

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


30
करने के लिए शायद आपका जवाब, है जो सही मेरा मानना है कि खत्म, समस्या यहां मूल रूप से एक बुरा संकलक त्रुटि संदेश है: यह होना चाहिए कहते हैं बी नहीं कर सकते छिपाने ts () ए एक स्थिर विधि अंतिम घोषणा में घोषित किया गया है यह छुपाया नहीं जा सकता।
शॉन ओवेन

2
@ सीन ओवेन: मुझे भी ऐसा ही लगता है। 'छुपाना' शब्द का इस्तेमाल जावा स्पेसिफिकेशन में भी किया जाता है, इसलिए इसे कंपाइलर मैसेज में इस्तेमाल नहीं किया जाता।
नावामन

2
यह एक विशेषता भी क्यों है? यह किस संदर्भ में उपयोगी होगा?
user253751

सार्वजनिक वर्ग टेस्ट {अंतिम स्थिर सार्वजनिक शून्य मुख्य (स्ट्रिंग ... srik) {System.out.println ("मुख्य विधि में"); ts (); } सार्वजनिक स्थैतिक शून्य ts () {बच्चा c = नया बच्चा (); c.ts (); System.out.println ("टेस्ट ts"); }} पब्लिक क्लास चाइल्ड एक्सटेंड्स टेस्ट {पब्लिक स्टैटिक void ts () {System.out.println ("चाइल्ड ts"); }} हाय कैन यू मुझे समझा सकता है कि इस परिदृश्य में क्या होता है
श्रीकांत आर

@ सीनियन मुझे नहीं लगता कि यह सही है या नहीं, कंपाइलर को यह कहना चाहिए कि चूंकि A#tsविरासत में मिला है और इस तरह की विधि पहले से मौजूद है B, बस एक ही हस्ताक्षर और एक अलग संशोधक ( final) के साथ दो तरीके होने से यह ओवरलोड के रूप में काम नहीं करेगा। काश, मैं इसके लिए एक सरल संदेश के बारे में सोच सकता, हालांकि
यूजीन

13

स्थैतिक तरीकों को खत्म नहीं किया जा सकता है

यह बिल्कुल सच नहीं है। उदाहरण कोड वास्तव में इसका मतलब है कि बी में विधि ts ए में विधि ts छुपाती है। इसलिए यह बिल्कुल ओवरराइडिंग नहीं है। जावरंच पर एक अच्छी व्याख्या है।


4
यह सच है कि सटीक नहीं है। स्थिर विधियों को ओवरराइड नहीं किया जा सकता है, लेकिन छिपाया जा सकता है यदि आप उन्हें क्लास के नाम के बजाय उदाहरण संदर्भ में बुला रहे हैं।
जॉन मर्सिएर

1
दुर्भाग्य से आपका लिंक किसी भी अधिक काम नहीं कर रहा है। क्या इसे ठीक करना संभव है?
मथियास बदर

Javaranch लिंक काम नहीं कर रहा है, लेकिन प्रमुख शब्द Googling ने इस लिंक को कोड रिंच पर बदल दिया
Sundeep

मैंने सुंदरदीप द्वारा पोस्ट किए गए लिंक द्वारा मृत लिंक को बदलकर पोस्ट को संपादित किया है।
एम सी सम्राट

10

स्टैटिक विधियाँ वर्ग की हैं, उदाहरण की नहीं।

A.ts()और B.ts()हमेशा अलग तरीके होने जा रहे हैं।

वास्तविक समस्या यह है कि जावा आपको एक उदाहरण ऑब्जेक्ट पर स्थिर तरीके से कॉल करने देता है। उपवर्ग के उदाहरण से पुकारे जाने पर माता-पिता वर्ग के समान हस्ताक्षर वाली स्थैतिक विधियाँ छिपी हुई हैं । हालाँकि, आप अंतिम विधियों को ओवरराइड / छिपा नहीं सकते ।

आपको लगता है कि त्रुटि संदेश ओवरराइड के बजाय छिपे हुए शब्द का उपयोग करेगा ...


6

आप एक स्थिर विधि को अंतिम बनाने के बारे में सोचने की स्थिति में खुद को पा सकते हैं, निम्नलिखित पर विचार कर सकते हैं:

निम्नलिखित कक्षाएं होने:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

अब इन विधियों को कॉल करने का 'सही' तरीका होगा

A.ts();
B.ts();

जिसके परिणामस्वरूप ABआप उदाहरणों पर विधियों को भी कॉल कर सकते हैं:

A a = new A();
a.ts();
B b = new B();
b.ts();

जिसके परिणामस्वरूप भी होगा AB

अब निम्नलिखित पर विचार करें:

A a = new B();
a.ts();

वह छपेगा A। जब से आप वास्तव में कक्षा की वस्तु हैं, तब आपको आश्चर्य हो सकता है B। लेकिन चूंकि आप इसे एक प्रकार के संदर्भ से बुला रहे हैं A, यह कॉल करेगा A.ts()। आप Bनिम्नलिखित कोड के साथ प्रिंट कर सकते हैं :

A a = new B();
((B)a).ts();

दोनों ही मामलों में आपके पास मौजूद वस्तु वास्तव में कक्षा से है B। लेकिन ऑब्जेक्ट को इंगित करने वाले पॉइंटर के आधार पर, आप विधि को Aया उससे कॉल करेंगे B

अब मान लेते हैं कि आप क्लास के डेवलपर हैं Aऔर आप सब-क्लासिंग की अनुमति देना चाहते हैं। लेकिन आप वास्तव में विधि चाहते हैं ts(), जब भी बुलाया जाता है, यहां तक ​​कि एक उपवर्ग से भी, यही वह है जो आप इसे करना चाहते हैं और एक उपवर्ग संस्करण द्वारा छिपाया नहीं जाना चाहिए। तब आप इसे बना सकते थे finalऔर इसे उपवर्ग में छिपे रहने से रोक सकते थे। और आप यह सुनिश्चित कर सकते हैं कि निम्न कोड आपकी कक्षा से विधि को बुलाएगा A:

B b = new B();
b.ts();

ठीक है, मान लिया कि किसी तरह का निर्माण किया है, लेकिन यह कुछ मामलों के लिए समझ में आ सकता है।

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


0

B में ts () विधि A में ts () विधि को ओवरराइड नहीं कर रही है, यह बस एक अन्य विधि है। B वर्ग A में ts () विधि को नहीं देखता है क्योंकि यह स्थिर है, इसलिए यह ts () नामक अपनी विधि की घोषणा कर सकता है।

हालाँकि, यदि विधि अंतिम है, तो संकलक उठाएगा कि A में एक ts () विधि है जिसे B में ओवरराइड नहीं किया जाना चाहिए।


मुझे नहीं लगता कि यह बताता है कि 'अंतिम' का अर्थ अचानक इन तरीकों से सह-अस्तित्व नहीं हो सकता है। जैसा कि आप कहते हैं, 'अंतिम' के बिना, कोई समस्या नहीं है। आप कहते हैं कि यह ओवरराइडिंग नहीं है, लेकिन फिर समस्या यह है कि बी ए के तरीके को ओवरराइड नहीं कर सकता है।
सीन ओवेन

यह सुनिश्चित करता है, मैं बताता हूं कि बी ए (यह 'छिपा हुआ है') में विधि ts () नहीं देखता है, लेकिन अंतिम संशोधक उन कक्षाओं से 'छिपाना' तरीकों को नहीं करता है जो एक और एक का विस्तार करते हैं। लेकिन एह, ठीक है।
18

0

मुझे लगता है कि संकलन त्रुटि यहाँ काफी भ्रामक थी। यह नहीं कहा जाना चाहिए था "ओवरराइड विधि स्थिर अंतिम है।", लेकिन इसके बजाय यह कहना चाहिए कि "ओवरराइड विधि अंतिम है।" स्थिर संशोधक यहाँ अप्रासंगिक है।


1
तो आप बी में स्थैतिक विधि को ए में एक से आगे निकलने पर विचार करते हैं?
कोरे तुगे

@KorayTugay मुझे आश्चर्य है कि अगर कंपाइलर पहली बार संभावित अधिकनीय विधि को देखता है (एक पल के लिए स्थैतिक को अनदेखा करता है), तो विफल होने पर अंतिम देखता है। हालांकि सिर्फ एक जंगली अनुमान है
यूजीन

Balus मुझे लगता है कि यह एकमात्र कम गुणवत्ता वाला उत्तर है जो आपके पास StackOverflow में है। आपके सभी असाधारण जवाबों को ध्यान में रखते हुए, यह उनका नहीं है। @ बालसु
कोरे तुगे

@KorayTugay: उस समय मेरे पास टिप्पणी करने के लिए पर्याप्त प्रतिष्ठा नहीं थी :) यदि आप वापस पिंग करते हैं, तो मैं जवाब को हटा दूंगा, कोई बात नहीं।
बालुसक

0

गैर-स्थैतिक तरीकों के विपरीत, जावा में एक स्थिर विधि को ओवरराइड नहीं किया जा सकता है। लेकिन उन्हें स्थिर और गैर-स्थैतिक डेटा सदस्यों की तरह विरासत में मिला है। यही कारण है कि मूल नाम के साथ एक गैर-स्थिर पद्धति को मूल श्रेणी में नहीं बनाया जा सकता है

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

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

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