জাভা: একটি সুপার পদ্ধতি কল করা যা একটি ওভাররাইড পদ্ধতিতে কল করে


98
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();
    }
}

আমার প্রত্যাশিত আউটপুট:

সাবক্লাস মেথড 1
সুপারক্লাস মেথড 1
সুপারক্লাস মেথড 2

আসল আউটপুট:

সাবক্লাস মেথড 1
সুপারক্লাস মেথড 1
সাবক্লাস মেথড 2

আমি টেকনিক্যালি জানি যে আমি একটি পাবলিক পদ্ধতি ওভাররাইড করেছি, তবে আমি বুঝতে পেরেছিলাম যে আমি সুপারকে কল করছিলাম, সুপারের মধ্যে যে কোনও কলই সুপারের মধ্যে থাকবে, এটি ঘটছে না। আমি কীভাবে এটি ঘটতে পারি তা সম্পর্কে কোনও ধারণা?


4
আমার সন্দেহ হয় আপনি হয়ত "উত্তরাধিকারের চেয়ে বেশি রচনা পছন্দ করতে" চান।
টম হাটিন -

উত্তর:


82

শব্দ super"স্টিক" নেই। প্রতিটি পদ্ধতি কল স্বতন্ত্রভাবে পরিচালিত হয়, তাই এমনকি যদি আপনি পেয়েছিলাম SuperClass.method1()কল করে super, যে অন্য কোন পদ্ধতি কল যে আপনি ভবিষ্যতে করা হতে পারে প্রভাবিত করে না।

অর্থাৎ ডাকতে কোন সরাসরি উপায় SuperClass.method2()থেকে SuperClass.method1()যদিও যাচ্ছে ছাড়া SubClass.method2(), যদি না আপনি একজন প্রকৃত নিদর্শনের সঙ্গে কাজ করছি SuperClass

আপনি প্রতিচ্ছবি ব্যবহার করে পছন্দসই প্রভাবও অর্জন করতে পারবেন না ( এর ডকুমেন্টেশনjava.lang.reflect.Method.invoke(Object, Object...) দেখুন )।

[সম্পাদনা] এখনও কিছু বিভ্রান্তি মনে হচ্ছে। আমাকে অন্য একটি ব্যাখ্যা চেষ্টা করুন।

আপনি যখন প্রার্থনা করেন foo(), আপনি আসলে প্রার্থনা করেনthis.foo() । জাভা কেবল আপনাকে বাদ দিতে দেয় this। প্রশ্নে উদাহরণে, ধরণ thisহয় SubClass

সুতরাং যখন জাভা কোডটি কার্যকর করে 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()


কেউ দয়া করে স্ট্যাকের মধ্য দিয়ে যেতে পারে (পাং উদ্দেশ্যে) একটি চিত্রটি আপলোড করতে পারেন? আগাম ধন্যবাদ!
লেটকাট

4
@ লাইক্যাট: ডায়াগ্রামের দরকার নেই। কেবল মনে রাখবেন যে জাভাটির কোনও "মেমরি" নেই super। যতবারই এটি কোনও পদ্ধতিতে কল করে, এটি উদাহরণের ধরণের দিকে নজর দেবে এবং আপনি যতবার ডেকেছিলেন তা বিবেচনা না করেই এই ধরণের মাধ্যমে পদ্ধতিটি অনুসন্ধান করা শুরু করবে super। সুতরাং আপনি যখন method2কোনও উদাহরণে কল করেন SubClass, এটি সর্বদা SubClassপ্রথমটি দেখায়।
অ্যারন দিগুল্লা

অ্যারোনডিগুল্লা, "জাভা সুপারের জন্য কোনও স্মৃতি নেই" সম্পর্কে আপনি আরও ব্যাখ্যা করতে পারেন?
MengT

@ ট্রুমানস ওয়ার্ল্ড: যেমনটি আমি আমার উত্তরে বলেছি: ব্যবহারের superফলে দৃষ্টান্ত পরিবর্তন হয় না। এটি "এখন থেকে কোনও লুকানো ক্ষেত্র সেট করে না, সমস্ত পদ্ধতি কলগুলি ব্যবহার শুরু করা উচিত SuperClass"। বা এটি অন্য কোনও উপায়ে দিতে: এর মান thisপরিবর্তন হয় না।
অ্যারন দিগুল্লা 2'14

@ অ্যারোনডিগুল্লা, তার মানে কি সুপার কীওয়ার্ডটি আসলে সুপার ক্লাসে না গিয়ে সাবক্লাসে উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি চাওয়া হয়?
মেংটি

