जावा: एक सुपर विधि को कॉल करना जो एक ओवरराइड विधि कहलाता है


97
public class SuperClass
{
    public void method1()
    {
        System.out.println("superclass method1");
        this.method2();
    }

    public void method2()
    {
        System.out.println("superclass method2");
    }

}

public class SubClass extends SuperClass
{
    @Override
    public void method1()
    {
        System.out.println("subclass method1");
        super.method1();
    }

    @Override
    public void method2()
    {
        System.out.println("subclass method2");
    }
}



public class Demo 
{
    public static void main(String[] args) 
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1();
    }
}

मेरा अपेक्षित उत्पादन:

उपवर्ग Method1
सुपर क्लास Method1
सुपर क्लास Method2

वास्तविक उत्पादन:

उपवर्ग Method1
सुपर क्लास Method1
उपवर्ग Method2

मुझे पता है कि तकनीकी रूप से मेरे पास एक सार्वजनिक तरीका है, लेकिन मुझे लगा कि क्योंकि मैं सुपर बुला रहा था, सुपर के भीतर कोई भी कॉल सुपर में रहेगी, ऐसा नहीं हो रहा है। किसी भी विचार के साथ कि मैं इसे कैसे बना सकता हूं?


2
मुझे संदेह है कि आप "उत्तराधिकार पर रचना पसंद करना चाहते हैं" कर सकते हैं।
टॉम हॉल्टिन -

जवाबों:


80

कीवर्ड super"छड़ी" नहीं करता है। प्रत्येक विधि कॉल को व्यक्तिगत रूप से नियंत्रित किया जाता है, इसलिए भले ही आपको SuperClass.method1()कॉल करके मिला हो super, लेकिन यह भविष्य में आपके द्वारा किए जा सकने वाले किसी अन्य तरीके के कॉल को प्रभावित नहीं करता है।

इसका मतलब है कि वहाँ कॉल करने के लिए कोई सीधा रास्ता है SuperClass.method2()से SuperClass.method1()हालांकि जाए बिना SubClass.method2()जब तक आप का एक वास्तविक उदाहरण के साथ काम कर रहे हैं SuperClass

आप परावर्तन ( प्रलेखनjava.lang.reflect.Method.invoke(Object, Object...) देखें ) का उपयोग करके वांछित प्रभाव भी प्राप्त नहीं कर सकते हैं ।

[संपादित करें] अभी भी कुछ भ्रम की स्थिति है। मुझे एक अलग व्याख्या की कोशिश करते हैं।

जब आप आह्वान करते हैं foo(), तो आप वास्तव में आह्वान करते हैं this.foo()। जावा बस आपको छोड़ देता है this। प्रश्न में उदाहरण में, प्रकार thisहै SubClass

इसलिए जब Java कोड को निष्पादित करता है SuperClass.method1(), तो यह अंत में आता हैthis.method2();

का उपयोग करके superइंगित की गई आवृत्ति को परिवर्तित नहीं करता है this। तो कॉल तब से चला जाता है SubClass.method2()जब thisप्रकार का होता है SubClass

शायद यह समझना आसान है जब आप कल्पना करते हैं कि जावा thisएक छिपे हुए पहले पैरामीटर के रूप में गुजरता है :

public class SuperClass
{
    public void method1(SuperClass this)
    {
        System.out.println("superclass method1");
        this.method2(this); // <--- this == mSubClass
    }

    public void method2(SuperClass this)
    {
        System.out.println("superclass method2");
    }

}

public class SubClass extends SuperClass
{
    @Override
    public void method1(SubClass this)
    {
        System.out.println("subclass method1");
        super.method1(this);
    }

    @Override
    public void method2(SubClass this)
    {
        System.out.println("subclass method2");
    }
}



public class Demo 
{
    public static void main(String[] args) 
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1(mSubClass);
    }
}

यदि आप कॉल स्टैक का अनुसरण करते हैं, तो आप देख सकते हैं कि thisकभी भी परिवर्तन नहीं होता है, यह हमेशा निर्मित उदाहरण है main()


