简体   繁体   中英

Implicit conversion of super keyword in toString() method to super.toString() not happening

I have the following two classes as shown below. For the sake of simplicity, only toString overridden method is shown .

        public class Circle {
        @Override
            public String toString() {
                return "Circle";
            }
        }
        public class Cylinder extends Circle {
            @Override
            public String toString() {
     //     return "Cylinder"+this;  // runs without explicitly calling toString() on this keyword
     //     return "Cylinder"+super;  // throws error, asks to delete super token
            return "Cylinder["+super.toString(); // runs without error after adding .toString() with super keyword
            }

}

The issue i am having is in my understanding of super keyword . The toString() of super keyword should be invoked implicitly as is in the case of this keyword .In fact most of the tutorials and books refer to super keyword as a kind of an object reference to a super class and so it must behave same as this keyword when used with "+" concatenation operator inside toString(). Please help me in understanding this.

The super keyword in Java is not an object reference, unlike this .

this is used as a reference to the calling object.

But, There's no reference-id which can be stored in super super is a keyword which is used to RESOLVE the parent CLASS, its methods and data members.

So, you can't print the value of super keyword. You can only access methods and members of parent class using super keyword.

this

super

Expressions

In Java, super keyword is used in two places.

  1. The constructor of a subclass.
  2. In a overridden method of a subclass.

When used in the constructor, super() must be called on the first line. If you are calling another constructor overload, you must call this() on the first line of that constructor as well.

A constructor without parameter (ie default constructor) does not need to call super() if the parent also has a default constructor. This is because the compiler actually does it for you, so it's still there.

When used in an overridden method, you are calling the parent implementation of the method. You cannot call super() because that is for parent constructor; you call via super.foo() . Unlike super() , you must explicitly call this. If you override a method and have empty implementation, then that method does nothing.

Furthermore, super.foo() can be used not only in an overridden method. Also, you need not call the same method as the method you are overriding. For example, this is allowed:

public void foo() {
    System.out.println(super.toString());
}

Although this is allowed, it is more common to call this.toString() in this case. This can be used if your class has overridden toString() and you do want the original implementation.

Lastly, super keyword cannot be used on its own. It is always in a form super() or super.method() .

Example:

public class Base {
    @Override public String toString() {
        return "Base";
    }
}

public class Sub extends Base {
    public void foo() {
        System.out.println(super.toString());
        System.out.println(this.toString());
    }

    @Override public String toString() {
        return "Sub";
    }
}

public class Test {
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.foo();
    }
}

Output:

Base
Sub

As Louis mentioned in the comment super is not a normal object. It is a special case.

According to java spec

The forms using the keyword super are valid only in an instance method, instance initializer, or constructor, or in the initializer of an instance variable of a class. If they appear anywhere else, a compile-time error occurs.

According to the Java Language Specification §15.11.2 and §15.12.1,

Accessing Superclass Members using super

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 .

...

Compile-Time Step 1: Determine Class or Interface to Search (in a method invocation expression)

If the form is super.[TypeArguments]Identifier , then the class to search is the superclass of the class whose declaration contains the method invocation.

It only mentions two forms of the super expression - either super.Identifier or T.super.Identifier . You are using neither of these forms. You are using super as if it were this , as if it were some kind of variable that you can use on its own. This is not true, super behaves very differently from this .

If you compare how the spec describes this :

§15.8.3 this

The keyword this may be used only in the following contexts:

  • in the body of an instance method or default method (§8.4.7, §9.4.3)
  • in the body of a constructor of a class (§8.8.7)
  • in an instance initializer of a class (§8.6)
  • in the initializer of an instance variable of a class (§8.3.2)
  • to denote a receiver parameter (§8.4.1)

As you can see, this means that this can be used on its own. super cannot.

In addition, an expression like "Cylinder"+super is less readable than "Cylinder"+suer.toString() . Don't you think? And by the way, return "Cylinder"+this; will probably cause infinite recursion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM