जावा स्थैतिक विधियों को ओवरराइड करने की अनुमति क्यों नहीं देता है?


534

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

यदि संभव हो, तो कृपया एक उदाहरण का उपयोग करें।


3
अधिकांश OOP भाषाएँ इसकी अनुमति नहीं देती हैं।
jmucchiello

7
@jmucchiello: मेरा जवाब देखें। मैं भी आपके जैसा ही सोच रहा था, लेकिन फिर रूबी / स्मॉलटाक 'क्लास' के तरीकों के बारे में सीखा और इसलिए अन्य सच्ची OOP भाषाएँ हैं जो ऐसा करती हैं।
केविन ब्रॉक

5
@jmucchiello अधिकांश OOP भाषा वास्तविक OOP भाषा नहीं है (मैं स्मॉलटाक के बारे में सोचता हूं)
mathk

इसके अलावा देखें stackoverflow.com/q/370962/632951
Pacerier

1
हो सकता है क्योंकि जावा संकलन समय पर स्थिर तरीकों से कॉल का समाधान करता है। इसलिए, भले ही आपने लिखा हो Parent p = new Child()और फिर p.childOverriddenStaticMethod()संकलक इसे Parent.childOverriddenStaticMethod()संदर्भ प्रकार को देखकर हल करेगा ।
मनोज

जवाबों:


494

ओवरराइडिंग एक वर्ग की आवृत्ति पर निर्भर करता है। बहुरूपता की बात यह है कि आप एक वर्ग को उपवर्गित कर सकते हैं और उन उपवर्गों को लागू करने वाली वस्तुओं में सुपरक्लास में परिभाषित समान विधियों (और उपवर्गों में ओवरराइड) के लिए अलग-अलग व्यवहार होंगे। एक स्थिर विधि किसी भी वर्ग के उदाहरण के साथ संबद्ध नहीं है इसलिए अवधारणा लागू नहीं है।

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


18
... लेकिन जावा में केवल "सही"। उदाहरण के लिए, स्काला के "स्टैटिक क्लासेस" (जिसे कहा जाता है objects) के बराबर तरीकों की ओवरलोडिंग की अनुमति देता है।

32
उद्देश्य-सी भी वर्ग विधियों को ओवरराइड करने की अनुमति देता है ।
रिचर्ड

11
एक संकलन-समय प्रकार पदानुक्रम और एक रन-टाइम प्रकार पदानुक्रम है। यह पूछने का सही अर्थ है कि एक स्थिर विधि कॉल उन परिस्थितियों में रन-टाइम प्रकार पदानुक्रम का लाभ क्यों नहीं उठाता है जहां एक है। जावा में ऐसा तब होता है जब किसी ऑब्जेक्ट ( obj.staticMethod()) से एक स्थिर विधि को कॉल किया जाता है - जिसे अनुमति दी जाती है और संकलन-समय प्रकारों का उपयोग किया जाता है। जब स्थिर कॉल किसी वर्ग की गैर-स्थिर पद्धति में होता है, तो "वर्तमान" ऑब्जेक्ट एक प्रकार का वर्ग हो सकता है - लेकिन व्युत्पन्न प्रकारों पर परिभाषित स्थिर तरीकों को नहीं माना जाता है (वे रन-टाइम प्रकार में हैं पदानुक्रम)।
स्टीव पॉवेल

18
मुझे यह स्पष्ट करना चाहिए था: यह सच नहीं है कि अवधारणा लागू नहीं है
स्टीव पॉवेल

13
यह उत्तर, जबकि सही है, यह ओपी की अपेक्षाओं को पूरा करने के लिए "यह कैसे है" के बजाय "यह कैसा है" और अधिक सटीक है कि यह कैसे हो सकता है, इसलिए, यहाँ, अपने आप और अन्य। "यह कैसे है" के अलावा अन्य स्थिर तरीकों को ओवरराइड करने से रोकने का कोई ठोस कारण नहीं है। मुझे लगता है कि यह व्यक्तिगत रूप से एक दोष है।
रिचीह

186

व्यक्तिगत रूप से मुझे लगता है कि यह जावा के डिजाइन में एक दोष है। हां, हां, मैं समझता हूं कि गैर-स्टैटिक विधियाँ एक उदाहरण से जुड़ी होती हैं जबकि स्टैटिक विधियाँ किसी वर्ग आदि से जुड़ी होती हैं। फिर भी, निम्नलिखित कोड पर विचार करें:

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

यह कोड काम नहीं करेगा जैसा कि आप उम्मीद कर सकते हैं। अर्थात्, विशेष कर्मचारी को नियमित कर्मचारियों की तरह 2% बोनस मिलता है। लेकिन अगर आप "स्टैटिक" को हटाते हैं, तो स्पेशलइम्प्लॉई को 3% बोनस मिलता है।

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

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

लेकिन यह काम नहीं करता है।

और हाँ, हाँ, मैं इसे काम करने के लिए उपरोक्त कोड को फिर से लिखने के किसी भी तरीके के बारे में सोच सकता हूं। मेरा कहना यह नहीं है कि यह एक असम्भव समस्या पैदा करता है, लेकिन यह अलिखित प्रोग्रामर के लिए एक जाल बनाता है, क्योंकि भाषा वैसा व्यवहार नहीं करती जैसा कि मुझे लगता है कि एक उचित व्यक्ति उम्मीद करेगा।

शायद अगर मैंने एक ओओपी भाषा के लिए एक कंपाइलर लिखने की कोशिश की, तो मैं जल्दी से देखूंगा कि इसे क्यों लागू किया जाए ताकि स्थिर कार्यों को ओवरराइड किया जा सके यह मुश्किल या असंभव होगा।

या शायद कुछ अच्छे कारण है कि जावा इस तरह से व्यवहार करता है। क्या कोई इस व्यवहार का लाभ उठा सकता है, समस्या की कोई श्रेणी जिसे इसके द्वारा आसान बनाया गया है? मेरा मतलब है, मुझे सिर्फ जावा लैंग्वेज स्पेक की ओर इशारा न करें और कहें "देखें, यह प्रलेखित है कि यह कैसे व्यवहार करता है"। मुझे पता है। लेकिन क्या एक अच्छा कारण है कि वह इस तरह से व्यवहार करे? (स्पष्ट के अलावा "यह सही काम करना मुश्किल था" ...)