क्या कोई कृपया इस का एक आरेख (वाक्य का इरादा) अपलोड कर सकता है जो स्टैक से गुजर रहा है? अग्रिम में धन्यवाद!
Laycat

2
@laycat: आरेख की कोई आवश्यकता नहीं है। बस याद रखें कि जावा के लिए कोई "मेमोरी" नहीं है super। हर बार जब यह एक विधि को बुलाता है, तो यह उदाहरण प्रकार को देखेगा, और इस प्रकार के साथ विधि की खोज करना शुरू कर देगा, चाहे आप कितनी बार बुलाए super। इसलिए जब आप method2एक उदाहरण पर कॉल करते हैं SubClass, तो यह हमेशा SubClassपहले से ही दिखाई देगा ।
आरोन दिगुल्ला

@AaronDigulla, क्या आप "Java में सुपर के लिए कोई मेमोरी नहीं है" के बारे में अधिक बता सकते हैं?
मेंगट

@ ट्रूमैनवर्ल्ड: जैसा कि मैंने अपने जवाब में कहा: उपयोग superसे उदाहरण नहीं बदलता है। यह कुछ छिपा हुआ क्षेत्र सेट नहीं करता है "अब से, सभी विधि कॉल का उपयोग शुरू करना चाहिए SuperClass"। या इसे दूसरे तरीके से रखने के लिए: इसका मूल्य thisनहीं बदलता है।
आरोन दिगुल्ला

@AaronDigulla, तो इसका मतलब यह है कि सुपर कीवर्ड वास्तव में सुपर क्लास में जाने के बजाय उपवर्ग में विरासत में मिले तरीकों को लागू करते हैं?
मेंगट

15

आप केवल ओवरराइडिंग विधियों (या ओवरराइडिंग क्लास के अन्य तरीकों) में ओवरराइड विधियों तक पहुँच सकते हैं।

इसलिए: या तो ओवरराइड संस्करण के अंदर ओवरराइड method2()या कॉल न करें super.method2()


8

आप उस thisकीवर्ड का उपयोग कर रहे हैं, जो वास्तव में "आपके द्वारा उपयोग की जा रही वस्तु के वर्तमान में चल रहे उदाहरण" को संदर्भित करता है, अर्थात, आप this.method2();अपने सुपरक्लास पर आह्वान कर रहे हैं , अर्थात यह आपके द्वारा ऑब्जेक्ट पर मेथड 2 () कॉल करेगा पुन: उपयोग कर रहा है, जो सबक्लास है।


8
सच है, और उपयोग thisनहीं करने से भी मदद नहीं मिलेगी। अयोग्य रूप से मंगलाचरण का उपयोग करता हैthis
सीन पैट्रिक फ्लोयड

3
यह क्यों उठ रहा है? यह इस सवाल का जवाब नहीं है। जब आप लिखेंगे method2()संकलक देखेंगे this.method2()। इसलिए अगर आप thisइसे हटा भी दें तो भी काम नहीं चलेगा। @ सीन पैट्रिक फ्लोयड जो कह रहा है वह सही है
शेरविन असगरी

4
@ शेरविन वह कुछ भी गलत नहीं कह रहा है, वह सिर्फ यह स्पष्ट नहीं कर रहा है कि क्या होगा यदि आप बाहर निकल जाते हैंthis
सीन पैट्रिक फ्लॉयड

4
उत्तर यह इंगित करने में सही है कि this"कंक्रीट रनिंग इंस्टेंस क्लास" (रनटाइम में जाना जाता है) को संदर्भित करता है और न कि (जैसा कि पोस्टर को लगता है) "वर्तमान संकलन-यूनिट क्लास" (जहां कीवर्ड का उपयोग किया जाता है, में जाना जाता है) संकलन समय)। लेकिन यह भ्रामक भी हो सकता है (जैसा कि शेरविन अंक): thisसादे तरीके से कॉल के साथ भी संदर्भित है; method2();के रूप में ही हैthis.method2();
leonbloy

7

मैं इसे इस तरह से सोचता हूं

