By jsonfry


2011-01-04 15:47:56 8 Comments

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

my expected output:

subclass method1
superclass method1
superclass method2

actual output:

subclass method1
superclass method1
subclass method2

I know technically I have overriden a public method, but I figured that because I was calling the super, any calls within the super would stay in the super, this isn't happening. Any ideas as to how I can make it happen?

12 comments

@Beat Siegrist 2017-10-06 10:12:33

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.

@M. le Rutte 2017-10-06 10:21:43

This code is dangerous and risky and expensive. Creating exceptions require the VM to construct a full stacktrace, comparing on only the name and not the full signature is error prone. Also, it reeks of a huge design flaw.

@Beat Siegrist 2017-10-06 12:24:31

From the performance point of view, my code does not seem to produce more impact than 'new HashMap().size()'. However, I may have overlooked the concerns you have been thinking about and I am by fare not a VM expert. I see your doubt by comparing the class names, but it includes the package what makes me pretty sure, it is my parent class. Anyway, I like the Idea of comparing the signature instead, how would you do that? In general, if you have a smoother way to determine whether the caller is the superclass or anyone else I would appreciate to here about.

@M. le Rutte 2017-10-06 12:31:08

If you need to determine whether the caller is a super class I would seriously think longer if a redesign is in place. This is an anti-pattern.

@Beat Siegrist 2017-10-06 13:05:24

I see the point but the general request of the thread is reasonable. In some situation, it can make sense a superclass method call stays in the superclass context with any nested method call. However, there seems to be no way to direct the method call accordingly in the Superclass.

@Mangu Singh Rajpurohit 2016-09-27 05:08:28

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.

@Unai Vivi 2016-08-12 04:12:17

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

@Johnny Baloney 2016-06-25 13:30:15

this always refers to currently executing object.

To further illustrate the point here is a simple sketch:

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

If you have an instance of the outer box, a Subclass object, wherever you happen to venture inside the box, even into the Superclass 'area', it is still the instance of the outer box.

What's more, in this program there is only one object that gets created out of the three classes, so this can only ever refer to one thing and it is:

enter image description here

as shown in the Netbeans 'Heap Walker'.

@Aaron Digulla 2011-01-04 16:11:57

The keyword super doesn't "stick". Every method call is handled individually, so even if you got to SuperClass.method1() by calling super, that doesn't influence any other method call that you might make in the future.

That means there is no direct way to call SuperClass.method2() from SuperClass.method1() without going though SubClass.method2() unless you're working with an actual instance of SuperClass.

You can't even achieve the desired effect using Reflection (see the documentation of java.lang.reflect.Method.invoke(Object, Object...)).

[EDIT] There still seems to be some confusion. Let me try a different explanation.

When you invoke foo(), you actually invoke this.foo(). Java simply lets you omit the this. In the example in the question, the type of this is SubClass.

So when Java executes the code in SuperClass.method1(), it eventually arrives at this.method2();

Using super doesn't change the instance pointed to by this. So the call goes to SubClass.method2() since this is of type SubClass.

Maybe it's easier to understand when you imagine that Java passes this as a hidden first parameter:

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

If you follow the call stack, you can see that this never changes, it's always the instance created in main().

@laycat 2014-04-16 13:39:42

could someone please upload a diagram of this(pun intended) going through the stack? thanks in advance!

@Aaron Digulla 2014-04-16 15:39:02

@laycat: There is no need for a diagram. Just remember that Java has no "memory" for super. Every time it calls a method, it will look at the instance type, and start searching for the method with this type, no matter how often you called super. So when you call method2 on an instance of SubClass, it will always see the one from SubClass first.

@MengT 2014-10-02 10:09:30

@AaronDigulla, Can you explain more about the "Java has no memory for super"?

@Aaron Digulla 2014-10-02 11:36:21

@Truman'sworld: as I said in my answer: using super doesn't change the instance. It doesn't set some hidden field "from now on, all method calls should start using SuperClass". Or to put it another way: The value of this doesn't change.

@MengT 2014-10-02 14:51:41

@AaronDigulla, so does that mean the super keyword are actually invoke the inherited methods in the subclass instead of go to the super class?

@Aaron Digulla 2014-10-03 07:43:11

@Truman'sworld: No. super just affects the immediate method call. It doesn't "stick" or apply to any subsequent method calls which are based off this.

@Vijay 2014-09-17 06:42:32

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



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

OutPut:

subclass method1
superclass method1
superclass method2

@carlos_lm 2014-09-14 19:18:33

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

@Ozil 2013-06-20 17:21:57

"this" keyword refers to current class reference. That means, when it is used inside the method, the 'current' class is still SubClass and so, the answer is explained.

@Joeri Hendrickx 2011-01-05 08:21:38

If you don't want superClass.method1 to call subClass.method2, make method2 private so it cannot be overridden.

Here's a suggestion:

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

If it didn't work this way, polymorphism would be impossible (or at least not even half as useful).

@Sean Patrick Floyd 2011-01-04 15:54:09

You can only access overridden methods in the overriding methods (or in other methods of the overriding class).

So: either don't override method2() or call super.method2() inside the overridden version.

@David Gelhar 2011-01-04 16:01:54

I don't believe you can do it directly. One workaround would be to have a private internal implementation of method2 in the superclass, and call that. For example:

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

}

@Jose Diaz 2011-01-04 15:55:45

You're using the this keyword which actually refers to the "currently running instance of the object you're using", that is, you're invoking this.method2(); on your superclass, that is, it will call the method2() on the object you're using, which is the SubClass.

@Sean Patrick Floyd 2011-01-04 15:59:05

true, and not using this won't help either. An unqualified invocation implicitly uses this

@Shervin Asgari 2011-01-04 16:01:03

Why is this getting upvoted? This is not the answer to this question. When you write method2() the compiler will see this.method2(). So even if you remove the this it still will not work. What @Sean Patrick Floyd is saying is correct

@Sean Patrick Floyd 2011-01-04 16:04:35

@Shervin he's not saying anything wrong, he's just not making clear what happens if you leave out this

@leonbloy 2011-01-04 16:16:17

The answer is right in pointing out that this refers to the "concrete running instance class" (known in runtime) and not (as the poster seems to believe) to the "current compilation-unit class" (where the keyword is used, known in compile time). But it can also be misleading (as Shervin points) : this is also referenced implicitly with the plain method call; method2(); is the same as this.method2();

Related Questions

Sponsored Content

85 Answered Questions

[SOLVED] Is Java "pass-by-reference" or "pass-by-value"?

43 Answered Questions

[SOLVED] How do I convert a String to an int in Java?

32 Answered Questions

[SOLVED] When to use LinkedList over ArrayList in Java?

65 Answered Questions

[SOLVED] How do I generate random integers within a specific range in Java?

  • 2008-12-12 18:20:57
  • user42155
  • 3899399 View
  • 3359 Score
  • 65 Answer
  • Tags:   java random integer

55 Answered Questions

[SOLVED] Creating a memory leak with Java

57 Answered Questions

[SOLVED] How do I read / convert an InputStream into a String in Java?

7 Answered Questions

[SOLVED] Understanding Python super() with __init__() methods

21 Answered Questions

[SOLVED] How do I call one constructor from another in Java?

  • 2008-11-12 20:10:19
  • ashokgelal
  • 805041 View
  • 2130 Score
  • 21 Answer
  • Tags:   java constructor

12 Answered Questions

[SOLVED] Why is it important to override GetHashCode when Equals method is overridden?

  • 2008-12-16 13:41:18
  • David Basarab
  • 351015 View
  • 1364 Score
  • 12 Answer
  • Tags:   c# overriding hashcode

24 Answered Questions

[SOLVED] Why can't I define a static method in a Java interface?

Sponsored Content