अपडेट करें

@VicKirk: यदि आपका मतलब है कि यह "खराब डिज़ाइन" है, क्योंकि यह फिट नहीं है कि जावा स्टेटिक्स को कैसे संभालता है, तो मेरा जवाब है, "ठीक है, दुआ, बिल्कुल।" जैसा कि मैंने अपने मूल पोस्ट में कहा था, यह काम नहीं करता है। लेकिन अगर आपका मतलब यह है कि यह इस अर्थ में खराब डिज़ाइन है कि जहां यह काम किया गया है, वहां एक ऐसी भाषा के साथ कुछ गलत होगा, जहां स्टैटिक्स को वर्चुअल फ़ंक्शंस की तरह ही ओवरराइड किया जा सकता है, तो यह किसी तरह एक अस्पष्टता का परिचय देगा या यह असंभव होगा। कुशलता से लागू करें या कुछ इस तरह, मैं जवाब देता हूं, "क्यों? अवधारणा के साथ क्या गलत है?"

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


11
@Bemrose: लेकिन यह मेरी बात है: मुझे ऐसा करने की अनुमति क्यों नहीं दी जानी चाहिए? हो सकता है कि "स्थिर" जो करना चाहिए, उसकी मेरी सहज अवधारणा आपसे भिन्न हो, लेकिन मूल रूप से मैं स्थैतिक के बारे में एक ऐसी विधि के रूप में सोचता हूं जो स्थिर हो सकती है क्योंकि यह किसी भी उदाहरण डेटा का उपयोग नहीं करता है, और जो आपको चाहिए क्योंकि वह स्थिर हो सकता है स्वतंत्र रूप से इसे कॉल करने के लिए। एक स्थैतिक स्पष्ट रूप से एक वर्ग से जुड़ा हुआ है: मुझे उम्मीद है कि Integer.valueOf को Integers से जोड़ा जा सकता है और Double.valueOf को डबल्स के साथ बांधने के लिए।
जय