+----------------+
|     super      |
+----------------+ <-----------------+
| +------------+ |                   |
| |    this    | | <-+               |
| +------------+ |   |               |
| | @method1() | |   |               |
| | @method2() | |   |               |
| +------------+ |   |               |
|    method4()   |   |               |
|    method5()   |   |               |
+----------------+   |               |
    We instantiate that class, not that one!

मुझे उस उपवर्ग को बाईं ओर थोड़ा घूमने दें, जो यह बताए कि नीचे क्या है ... (मनुष्य, मुझे ASCII ग्राफिक्स पसंद हैं)

We are here
        |
       /  +----------------+
      |   |     super      |
      v   +----------------+
+------------+             |
|    this    |             |
+------------+             |
| @method1() | method1()   |
| @method2() | method2()   |
+------------+ method3()   |
          |    method4()   |
          |    method5()   |
          +----------------+

Then we call the method
over here...
      |               +----------------+
 _____/               |     super      |
/                     +----------------+
|   +------------+    |    bar()       |
|   |    this    |    |    foo()       |
|   +------------+    |    method0()   |
+-> | @method1() |--->|    method1()   | <------------------------------+
    | @method2() | ^  |    method2()   |                                |
    +------------+ |  |    method3()   |                                |
                   |  |    method4()   |                                |
                   |  |    method5()   |                                |
                   |  +----------------+                                |
                   \______________________________________              |
                                                          \             |
                                                          |             |
...which calls super, thus calling the super's method1() here, so that that
method (the overidden one) is executed instead[of the overriding one].

Keep in mind that, in the inheritance hierarchy, since the instantiated
class is the sub one, for methods called via super.something() everything
is the same except for one thing (two, actually): "this" means "the only
this we have" (a pointer to the class we have instantiated, the
subclass), even when java syntax allows us to omit "this" (most of the
time); "super", though, is polymorphism-aware and always refers to the
superclass of the class (instantiated or not) that we're actually
executing code from ("this" is about objects [and can't be used in a
static context], super is about classes).

दूसरे शब्दों में, जावा भाषा विशिष्टता से उद्धृत :

प्रपत्र super.Identifierनामित फ़ील्ड को संदर्भित करता हैIdentifier वर्तमान ऑब्जेक्ट के , लेकिन वर्तमान ऑब्जेक्ट को वर्तमान वर्ग के सुपरक्लास के उदाहरण के रूप में देखा जाता है।

यह प्रपत्र लेक्सिक रूप से संलग्न उदाहरण के T.super.Identifierनाम Identifierसे संबंधित फ़ील्ड को संदर्भित करता है T, लेकिन उस उदाहरण के साथ सुपरक्लियर के उदाहरण के रूप में देखा जाता है T

आम आदमी की शर्तों में, thisमूल रूप से एक वस्तु है (* ** वस्तु; वही वस्तु जिसे आप चर में घुमा सकते हैं), तात्कालिक वर्ग का उदाहरण, डेटा डोमेन में एक सादा चर;superकोड के एक उधार ब्लॉक के लिए एक संकेतक की तरह है जिसे आप निष्पादित करना चाहते हैं, अधिक मात्र फ़ंक्शन कॉल की तरह, और यह उस वर्ग के सापेक्ष है जहां इसे कहा जाता है।

इसलिए यदि आप superसुपरक्लास से उपयोग करते हैं तो आपको सुपरड्यूपर क्लास [दादा दादी] से कोड प्राप्त होता है), जबकि यदि आप सुपरक्लास से उपयोग करते हैं this(या यदि इसका उपयोग किया जाता है) तो यह उपवर्ग की ओर इशारा करता रहता है (क्योंकि किसी ने इसे नहीं बदला है - और कोई नहीं सकता है)।


2

यदि आप नहीं चाहते हैं कि SuperClass.method1 को subClass.method2 पर कॉल करें, तो method2 को निजी बनाएं ताकि इसे ओवरराइड नहीं किया जा सके।

यहाँ एक सुझाव है:

public class SuperClass {

  public void method1() {
    System.out.println("superclass method1");
    this.internalMethod2();
  }

  public void method2()  {
    // this method can be overridden.  
    // It can still be invoked by a childclass using super
    internalMethod2();
  }