15

আপনি কেবল ওভাররাইড পদ্ধতিতে (বা ওভাররাইডিং ক্লাসের অন্যান্য পদ্ধতিতে) ওভাররাইড পদ্ধতিতে অ্যাক্সেস করতে পারেন।

সুতরাং: হয় ওভাররাইড method2()বা super.method2()ওভাররাইড সংস্করণে কল না ।


8

আপনি এমন thisকীওয়ার্ডটি ব্যবহার করছেন যা প্রকৃতপক্ষে "আপনি যে অবজেক্টটি ব্যবহার করছেন তার বর্তমানে চলমান দৃষ্টান্ত" বোঝায়, এটি হ'ল আপনি this.method2();আপনার সুপারক্লাসে প্রার্থনা করছেন, অর্থাত্ এটি আপনাকে বস্তুটিতে মেথড 2 () কল করবে ' ব্যবহার করছেন, যা সাবক্লাস।


9
সত্য, এবং ব্যবহার না করেও thisকোনও কাজে আসবে না। একটি অযোগ্য প্রার্থনা স্পষ্টভাবে ব্যবহার করেthis
সান প্যাট্রিক ফ্লয়েড

4
কেন এই upvated হচ্ছে? এটি এই প্রশ্নের উত্তর নয়। method2()সংকলক লেখার সময় দেখতে পাবেন this.method2()। সুতরাং আপনি সরিয়ে ফেললেও thisএটি এখনও কাজ করবে না। @ সিয়ান প্যাট্রিক ফ্লয়েড যা বলছেন তা সঠিক
শেরভিন আসগরী

4
@ শেরভিন তিনি কোনও ভুল বলছেন না, আপনি বাইরে চলে গেলে কী হয় সে কেবল তা পরিষ্কার করে বলছে নাthis
সান প্যাট্রিক ফ্লয়েড

4
উত্তরটি সঠিকভাবে thisনির্দেশ করতে পারে যা "কংক্রিটের চলমান দৃষ্টান্ত শ্রেণি" (রানটাইম হিসাবে পরিচিত) এবং "পোস্টারটি বিশ্বাস করে বলে মনে হয় না" হিসাবে "বর্তমান সংকলন-ইউনিট শ্রেণি" (যেখানে মূলশব্দটি ব্যবহৃত হয়, যা পরিচিত সংকলন সময়)। তবে এটি বিভ্রান্তিমূলকও হতে পারে (শেরভিন পয়েন্ট হিসাবে): thisসরল পদ্ধতি কলের সাথেও স্পষ্টভাবে উল্লেখ করা হয়; method2();this.method2();
লেওনব্লয়

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ক্ষেত্রটির উল্লেখ করে তবে এর সাথে সুপারক্লাসের উদাহরণ হিসাবে দেখা যায় ।IdentifierTT

সাধারণ ব্যক্তির ভাষায়, thisমূলত একটি অবজেক্ট (* ** অবজেক্ট; আপনি একই ধরণের অবজেক্টে ভেরিয়েবলে ঘুরতে পারেন), ইনস্ট্যান্টিয়েটেড ক্লাসের উদাহরণ, ডেটা ডোমেনে একটি স্পষ্ট পরিবর্তনশীল; superকোডটি ধার করা ব্লকের পয়েন্টারের মতো যা আপনি কার্যকর করতে চান, আরও নিছক ফাংশন কলের মতো এবং এটি শ্রেণীর যেখানে এটি বলা হয় তার সাথে সম্পর্কিত।

অতএব আপনি যদি superসুপারক্লাস থেকে ব্যবহার করেন তবে সুপারডুপার শ্রেণি [পিতামহ] মৃত্যুদন্ড কার্যকর করা হয়েছে) থেকে কোড পান, যদি আপনি thisএকটি সুপারক্লাস থেকে ব্যবহার করেন (বা যদি এটি স্পষ্টভাবে ব্যবহার করা হয়) তবে এটি সাবক্লাসের দিকে ইশারা করে রাখে (কারণ কেউই এটি পরিবর্তন করেনি - এবং কেউই) পারে)।


3
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();

ফলাফল

সাবক্লাস মেথড 1
সুপারক্লাস মেথড 1
সুপারক্লাস মেথড 2


2

আপনি যদি সুপারক্লাস.মোথডা 1 টি সাবক্লাস.মোথডো 2 কল করতে না চান তবে মেথড 2টিকে ব্যক্তিগত করুন যাতে এটি ওভাররাইড করা যায় না।