9
@ewernli & Bemrose: हां हां, यह है कि यह कैसे है। मैं उस पर बहस नहीं कर रहा हूं। जैसा कि मेरे उदाहरण में कोड काम नहीं करता है, निश्चित रूप से मैं इसे लिखने की कोशिश नहीं करूंगा। मेरा सवाल है कि ऐसा क्यों है। (मुझे डर है कि यह उन वार्तालापों में से एक में बदल रहा है जहां हम सिर्फ संवाद नहीं कर रहे हैं। "माफ कीजिए मिस्टर सेल्समैन, क्या मैं इनमें से एक को लाल रंग में ले सकता हूं?" "नहीं, इसकी कीमत $ 5 है।" "हां, मुझे पता है कि इसकी लागत है। $ 5, लेकिन क्या मुझे एक लाल मिल सकता है? "" सर, मैंने अभी आपको बताया था कि इसकी कीमत $ 5 है। "" ठीक है, मुझे इसकी कीमत पता है, लेकिन मैं रंग के बारे में पूछ रहा था। "" मैंने पहले ही आपको कीमत बता दी थी! आदि)
जय

6
मुझे लगता है कि अंततः यह कोड भ्रामक है। विचार करें कि क्या उदाहरण पैरामीटर के रूप में पारित किया गया है। फिर आप कह रहे हैं कि रनटाइम इंस्टेंस को तय करना चाहिए कि कौन सी स्थैतिक विधि है। यह मूल रूप से मौजूदा उदाहरण के समानांतर एक पूरी अलग पदानुक्रम बनाता है। अब क्या होगा यदि एक उपवर्ग गैर-स्थैतिक के समान विधि हस्ताक्षर को परिभाषित करता है? मुझे लगता है कि नियम चीजों को काफी जटिल बना देंगे। यह ठीक उसी प्रकार की भाषा जटिलताएँ हैं जिनसे जावा बचने की कोशिश करता है।
यिशै

6
@ यिशै: आरई "रनटाइम उदाहरण निर्धारित करते हैं कि कौन सी स्थैतिक विधि कहा जाता है": बिल्कुल। मैं यह नहीं देखता कि आप स्थैतिक के साथ कुछ भी क्यों नहीं कर सकते हैं जो आप एक आभासी के साथ कर सकते हैं। "अलग पदानुक्रम": मैं कहूंगा, इसे उसी पदानुक्रम का हिस्सा बनाएं। स्टेटिक्स को एक ही पदानुक्रम में शामिल क्यों नहीं किया गया है? "उपवर्ग एक ही हस्ताक्षर को गैर-स्थैतिक परिभाषित करता है": मुझे लगता है कि यह अवैध होगा, ठीक उसी तरह जैसे कि यह कहना कि अवैध है, एक उपवर्ग को एक समान हस्ताक्षर के साथ एक फ़ंक्शन को ओवरराइड करें लेकिन एक अलग रिटर्न प्रकार, या सभी अपवादों को न फेंकें माता-पिता फेंकता है, या एक संकीर्ण गुंजाइश है।
Jay

28
मुझे लगता है कि जय के पास एक बिंदु है - यह मुझे बहुत आश्चर्यचकित करता है जब मुझे पता चला कि स्टैटिक्स को ओवरराइड नहीं किया जा सकता है। भाग में क्योंकि अगर मेरे पास A है someStatic()और B का विस्तार A से है, तो A में विधि से B.someMethod() बंध जाता है। यदि मैं बाद someStatic()में B को जोड़ देता हूं , तो कॉलिंग कोड को A.someStatic()फिर से जमा करने तक कॉलिंग कोड अभी भी इनवॉइस करता है । यह भी मुझे आश्चर्यचकित bInstance.someStatic()करता है कि घोषित प्रकार के इनस्टांस का उपयोग करता है , न कि रनटाइम प्रकार का क्योंकि यह संकलन नहीं लिंक पर बांधता है, इसलिए A bInstance; ... bInstance.someStatic()ए.सोमैस्टैटिक () यदि बी.सोमस्टैटिक () मौजूद है , तो आह्वान करता है।
लॉरेंस डॉल

42

संक्षिप्त उत्तर है: यह पूरी तरह से संभव है, लेकिन जावा ऐसा नहीं करता है।

यहां कुछ कोड दिए गए हैं जो वर्तमान स्थिति को दर्शाते हैं जावा में :

फ़ाइल Base.java:

package sp.trial;
public class Base {
  static void printValue() {
    System.out.println("  Called static Base method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Base method.");
  }
  void nonLocalIndirectStatMethod() {
    System.out.println("  Non-static calls overridden(?) static:");
    System.out.print("  ");
    this.printValue();
  }
}

फ़ाइल Child.java:

package sp.trial;
public class Child extends Base {
  static void printValue() {
    System.out.println("  Called static Child method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Child method.");
  }
  void localIndirectStatMethod() {
    System.out.println("  Non-static calls own static:");
    System.out.print("  ");
    printValue();
  }
  public static void main(String[] args) {
    System.out.println("Object: static type Base; runtime type Child:");
    Base base = new Child();
    base.printValue();
    base.nonStatPrintValue();
    System.out.println("Object: static type Child; runtime type Child:");
    Child child = new Child();
    child.printValue();
    child.nonStatPrintValue();
    System.out.println("Class: Child static call:");
    Child.printValue();
    System.out.println("Class: Base static call:");
    Base.printValue();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
    child.localIndirectStatMethod();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
    child.nonLocalIndirectStatMethod();
  }
}

यदि आप इसे चलाते हैं (मैंने इसे मैक पर किया था, ग्रहण से, जावा 1.6 का उपयोग करके) आपको मिलता है:

Object: static type Base; runtime type Child.
  Called static Base method.
  Called non-static Child method.
Object: static type Child; runtime type Child.
  Called static Child method.
  Called non-static Child method.
Class: Child static call.
  Called static Child method.
Class: Base static call.
  Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
  Non-static calls own static.
    Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
  Non-static calls overridden(?) static.
    Called static Base method.

यहाँ, केवल वे मामले जो आश्चर्यचकित कर सकते हैं (और जो प्रश्न के बारे में है) पहला मामला प्रतीत होता है :

"रन-टाइम प्रकार का उपयोग यह निर्धारित करने के लिए नहीं किया जाता है कि कौन से स्थिर तरीके कहलाते हैं, यहां तक ​​कि जब ऑब्जेक्ट ऑब्जेक्ट ( obj.staticMethod()) के साथ कहा जाता है ।"

और अंतिम मामला:

"जब किसी क्लास के ऑब्जेक्ट मेथड से स्टैटिक मेथड को कॉल किया जाता है, तो जो स्टैटिक मेथड चुना जाता है वह क्लास से ही ऐक्सेस होता है ना कि क्लास से ऑब्जेक्ट के रन-टाइम टाइप को डिफाइन करता है।"

किसी वस्तु उदाहरण के साथ कॉल करना

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

किसी वस्तु विधि के भीतर से कॉल करना

रन-टाइम प्रकार का उपयोग करके ऑब्जेक्ट विधि कॉल का समाधान किया जाता है, लेकिन स्टैटिक ( क्लास ) विधि कॉल का संकलन-समय (घोषित) प्रकार का उपयोग करके हल किया जाता है।

नियमों में बदलाव

इन नियमों को बदलने के लिए, ताकि अंतिम उदाहरण में कॉल किया जा सके Child.printValue() , स्टैटिक कॉल को रन-टाइम पर एक प्रकार के साथ प्रदान करना होगा, बजाय संकलक के ऑब्जेक्ट के घोषित वर्ग के साथ संकलन-समय पर कॉल को हल करना (या संदर्भ)। स्टैटिक कॉल तब कॉल को हल करने के लिए (डायनामिक) प्रकार पदानुक्रम का उपयोग कर सकते थे, जैसे कि ऑब्जेक्ट मेथड कॉल आज करते हैं।

यह आसानी से संभव होगा (यदि हमने जावा: -ओ को बदल दिया है), और यह अनुचित नहीं है, हालांकि, इसके कुछ दिलचस्प विचार हैं।

मुख्य विचार यह है कि हमें यह तय करने की आवश्यकता है कि कौन सी स्थिर विधि कॉल को ऐसा करना चाहिए।

फिलहाल, जावा में यह "quirk" भाषा है जिसमें obj.staticMethod()कॉल को ObjectClass.staticMethod()कॉल द्वारा प्रतिस्थापित किया जाता है (आमतौर पर एक चेतावनी के साथ)। [ नोट: ObjectClass संकलन-समय का प्रकार है obj।] इस तरह से ओवरराइड करने के लिए अच्छे उम्मीदवार होंगे, जो रन-टाइम प्रकार का है obj

अगर हमने ऐसा किया है तो यह विधि निकायों को पढ़ने के लिए कठिन बना देगा: माता-पिता वर्ग में स्थिर कॉल संभवतः गतिशील रूप से "पुन: रूट किए गए" हो सकते हैं। इससे बचने के लिए हमें स्टैटिक विधि को एक क्लास नाम के साथ कॉल करना होगा - और इससे कॉल्स को स्पष्ट रूप से कंपाइल-टाइम टाइप पदानुक्रम (अब) के साथ हल किया जाता है।

स्थैतिक विधि को लागू करने के अन्य तरीके अधिक मुश्किल हैं: this.staticMethod()इसका मतलब उसी तरह होना चाहिए obj.staticMethod(), जैसे कि रन-टाइम प्रकार this। हालांकि, इससे मौजूदा कार्यक्रमों के साथ कुछ सिरदर्द हो सकते हैं, जो सजावट के बिना (जाहिरा तौर पर स्थानीय) स्थिर तरीकों को कॉल करते हैं (जो यकीनन इसके बराबर है this.method())।

तो अनजाने कॉल के बारे में क्या staticMethod()? मेरा सुझाव है कि वे आज की तरह ही करें, और स्थानीय वर्ग के संदर्भ का उपयोग करके यह तय करें कि क्या करना है। अन्यथा बहुत भ्रम पैदा होता। बेशक इसका मतलब यह है कि अगर कोई गैर-स्थैतिक विधि थी, और अगर एक स्थैतिक विधि थी, तो method()इसका मतलब होगा । यह भ्रम का एक और स्रोत है।this.method()methodThisClass.method()method

अन्य बातें

यदि हमने इस व्यवहार को बदल दिया (और स्थैतिक रूप से गतिशील रूप से गैर-स्थानीय कॉल किया गया), तो हम शायद इसका अर्थ फिर से समझना चाहेंगे final , privateऔर protectedक्वालिफायर के रूप में पर staticएक वर्ग के तरीके। हम तो सब तथ्य यह है कि करने के लिए इस्तेमाल करने के लिए होता है private staticऔर public finalतरीकों ओवरराइड नहीं कर रहे हैं, और इसलिए सुरक्षित रूप से संकलन समय पर हल किया जा सकता है, और "सुरक्षित" स्थानीय संदर्भ के रूप में पढ़ने के लिए कर रहे हैं।


"अगर हमने ऐसा किया है तो यह विधि निकायों को पढ़ने के लिए कठिन बना देगा: एक मूल वर्ग में स्थैतिक कॉल संभवतः गतिशील रूप से" पुन: रूट किए जा सकते हैं "।" यह सच है, लेकिन सामान्य गैर-स्थिर फ़ंक्शन कॉल के साथ वास्तव में यही होता है। यह सामान्य आभासी कार्यों के लिए एक सकारात्मक विशेषता के रूप में नियमित रूप से टाल दिया जाता है, समस्या नहीं है।
Jay

25

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

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

परिणामी उत्पादन:

0.02
0.02
0.02
0.03

हम क्या हासिल करने की कोशिश कर रहे थे :)