  private void internalMethod2()  {
    // this one cannot.  Call this one if you want to be sure to use
    // this implementation.
    System.out.println("superclass method2");
  }

}

public class SubClass extends SuperClass {

  @Override
  public void method1() {
    System.out.println("subclass method1");
    super.method1();
  }

  @Override
  public void method2() {
    System.out.println("subclass method2");
  }
}

यदि यह इस तरह से काम नहीं करता है, तो बहुरूपता असंभव होगा (या कम से कम आधा भी उपयोगी नहीं है)।


2

चूंकि ओवरराइड पाने के लिए एक विधि से बचने का एकमात्र तरीका कीवर्ड सुपर का उपयोग करना है , मैंने सोचा है कि मेथड 2 () को सुपरक्लास से दूसरे नए बेस क्लास में स्थानांतरित किया जाए और फिर सुपरक्लास से इसे कॉल करें :

class Base 
{
    public void method2()
    {
        System.out.println("superclass method2");
    }
}

class SuperClass extends Base
{
    public void method1()
    {
        System.out.println("superclass method1");
        super.method2();
    }
}

class SubClass extends SuperClass
{
    @Override
    public void method1()
    {
        System.out.println("subclass method1");
        super.method1();
    }

    @Override
    public void method2()
    {
        System.out.println("subclass method2");
    }
}

public class Demo 
{
    public static void main(String[] args) 
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1();
    }
}

आउटपुट:

subclass method1
superclass method1
superclass method2

2

this हमेशा वर्तमान में निष्पादित ऑब्जेक्ट को संदर्भित करता है।

इस बिंदु को और स्पष्ट करने के लिए यहां एक सरल रेखाचित्र दिया गया है:

+----------------+
|  Subclass      |
|----------------|
|  @method1()    |
|  @method2()    |
|                |
| +------------+ |
| | Superclass | |
| |------------| |
| | method1()  | |
| | method2()  | |
| +------------+ |
+----------------+

यदि आपके पास बाहरी बॉक्स का एक उदाहरण है, तो एक Subclassवस्तु, जहां भी आप बॉक्स के अंदर उद्यम करते हैं, यहां तक ​​कि Superclass'क्षेत्र' में भी, यह बाहरी बॉक्स का उदाहरण है।

क्या अधिक है, इस कार्यक्रम में केवल एक ही वस्तु है जो तीन वर्गों में से बनाई गई है, इसलिए thisकेवल एक चीज का उल्लेख कर सकते हैं और यह है:

यहां छवि विवरण दर्ज करें

जैसा कि नेटबीन्स 'हीप वॉकर' में दिखाया गया है ।


2
class SuperClass
{
    public void method1()
    {
        System.out.println("superclass method1");
        SuperClass se=new SuperClass();
        se.method2();
    }

    public void method2()
    {
        System.out.println("superclass method2");
    }
}


class SubClass extends SuperClass
{
    @Override
    public void method1()
    {
        System.out.println("subclass method1");
        super.method1();
    }

    @Override
    public void method2()
    {
        System.out.println("subclass method2");
    }
}

बुला

SubClass mSubClass = new SubClass();
mSubClass.method1();

आउटपुट

उपवर्ग Method1
सुपर क्लास Method1
सुपर क्लास Method2


1

मुझे विश्वास नहीं होता कि आप इसे सीधे कर सकते हैं। एक वर्कअराउंड सुपरक्लास में मेथड 2 का निजी आंतरिक कार्यान्वयन होगा, और इसे कॉल करें। उदाहरण के लिए:

public class SuperClass
{
    public void method1()
    {
        System.out.println("superclass method1");
        this.internalMethod2();
    }

    public void method2()
    {
        this.internalMethod2(); 
    }
    private void internalMethod2()
    {
        System.out.println("superclass method2");
    }

}

1

"यह" कीवर्ड वर्तमान वर्ग के संदर्भ को संदर्भित करता है। इसका मतलब है, जब यह विधि के अंदर उपयोग किया जाता है, तो 'वर्तमान' वर्ग अभी भी सबक्लास है और इसलिए, उत्तर समझाया गया है।


1

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

पुनश्च। विधियों के विपरीत, वर्ग के सदस्य चर पॉलीमॉर्फिक नहीं हैं।


0

इसी तरह के एक मामले के लिए अपने शोध के दौरान, मैं यह जानने के लिए उप-विधि में स्टैक ट्रेस की जांच करके समाप्त कर रहा हूं कि कॉल कहां से आ रही है। ऐसा करने के लिए शायद अधिक स्मार्ट तरीके हैं, लेकिन यह मेरे लिए काम करता है और यह एक गतिशील दृष्टिकोण है।

public void method2(){
        Exception ex=new Exception();
        StackTraceElement[] ste=ex.getStackTrace();
        if(ste[1].getClassName().equals(this.getClass().getSuperclass().getName())){
            super.method2();
        }
        else{
            //subclass method2 code
        }
}

मुझे लगता है कि सवाल का समाधान उचित है। विभिन्न तरीकों के नाम या यहां तक ​​कि विभिन्न पैरामीटर प्रकारों के साथ समस्या को हल करने के लिए निश्चित रूप से हैं, जैसे कि पहले से ही थ्रेड में उल्लिखित है, लेकिन मेरे मामले में मैं अलग-अलग तरीकों के नामों से भ्रमित करना पसंद नहीं करता।


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

प्रदर्शन के दृष्टिकोण से, मेरा कोड 'नए हैशपॉप () आकार ()' की तुलना में अधिक प्रभाव उत्पन्न नहीं करता है। हालाँकि, आप उन चिंताओं को नजरअंदाज कर सकते हैं जिनके बारे में आप सोच रहे हैं और मैं VM विशेषज्ञ नहीं हूं। मैं कक्षा के नामों की तुलना करके आपके संदेह को देखता हूं, लेकिन इसमें वह पैकेज शामिल है जो मुझे बहुत यकीन दिलाता है, यह मेरा मूल वर्ग है। वैसे भी, मुझे इसके बजाय हस्ताक्षर की तुलना करने का विचार पसंद है, आप ऐसा कैसे करेंगे? सामान्य तौर पर, यदि आपके पास यह निर्धारित करने के लिए एक चिकना तरीका है कि क्या कॉलर सुपरक्लास है या कोई और है जिसके बारे में मैं यहां सराहना करूंगा।
सिट्रिस्ट

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

मुझे बिंदु दिखाई देता है लेकिन धागे का सामान्य अनुरोध उचित है। किसी भी स्थिति में, यह किसी भी नेस्टेड विधि कॉल के साथ सुपरक्लास संदर्भ में सुपरक्लास विधि कॉल स्टेन्स को समझ सकता है। हालाँकि, सुपरक्लास के अनुसार विधि कॉल को निर्देशित करने का कोई तरीका नहीं है।
सीक्रेट

0

आगे उठाए गए प्रश्न के आउटपुट को और अधिक बढ़ाया, यह एक्सेस स्पेसियर और ओवरराइड व्यवहार पर अधिक अंतर्दृष्टि देगा।

            package overridefunction;
            public class SuperClass 
                {
                public void method1()
                {
                    System.out.println("superclass method1");
                    this.method2();
                    this.method3();
                    this.method4();
                    this.method5();
                }
                public void method2()
                {
                    System.out.println("superclass method2");
                }
                private void method3()
                {
                    System.out.println("superclass method3");
                }
                protected void method4()
                {
                    System.out.println("superclass method4");
                }
                void method5()
                {
                    System.out.println("superclass method5");
                }
            }

            package overridefunction;
            public class SubClass extends SuperClass
            {
                @Override
                public void method1()
                {
                    System.out.println("subclass method1");
                    super.method1();
                }
                @Override
                public void method2()
                {
                    System.out.println("subclass method2");
                }
                // @Override
                private void method3()
                {
                    System.out.println("subclass method3");
                }
                @Override
                protected void method4()
                {
                    System.out.println("subclass method4");
                }
                @Override
                void method5()
                {
                    System.out.println("subclass method5");
                }
            }

            package overridefunction;
            public class Demo 
            {
                public static void main(String[] args) 
                {
                    SubClass mSubClass = new SubClass();
                    mSubClass.method1();
                }
            }

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