এখানে একটি পরামর্শ:

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

যেহেতু একমাত্র উপায় ওভাররাইড পেতে একটি পদ্ধতি এড়াতে শব্দ ব্যবহার করা সুপার , আমি থেকে method2 () উপরে উঠানো বলে মনে করে থাকেন সুপারক্লাস অন্য নতুন বেজ ক্লাসের তখন তোমরা তা থেকে কল সুপারক্লাস :

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বস্তু, যেখানেই আপনি বাক্সের ভিতরে ventureSuperclass 'অঞ্চলে' , এটি এখনও বাইরের বাক্সের উদাহরণ।

আরও কী, এই প্রোগ্রামে তিনটি শ্রেণীর মধ্যে একটি মাত্র অবজেক্ট তৈরি হয়ে যায়, তাই thisকেবল কখনও একটি জিনিস উল্লেখ করতে পারে এবং তা হ'ল:

এখানে চিত্র বর্ণনা লিখুন

যেমন নেটবীনের 'হিপ ওয়াকার' তে দেখানো হয়েছে ।


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
        }
}

আমি মনে করি মামলার সমাধান করার জন্য প্রশ্নটি যুক্তিসঙ্গত। ইস্যুটি বিভিন্ন পদ্ধতির নাম বা এমনকি বিভিন্ন প্যারামিটার ধরণের সাথে সমাধান করার উপায় অবশ্যই রয়েছে, যেমন থ্রেডে ইতিমধ্যে উল্লিখিত রয়েছে, তবে আমার ক্ষেত্রে আমি বিভিন্ন পদ্ধতির নাম দ্বারা বিভ্রান্ত করতে পছন্দ করি না।


এই কোডটি বিপজ্জনক এবং ঝুঁকিপূর্ণ এবং ব্যয়বহুল। ব্যতিক্রমগুলি তৈরি করতে ভিএমকে একটি সম্পূর্ণ স্ট্যাকট্র্যাস তৈরি করতে হবে, কেবলমাত্র নামের সাথে তুলনা করে সম্পূর্ণ স্বাক্ষরটি নয় ত্রুটি প্রবণ। এছাড়াও, এটি একটি বিশাল ডিজাইনের ত্রুটি দেখায়।
এম লে রুট্ট

পারফরম্যান্সের দৃষ্টিকোণ থেকে, আমার কোডটি 'নতুন হ্যাশম্যাপ ()। আকার ()' এর চেয়ে বেশি প্রভাব ফেলবে বলে মনে হচ্ছে না। তবে, আপনি যে উদ্বেগগুলি নিয়ে ভাবছেন তা আমি উপেক্ষা করেছি এবং আমি কোনও ভিএম বিশেষজ্ঞের হাত থেকে রেহাই পাচ্ছি না। ক্লাসের নামগুলির তুলনা করে আমি আপনার সন্দেহ দেখতে পাচ্ছি, তবে এতে প্যাকেজ অন্তর্ভুক্ত রয়েছে যা আমাকে বেশ নিশ্চিত করে তোলে, এটি আমার পিতামাতার ক্লাস। যাইহোক, আমি পরিবর্তে স্বাক্ষরের তুলনা করার আইডিয়া পছন্দ করি, আপনি এটি কীভাবে করবেন? সাধারণভাবে, যদি আপনার কাছে নির্ধারিত কোনও মসৃণ উপায় থাকে যে কলারটি সুপারক্লাস কিনা বা অন্য কারও বিষয়ে আমি এখানে প্রশংসা করব।
সিজিরিস্টকে

কলারটি একটি সুপার ক্লাস কিনা তা নির্ধারণ করার দরকার হলে পুনরায় নকশার জায়গায় উপস্থিত থাকলে আমি গুরুত্ব সহকারে আরও দীর্ঘক্ষণ চিন্তা করব। এটি একটি অ্যান্টি-প্যাটার্ন।
এম লে রুট্ট

আমি বিষয়টি দেখতে পাচ্ছি তবে থ্রেডের সাধারণ অনুরোধটি যুক্তিসঙ্গত। কিছু পরিস্থিতিতে, এটি একটি সুপারক্লাস পদ্ধতির কলটি কোনও নেস্টেড পদ্ধতি কল সহ সুপারক্লাসের প্রসঙ্গে থাকতে পারে sense তবে, সুপারক্লাসে সেই অনুসারে পদ্ধতি কলটি নির্দেশ করার কোনও উপায় নেই বলে মনে হয়।
সিজিরিস্টকে

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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.