भले ही हम तीसरे वेरिएबल कार्ल को रेग्युलर एम्प्लॉई घोषित करते हैं और उसे स्पेशल इम्प्लॉई का उदाहरण देते हैं, फिर भी हमारे पास रेग्युलर इम्प्लॉई का पहला कॉल होगा और दूसरे मामले में स्पेशल इम्प्लॉई का कॉल आएगा।

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

बस आउटपुट कंसोल को देखें:

0.02
0.03

;)


9
हां परावर्तन बहुत ही एकमात्र चीज है जो कोई भी कर सकता है - लेकिन सवाल यह बिल्कुल नहीं है - हालांकि यह यहाँ उपयोगी है
Mr_and_Mrs_D

1
यह उत्तर सबसे बड़ी हैक है जिसे मैंने अब तक सभी जावा विषयों में देखा है। यह अभी भी पढ़ने के लिए मजेदार था :)
वृषभ

19

JVM द्वारा स्टैटिक विधियों को वैश्विक माना जाता है, वहाँ वस्तु उदाहरण के लिए बाध्य नहीं हैं।

यह वैचारिक रूप से संभव हो सकता है यदि आप क्लास ऑब्जेक्ट्स (जैसे कि स्मॉलटॉक जैसी भाषाओं) से स्थिर तरीकों को कॉल कर सकते हैं लेकिन यह जावा में ऐसा नहीं है।

संपादित करें

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

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

आप कक्षाओं पर प्रतिबिंबित कर सकते हैं, लेकिन यह वहां रुक जाता है। आप एक स्थिर विधि का उपयोग करके clazz1.staticMethod(), लेकिन उपयोग नहीं करते हैं MyClass.staticMethod()। एक स्थैतिक विधि किसी वस्तु से बंधी नहीं होती है और इसलिए thisन ही कोई धारणा होती हैsuper एक स्थिर विधि में। एक स्थिर विधि एक वैश्विक कार्य है; इसके परिणामस्वरूप बहुरूपता की भी कोई धारणा नहीं है और इसलिए, विधि अधिभावी का कोई मतलब नहीं है।

लेकिन यह संभव हो सकता है यदि MyClassरन-टाइम पर एक ऑब्जेक्ट था, जिस पर आप एक विधि लागू करते हैं, जैसा कि स्मॉलटाक में (या शायद एक टिप्पणी के रूप में JRuby, लेकिन मुझे JRuby का कुछ भी पता नहीं है)।

अरे, एक ओर बात। आप एक वस्तु के माध्यम से एक स्थैतिक विधि को लागू कर सकते हैं, obj1.staticMethod()लेकिन वास्तव में इसके लिए चीनी की मात्रा को कम MyClass.staticMethod()करना चाहिए और इससे बचना चाहिए। यह आमतौर पर आधुनिक आईडीई में एक चेतावनी उठाता है। मुझे नहीं पता कि उन्होंने कभी इस शॉर्टकट की अनुमति क्यों दी।


5
यहां तक ​​कि रूबी जैसी कई आधुनिक भाषाओं में कक्षा-विधियां हैं और उन्हें ओवरराइड करने की अनुमति है।
चन्द्र सेकर

3
जावा में ऑब्जेक्ट के रूप में कक्षाएं मौजूद हैं। "क्लास" क्लास देखें। मैं myObject.getClass () कह सकता हूं और यह मुझे उपयुक्त वर्ग ऑब्जेक्ट का एक उदाहरण लौटाएगा।
Jay

5
आपको केवल कक्षा का "विवरण" मिलता है - केवल कक्षा का नहीं। लेकिन अंतर सूक्ष्म है।
ewernli

आपके पास अभी भी कक्षा है, लेकिन यह वीएम (क्लास लोडर के पास) में छिपा हुआ है, उपयोगकर्ता के पास लगभग कोई पहुंच नहीं है।
मैथक

clazz2 instanceof clazz1ठीक से उपयोग करने के लिए आप इसके बजाय उपयोग कर सकते हैं class2.isAssignableFrom(clazz1), जो मुझे विश्वास है कि आपके उदाहरण में सच होगा।
साइमन फोर्सबर्ग

14

ओवरराइडिंग को गतिशील प्रेषण द्वारा संभव बनाया गया है , जिसका अर्थ है कि घोषित प्रकार की वस्तु इसके व्यवहार को निर्धारित नहीं करती है, बल्कि इसके अतिरिक्त समय को निर्धारित करती है:

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"

भले ही दोनों को lassieऔर kermitप्रकार की वस्तुओं के रूप में घोषित किया गया हो Animal, उनका व्यवहार (विधि .speak()) भिन्न होता है क्योंकि गतिशील प्रेषण केवल विधि कॉल को चलाने के समय में कार्यान्वित करने के लिए बाध्य करेगा .speak()- संकलन समय पर नहीं।

अब, यहाँ जहाँ staticकीवर्ड समझ में आने लगता है: "स्थिर" शब्द "डायनामिक" के लिए एक एंटोनॉम है। तो यही कारण है कि आप स्थैतिक विधियों को ओवरराइड नहीं कर सकते हैं क्योंकि स्थैतिक सदस्यों पर कोई गतिशील प्रेषण नहीं है - क्योंकि स्थैतिक का शाब्दिक अर्थ है "गतिशील नहीं"। यदि वे गतिशील रूप से भेजे जाते हैं (और इस तरह से ओवरराइड किया जा सकता है) तो staticकीवर्ड अब समझ में नहीं आएगा।


11

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

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog's eat but it didn't
    }
}


Output Animal Eating

जावा के बहुरूपता सिद्धांत के अनुसार, आउटपुट होना चाहिए Dog Eating
लेकिन परिणाम अलग था क्योंकि पॉलिमॉर्फिज्म का समर्थन करने के लिए जावा लेट बाइंडिंग का उपयोग करता है इसका मतलब है कि तरीकों को केवल रन-टाइम पर कहा जाता है लेकिन स्थिर तरीकों के मामले में नहीं। स्थैतिक विधियों में संकलक रन-टाइम के बजाय संकलित समय पर विधियां कहता है, इसलिए हमें संदर्भ के अनुसार विधियाँ मिलती हैं न कि किसी संदर्भ वाली वस्तु के अनुसार, इसीलिए आप कह सकते हैं कि यह व्यावहारिक रूप से स्थैतिक अतिरेक का समर्थन करता है, लेकिन यह नहीं है 'टी।


3
स्थैतिक तरीकों को ऑब्जेक्ट से कॉल करना बुरा है।
दिमित्री ज़गोरुलकिन

6

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


1
क्या आपने पहले से ही इसे कवर करने वाले किसी अन्य उत्तर को नहीं पढ़ा था और यह स्पष्ट किया था कि ये वैचारिक स्तर पर स्टैटिक्स को ओवरराइड करने से छूट देने के लिए पर्याप्त कारण नहीं हैं। हम जानते हैं कि यह काम नहीं करता है। यह पूरी तरह से "स्थैतिक तरीकों की ओवरराइडिंग की इच्छा के लिए साफ है और वास्तव में यह कई अन्य भाषाओं में संभव है।
रिचीएच

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

6

जावा (और कई ओओपी भाषाओं में, लेकिन मैं सभी के लिए नहीं बोल सकता हूं; और कुछ में स्थिर नहीं है) सभी विधियों में एक निश्चित हस्ताक्षर हैं - पैरामीटर और प्रकार। एक आभासी विधि में, पहला पैरामीटर निहित है: ऑब्जेक्ट के लिए एक संदर्भ और जब ऑब्जेक्ट के भीतर से कॉल किया जाता है, तो कंपाइलर स्वचालित रूप से जुड़ जाता हैthis

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

इस अंतर के कारण दोनों के बीच; आभासी तरीकों में हमेशा संदर्भ ऑब्जेक्ट (यानी this) का संदर्भ होता है, इसलिए फिर उस वस्तु के उदाहरण से संबंधित ढेर के भीतर कुछ भी संदर्भित करना संभव है। लेकिन स्थैतिक विधियों के साथ, चूंकि कोई संदर्भ पारित नहीं हुआ है, इसलिए यह विधि किसी भी वस्तु चर और तरीकों का उपयोग नहीं कर सकती है क्योंकि संदर्भ ज्ञात नहीं है।

यदि आप चाहते हैं कि जावा परिभाषा को बदल दे, ताकि हर विधि, स्थैतिक या आभासी के लिए एक वस्तु प्रसंग पारित हो जाए, तो आप सार में केवल आभासी विधियाँ होंगी।

जैसा कि किसी ने op में एक टिप्पणी में पूछा - इस सुविधा को चाहने का आपका कारण और उद्देश्य क्या है?

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

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

संपादित करें : एक अन्य टिप्पणी। अब जब मैं अंतर देख रहा हूं और जैसा कि मैं स्वयं जावा / सी # डेवलपर हूं, तो मैं समझ सकता हूं कि जावा डेवलपर्स से आपको जो उत्तर मिलेंगे, वे भ्रमित करने वाले हो सकते हैं यदि आप रूबी जैसी भाषा से आ रहे हैं। जावा staticविधियां रूबी classविधियों के समान नहीं हैं । जावा डेवलपर्स को यह समझने में कठिन समय लगेगा, क्योंकि जो लोग रूबी / स्मॉलटॉक जैसी भाषा के साथ काम करते हैं, वे इसके विपरीत होंगे। मैं देख सकता हूं कि यह कैसे इस तथ्य से बहुत भ्रमित होगा कि जावा "क्लास पद्धति" का उपयोग अन्य तरीकों के रूप में स्थैतिक तरीकों के बारे में बात करने के लिए भी करता है, लेकिन इसी शब्द का उपयोग रूबी द्वारा अलग तरीके से किया जाता है। जावा में रूबी स्टाइल क्लास के तरीके नहीं हैं (क्षमा करें); रूबी के पास जावा शैली के स्थिर तरीके नहीं हैं जो वास्तव में सिर्फ पुरानी प्रक्रियात्मक शैली के कार्य हैं, जैसा कि सी में पाया जाता है।

वैसे - सवाल के लिए धन्यवाद! मैंने क्लास के तरीकों (रूबी स्टाइल) के बारे में आज मेरे लिए कुछ नया सीखा।


1
बेशक, कोई कारण नहीं है कि जावा स्थिर तरीकों के लिए एक छिपे हुए पैरामीटर के रूप में "क्लास" ऑब्जेक्ट को पारित नहीं कर सकता है। यह सिर्फ यह करने के लिए डिज़ाइन नहीं किया गया था।
jmucchiello

6

