Java: Calling a super method which calls an overridden method

前端 未结 13 2260
有刺的猬
有刺的猬 2020-11-27 10:29
public class SuperClass
{
    public void method1()
    {
        System.out.println(\"superclass method1\");
        this.method2();
    }

    public void method2(         


        
相关标签:
13条回答
  • 2020-11-27 11:10

    Since the only way to avoid a method to get overriden is to use the keyword super, I've thought to move up the method2() from SuperClass to another new Base class and then call it from SuperClass:

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

    Output:

    subclass method1
    superclass method1
    superclass method2
    
    0 讨论(0)
  • 2020-11-27 11:11

    Further more extended the output of the raised question, this will give more insight on the access specifier and override behavior.

                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
    
    0 讨论(0)
  • 2020-11-27 11:12
    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");
        }
    }
    

    calling

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

    outputs

    subclass method1
    superclass method1
    superclass method2

    0 讨论(0)
  • 2020-11-27 11:14

    During my research for a similar case, I have been ending up by checking the stack trace in the subclass method to find out from where the call is coming from. There are probably smarter ways to do so, but it works out for me and it's a dynamic approach.

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

    I think the question to have a solution for the case is reasonable. There are of course ways to solve the issue with different method names or even different parameter types, like already mentioned in the thread, but in my case I dindn't like to confuse by different method names.

    0 讨论(0)
  • 2020-11-27 11:15

    I think of it this way

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

    Let me move that subclass a little to the left to reveal what's beneath... (Man, I do love ASCII graphics)

    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).
    

    In other words, quoting from the Java Language Specification:

    The form super.Identifier refers to the field named Identifier of the current object, but with the current object viewed as an instance of the superclass of the current class.

    The form T.super.Identifier refers to the field named Identifier of the lexically enclosing instance corresponding to T, but with that instance viewed as an instance of the superclass of T.

    In layman's terms, this is basically an object (*the** object; the very same object you can move around in variables), the instance of the instantiated class, a plain variable in the data domain; super is like a pointer to a borrowed block of code that you want to be executed, more like a mere function call, and it's relative to the class where it is called.

    Therefore if you use super from the superclass you get code from the superduper class [the grandparent] executed), while if you use this (or if it's used implicitly) from a superclass it keeps pointing to the subclass (because nobody has changed it - and nobody could).

    0 讨论(0)
  • 2020-11-27 11:15

    To summarize, this points to current object and the method invocation in java is polymorphic by nature. So, method selection for execution, totally depends upon object pointed by this. Therefore, invoking method method2() from parent class invokes method2() of child class, as the this points to object of child class. The definition of this doesn't changes, irrespective of whichever class it's used.

    PS. unlike methods, member variables of class are not polymorphic.

    0 讨论(0)
提交回复
热议问题