ठीक है ... जवाब नहीं है, अगर आप इस परिप्रेक्ष्य से सोचते हैं कि जावा में एक ओवरराइड विधि को कैसे व्यवहार किया जाना चाहिए। यदि आप किसी स्थिर विधि को ओवरराइड करने का प्रयास करते हैं, तो आपको कोई कंपाइलर त्रुटि नहीं मिलती है। इसका मतलब है, यदि आप ओवरराइड करने की कोशिश करते हैं, तो जावा आपको ऐसा करने से नहीं रोकता है; लेकिन आप निश्चित रूप से वैसा ही प्रभाव प्राप्त नहीं करते हैं जैसा कि आप गैर-स्थिर तरीकों के लिए करते हैं। जावा में ओवरराइड करने का सीधा मतलब है कि किसी विशेष विधि को ऑब्जेक्ट के रन टाइम प्रकार के आधार पर कहा जाएगा, न कि इसके संकलन समय पर (जो कि स्थैतिक तरीकों के साथ है)। ठीक है ... किसी भी कारण के लिए अनुमान लगाते हैं कि वे अजीब व्यवहार क्यों करते हैं? क्योंकि वे कक्षा के तरीके हैं और इसलिए उनका संकलन हमेशा संकलन समय के दौरान ही संकलित समय प्रकार की जानकारी का उपयोग करके हल किया जाता है।

उदाहरण : आइए देखें कि यदि हम एक स्थैतिक विधि को ओवरराइड करने की कोशिश करते हैं तो क्या होता है: -

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

आउटपुट : -
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

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


5

सामान्य तौर पर यह स्थिर तरीकों की 'ओवरराइडिंग' की अनुमति देने के लिए कोई मतलब नहीं है क्योंकि यह निर्धारित करने का कोई अच्छा तरीका नहीं होगा कि कौन से रनटाइम पर कॉल किया जाए। कर्मचारी का उदाहरण लेते हुए, अगर हम RegularEmployee.getBonusMultiplier () कहते हैं - किस विधि को निष्पादित किया जाना है?

जावा के मामले में, कोई भी भाषा की परिभाषा की कल्पना कर सकता है जहां किसी वस्तु के उदाहरण के माध्यम से उन्हें तब तक स्थिर तरीकों से 'ओवरराइड' करना संभव है। हालाँकि, यह सब करना होगा नियमित कक्षा विधियों को फिर से लागू करना, बिना किसी लाभ के वास्तव में भाषा के साथ अतिरेक जोड़ना।


2
सहज रूप से, मुझे लगता है कि यह एक आभासी कार्य की तरह काम करना चाहिए। यदि B, A को विस्तारित करता है और A और B दोनों के पास doStuff नाम के वर्चुअल फ़ंक्शंस हैं, तो कंपाइलर जानता है कि A के उदाहरणों में A.doStuff का उपयोग करना चाहिए और B के उदाहरणों में B.doStuff का उपयोग करना चाहिए। यह स्थैतिक कार्यों के साथ क्यों नहीं कर सकता है? आखिरकार, संकलक जानता है कि प्रत्येक वस्तु किस वर्ग की है।
जय

एर्म ... जे, एक स्थिर विधि की आवश्यकता नहीं होती है (आमतौर पर नहीं होती है) एक उदाहरण पर कहा जाता है ...
मेरिटॉन

2
@meriton, लेकिन फिर यह और भी आसान है, नहीं? यदि एक स्थिर पद्धति को क्लासनाम का उपयोग करके बुलाया जाता है, तो आप क्लास के लिए उपयुक्त विधि का उपयोग करेंगे।
CPerkins

लेकिन फिर आपके लिए क्या ओवरराइडिंग है। यदि आप A.doStuff () कहते हैं, तो क्या यह उस संस्करण का उपयोग करना चाहिए जो "बी एक्सटेंड ए" में ओवरराइड किया गया था या "सी एक्सटेंड्स ए" में ओवरराइड किया गया संस्करण। और अगर आपके पास C या B है तो आप वैसे भी उन संस्करणों को कॉल कर रहे हैं ... कोई अति आवश्यक नहीं।
पीएसपीईड

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

5

ओवरराइड करके हम ऑब्जेक्ट प्रकार के आधार पर बहुरूपी प्रकृति बना सकते हैं। स्थैतिक विधि का वस्तु से कोई संबंध नहीं है। इसलिए जावा स्थैतिक विधि का समर्थन नहीं कर सकता।


5

मुझे जे और की टिप्पणी पसंद है ( https://stackoverflow.com/a/2223803/1517187 )।
मैं मानता हूं कि यह जावा का खराब डिजाइन है।
कई अन्य भाषाएँ स्थैतिक तरीकों को ओवरराइड करने का समर्थन करती हैं, जैसा कि हम पिछली टिप्पणियों में देखते हैं। मुझे लगता है कि जेई भी मेरी तरह डेल्फी से जावा आए हैं।
डेल्फी (ऑब्जेक्ट पास्कल) ओओपी को लागू करने वाली पहली भाषा थी।
यह स्पष्ट है कि कई लोगों के पास उस भाषा के साथ अनुभव था क्योंकि यह वाणिज्यिक जीयूआई उत्पादों को लिखने के लिए एकमात्र भाषा थी। और - हाँ, हम डेल्फी में स्थैतिक तरीकों को ओवरराइड कर सकते हैं। दरअसल, डेल्फी में स्थिर तरीकों को "क्लास मेथड्स" कहा जाता है, जबकि डेल्फी में "डेल्फी स्टैटिक मेथड्स" की अलग अवधारणा थी, जो शुरुआती बाइंडिंग के तरीके थे। देर से बाध्यकारी का उपयोग करने के तरीकों को ओवरराइड करने के लिए, "आभासी" निर्देश की घोषणा करें। इसलिए यह बहुत सुविधाजनक और सहज था और मैं जावा में इसकी उम्मीद करूंगा।


3

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

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

संपादित करें: ऐसा प्रतीत होता है कि भाषा डिजाइन में एक दुर्भाग्यपूर्ण निरीक्षण के माध्यम से, आप एक उदाहरण के माध्यम से स्थैतिक तरीकों को कॉल कर सकते हैं । आम तौर पर कोई भी ऐसा नहीं करता है। मेरी गलती।


8
"आप एक उदाहरण के माध्यम से स्थैतिक तरीकों को कॉल नहीं कर सकते हैं" वास्तव में, जावा के क्वैरक्स में से एक यह है कि आप एक उदाहरण के माध्यम से स्थिर तरीकों को कॉल कर सकते हैं, भले ही यह एक अत्यधिक खराब विचार है।
पॉवरलॉर्ड

1
वास्तव में जावा स्थिर सदस्यों को इंस्टेंस के माध्यम से एक्सेस करने की अनुमति देता है: जावा में स्टेटिक वैरिएबल
रिचर्ड जेपी ले गुएन

जब आप ऐसा करते हैं तो एक उचित आधुनिक आईडीई एक चेतावनी उत्पन्न करेगा, इसलिए कम से कम आप इसे पकड़ सकते हैं जबकि ओरेकल बैकवर्ड संगतता चीज को चालू रख सकता है।
गिम्बी

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

@ रिखीह वह नहीं है जिसके बारे में वे चुटकी ले रहे हैं। सवाल यह है कि इसे कॉल करने की अनुमति क्यों दी गई है variable.staticMethod(), इसके बजाय Class.staticMethod(), variableघोषित प्रकार के साथ एक चर कहां है Class। मैं मानता हूं कि यह खराब भाषा डिजाइन है।
फिशिनियर

3

जावा में ओवरराइड करने का सीधा मतलब है कि किसी विशेष विधि को ऑब्जेक्ट के रनटाइम प्रकार के आधार पर कहा जाएगा न कि इसके संकलन-समय प्रकार पर (जो ओवरराइड स्टैटिक विधियों के साथ मामला है)। चूंकि स्टैटिक मेथड्स क्लास मेथड हैं, वे इंस्टेंस मेथड नहीं हैं, इसलिए उनका इस तथ्य से कोई लेना-देना नहीं है कि संदर्भ किस ऑब्जेक्ट या इंस्टेंस की ओर इशारा करता है, क्योंकि स्टैटिक विधि की प्रकृति के कारण यह एक विशिष्ट वर्ग से संबंधित है। आप इसे उपवर्ग में पुन: प्रकाशित कर सकते हैं लेकिन उस उपवर्ग को अभिभावक वर्ग के स्थैतिक तरीकों के बारे में कुछ भी पता नहीं चलेगा, क्योंकि जैसा कि मैंने कहा, यह केवल उस वर्ग के लिए विशिष्ट है जिसमें यह घोषित किया गया है। ऑब्जेक्ट संदर्भों का उपयोग करके उन्हें एक्सेस करना जावा के डिजाइनरों द्वारा दी गई एक अतिरिक्त स्वतंत्रता है और हमें निश्चित रूप से उस अभ्यास को रोकने के बारे में नहीं सोचना चाहिए, जब वे इसे अधिक विवरण और उदाहरण के लिए प्रतिबंधित करते हैं। http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html


3

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

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

डायनेमिक बहुरूपता व्यवहार तब आता है जब एक प्रोग्रामर एक ऑब्जेक्ट का उपयोग करता है और एक इंस्टेंस विधि का उपयोग करता है। जेआरई विभिन्न वर्गों के विभिन्न उदाहरणों को मैप करेगा जो इस आधार पर होगा कि आप किस तरह की वस्तु का उपयोग कर रहे हैं।

जब आप स्थैतिक विधियों को ओवरराइड करते हुए कहते हैं, स्थैतिक विधियाँ हम वर्ग नाम का उपयोग करके प्राप्त करेंगे, जिसे संकलन समय पर लिंक किया जाएगा, इसलिए स्थैतिक विधियों के साथ रनटाइम पर विधियों को जोड़ने की कोई अवधारणा नहीं है। अतः "स्टैटिक मेथड्स" शब्द का कोई मतलब नहीं है।

नोट: भले ही आप किसी ऑब्जेक्ट के साथ क्लास विधि का उपयोग करते हैं, फिर भी जावा कंपाइलर इसे खोजने के लिए पर्याप्त बुद्धिमान है, और स्थैतिक लिंकिंग करेगा।


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

स्थैतिक का अर्थ संकलन समय नहीं है, स्थैतिक का अर्थ है कि यह किसी विशिष्ट वस्तु के बजाय कक्षा के लिए बाध्य है। यह स्थिर श्रेणी को छोड़कर, क्लास फैक्ट्री बनाने की तुलना में अधिक समझ में नहीं आता हैBox.createBox तुलना में अधिक समझ में आता है BoxFactory.createBox, और एक अपरिहार्य पैटर्न है जब अपवाद फेंकने के बिना निर्माण की त्रुटि की जांच करने की आवश्यकता होती है (निर्माता विफल नहीं हो सकते, वे केवल प्रक्रिया को मार सकते हैं / फेंक सकते हैं अपवाद), जबकि एक स्थिर विधि विफलता पर अशक्त हो सकती है, या यहां तक ​​कि सफलता / त्रुटि कॉलबैक को स्वीकार कर सकती है जैसे hastebin.com/codajahati.java
दिमित्री

2

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


1
ह G4uKu3_Gaurav। योगदान के लिए निर्णय लेने के लिए धन्यवाद। हालाँकि हम आम तौर पर इससे अधिक लंबे और अधिक विस्तृत उत्तर की उम्मीद करते हैं।
डीजेकेवर्थ 20

@DJClayworth आपको विस्तृत उत्तर के लिए इस लिंक का पालन करना चाहिए geeksforgeeks.org/…
g1ji

लिंक के लिए धन्यवाद। वास्तव में मैं यहां साइट के नए लोगों के लिए सहायक हो रहा हूं, यह समझाने के लिए कि साइट उन लोगों के लिए कैसे काम करती है, जिन्हें इसकी आदत नहीं है, इसलिए नहीं कि मुझे सवाल का जवाब चाहिए।
डीजेकेवर्थ

1

आसान समाधान: सिंगलटन उदाहरण का उपयोग करें। यह ओवरराइड और वंशानुक्रम की अनुमति देगा।

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

Haxe भाषा वर्ग:

package rflib.common.utils;
import haxe.ds.ObjectMap;



class SingletonsRegistry
{
  public static var instances:Map<Class<Dynamic>, Dynamic>;

  static function __init__()
  {
    StaticsInitializer.addCallback(SingletonsRegistry, function()
    {
      instances = null;
    });

  } 

  public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
  {
    if (instances == null) {
      instances = untyped new ObjectMap<Dynamic, Dynamic>();      
    }

    if (!instances.exists(cls)) 
    {
      if (args == null) args = [];
      instances.set(cls, Type.createInstance(cls, args));
    }

    return instances.get(cls);
  }


  public static function validate(inst:Dynamic, cls:Class<Dynamic>)
  {
    if (instances == null) return;

    var inst2 = instances[cls];
    if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
  }

}

बहुत अच्छा, यह पहली बार मैंने
हेक्स

1
यह जावा में क्लास पर ही एक स्थिर विधि के रूप में लागू किया गया है; Singleton.get()। रजिस्ट्री बस बॉयलरप्लेट ओवरहेड है, और यह जीसी को कक्षाओं में शामिल करती है।
लॉरेंस Dol

आप सही हैं, यह एक क्लासिक समाधान है। मुझे याद नहीं है कि मैंने रजिस्ट्री को क्यों चुना, शायद विचार का कुछ ढांचा था जिसके कारण यह परिणाम हुआ।
Raivo Fishmeister

1

एक स्थिर विधि, परिवर्तनशील, ब्लॉक या नेस्टेड वर्ग पूरे वर्ग के अंतर्गत आता है एक वस्तु के बजाय से संबंधित है।

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

उच्च सामंजस्य - एक वर्ग की केवल एक भूमिका होनी चाहिए। उदाहरण के लिए: एक कार वर्ग को केवल कार ऑब्जेक्ट का उत्पादन करना चाहिए न कि बाइक, ट्रक, प्लेन इत्यादि। लेकिन कार क्लास में कुछ विशेषताएं (व्यवहार) हो सकती हैं जो स्वयं के लिए हैं।

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


नीचे का टुकड़ा कोड स्थिर विधि को ओवरराइड करने की कोशिश करता है, लेकिन किसी भी संकलन की त्रुटि का सामना नहीं करेगा ।

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

ऐसा इसलिए है, क्योंकि यहां हम एक विधि को ओवरराइड नहीं कर रहे हैं, लेकिन हम इसे फिर से घोषित कर रहे हैं। जावा एक विधि (स्थिर / गैर-स्थैतिक) की पुनः घोषणा की अनुमति देता है।

कार श्रेणी के getVehileNumber () विधि से स्थिर कीवर्ड को हटाने से संकलन त्रुटि हो जाएगी, क्योंकि, हम स्थैतिक विधि की कार्यक्षमता को बदलने की कोशिश कर रहे हैं जो केवल वाहन वर्ग से संबंधित है।

इसके अलावा, अगर getVehileNumber () को अंतिम घोषित किया जाता है, तो कोड संकलित नहीं होगा, क्योंकि अंतिम कीवर्ड प्रोग्रामर को फिर से विधि घोषित करने से रोकता है।

public static final int getVehileNumber() {
return VIN;     }

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


1

यहाँ एक सरल व्याख्या है। एक स्थिर विधि एक वर्ग से जुड़ी होती है जबकि एक आवृत्ति विधि किसी विशेष वस्तु से जुड़ी होती है। ओवरराइड्स विशेष वस्तु से जुड़े ओवरराइड तरीकों के विभिन्न कार्यान्वयन को कॉल करने की अनुमति देते हैं। तो यह स्थैतिक विधि को ओवरराइड करने के लिए काउंटर-सहज है जो वस्तुओं से जुड़ा नहीं है, लेकिन पहली जगह में ही वर्ग है। इसलिए स्थैतिक तरीकों को इस बात के आधार पर अधिभूत नहीं किया जा सकता है कि कौन सी वस्तु इसे बुला रही है, यह हमेशा उस वर्ग से जुड़ा होगा जहां इसे बनाया गया था।


यह कैसे public abstract IBox createBox();अंदर IBox इंटरफ़ेस के लिए सहज ज्ञान युक्त है ? बॉक्स बायबॉक्स को ओवरराइड करने के लिए IBox को लागू कर सकता है, और एक वैध IBox में ऑब्जेक्ट परिणाम का निर्माण होता है, अन्यथा एक अशक्त वापस आ जाता है। कंस्ट्रक्टर "null" वापस नहीं कर सकते हैं और इसलिए आपको (1) अपवादों का उपयोग करने के लिए मजबूर किया जाता है (हम अभी क्या करते हैं), या (2) कारखाने की कक्षाएं बनाते हैं जो मैंने पहले कहा था, लेकिन एक तरह से जो novices या विशेषज्ञों का कोई मतलब नहीं है जावा का (जो अब हम भी करते हैं)। स्टेटिक अनइम्प्लीमेंटेड मेथड्स इसे हल करते हैं।
दिमित्री

-1

अब उपर्युक्त उत्तरों को देखकर सभी को पता है कि हम स्थैतिक तरीकों से आगे नहीं बढ़ सकते हैं, लेकिन किसी को उपवर्ग से स्थिर तरीकों तक पहुँचने की अवधारणा के बारे में गलतफहमी नहीं होनी चाहिए ।

हम सुपर क्लास के स्टैटिक तरीकों को उपवर्ग संदर्भ के साथ एक्सेस कर सकते हैं यदि यह स्टैटिक तरीका सब क्लास में परिभाषित नए स्टैटिक मेथड द्वारा छिपाया नहीं गया है।

उदाहरण के लिए, नीचे दिया गया कोड देखें: -

public class StaticMethodsHiding {
    public static void main(String[] args) {
        SubClass.hello();
    }
}


class SuperClass {
    static void hello(){
        System.out.println("SuperClass saying Hello");
    }
}


class SubClass extends SuperClass {
    // static void hello() {
    // System.out.println("SubClass Hello");
    // }
}

आउटपुट: -

SuperClass saying Hello

उप-वर्ग में स्थैतिक तरीकों को छिपाने के बारे में जानकारी के लिए जावा ऑरेकल डॉक्स देखें और आप जो कर सकते हैं उसे एक उपवर्ग में खोजें।

धन्यवाद


-3

निम्न कोड दिखाता है कि यह संभव है:

class OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriden Meth");   
}   

}   

public class OverrideStaticMeth extends OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriding Meth");   
}   

public static void main(String[] args) {   
OverridenStaticMeth osm = new OverrideStaticMeth();   
osm.printValue();   

System.out.println("now, from main");
printValue();

}   

} 

1
नहीं, यह नहीं है; के स्थिर घोषित प्रकार osmहै OverridenStaticMethनहीं OverrideStaticMeth
लॉरेंस Dol

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