I'm dealing with a class which extends JFrame.
It's not my code and it makes a call to super before it begins constructing the GUI. I'm wondering why this is done since I've always just accessed the methods of the superclass without having to call super();
There is an implicit call to super() with no arguments for all classes that have a parent - which is every user defined class in Java - so calling it explicitly is usually not required. However, you may use the call to super() with arguments if the parent's constructor takes parameters, and you wish to specify them. Moreover, if the parent's constructor takes parameters, and it has no default parameter-less constructor, you will need to call super() with argument(s).
An example, where the explicit call to super() gives you some extra control over the title of the frame:
class MyFrame extends JFrame
{
public MyFrame() {
super("My Window Title");
...
}
}
A call to your parent class's empty constructor super() is done automatically when you don't do it yourself. That's the reason you've never had to do it in your code. It was done for you.
When your superclass doesn't have a no-arg constructor, the compiler will require you to call super with the appropriate arguments. The compiler will make sure that you instantiate the class correctly. So this is not something you have to worry about too much.
Whether you call super() in your constructor or not, it doesn't affect your ability to call the methods of your parent class.
As a side note, some say that it's generally best to make that call manually for reasons of clarity.
None of the above answers answer the 'why'.
Found a good explanation here:
A subclass can have its own private data members, so a subclass can
also have its own constructors.
The constructors of the subclass can initialize only the instance
variables of the subclass. Thus, when a subclass object is
instantiated the subclass object must also automatically execute one
of the constructors of the superclass.
You might also want to read everything about the super keyword here or watch everything about the super keyword here.
We can access super class elements by using super keyword
Consider we have two classes, Parent class and Child class, with different implementations of method foo. Now in child class if we want to call the method foo of parent class, we can do so by super.foo(); we can also access parent elements by super keyword.
class parent {
String str="I am parent";
//method of parent Class
public void foo() {
System.out.println("Hello World " + str);
}
}
class child extends parent {
String str="I am child";
// different foo implementation in child Class
public void foo() {
System.out.println("Hello World "+str);
}
// calling the foo method of parent class
public void parentClassFoo(){
super.foo();
}
// changing the value of str in parent class and calling the foo method of parent class
public void parentClassFooStr(){
super.str="parent string changed";
super.foo();
}
}
public class Main{
public static void main(String args[]) {
child obj = new child();
obj.foo();
obj.parentClassFoo();
obj.parentClassFooStr();
}
}
It simply calls the default constructor of the superclass.
We use super keyword to call the members of the Superclass.
As a subclass inherits all the members (fields, methods, nested classes) from its parent and since Constructors are NOT members (They don't belong to objects. They are responsible for creating objects), they are NOT inherited by subclasses.
So we have to explicitly give the call for parent constructor so that the chain of constructor remains connected if we need to create an object for the superclass. At the time of object creation, only one constructor can be called. Through super, we can call the other constructor from within the current constructor when needed.
If you are thinking why it's there for a class that is not extending any other class, then just remember every class follows object class by default. So it's a good practice to keep super in your constructor.
Note: Even if you don't have super() in your first statement, the compiler will add it for you!
We can Access SuperClass members using super keyword
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super. You can also use super to refer to a hidden field (although hiding fields is discouraged). Consider this class, Superclass:
public class Superclass {
public void printMethod() {
System.out.println("Printed in Superclass.");
}
}
// Here is a subclass, called Subclass, that overrides printMethod():
public class Subclass extends Superclass {
// overrides printMethod in Superclass
public void printMethod() {
super.printMethod();
System.out.println("Printed in Subclass");
}
public static void main(String[] args) {
Subclass s = new Subclass();
s.printMethod();
}
}
Within Subclass, the simple name printMethod() refers to the one declared in Subclass, which overrides the one in Superclass. So, to refer to printMethod() inherited from Superclass, Subclass must use a qualified name, using super as shown. Compiling and executing Subclass prints the following:
Printed in Superclass.
Printed in Subclass
as constructor is not a part of class,
so while calling it cannot be implemented,
by using SUPER() we can call the members and memberfunctions in constructor.
Related
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.
The constructor of a subclass.
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 (i.e. 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.
Assume for some reason that I don't want to implicitly call super() which is done by default.
class Animal {
public Animal() {
System.out.println("Constructing an animal.");
}
}
class Dog extends Animal {
public Dog() {
System.out.println("Constructing a dog.");
}
public static void main(String[] a) {
new Dog();
}
}
Is there any way to "disable" the default behavior that super() is invoked when making a new Dog? Or would that be principally and conceptually wrong?
I mean there could be cases where you would want only the constructor of the subclass and not invoke the construction of the baseclass, and still inherit the baseclass.
If I understand you correctly you want to override the behavior of the Animal constructor or just not call it. If so you're conceptually wrong: you always need to call a super constructor, the only thing you could to with the calls is provide a non-default constructor, i.e. one with arguments and provide appropriate arguments to influence the behavior of that constructor (e.g. by either selecting a different constructor, passing some sort of strategy/function object etc.)
Another way might be to provide some init() method that the default constructor is calling and which you can override but there are a few problems with it, e.g.:
If the overridden method tries to access anything only visible to the subclass (e.g. additional fields) you could run into problems because those haven't been initialized yet.
That method can't initialize any final field.
s there any way to "disable" the default behavior that super() is
invoked when making a new Dog? Or would that be principally and
conceptually wrong?
It is conceptually wrong since any class which invokes its constructor has to invoke the constructor of its parent : super() or super() with any arguments if the super constructor has not it.
If the constructor of the super class does some specific processing and that is not desirable for all concrete classes, you should change rather the implementation of the super constructor and move the specific behavior in a method of the super class or in a method of concrete classes.
You can't bypass the construction of a parent class, and perhaps you shouldn't attempt to circumvent this rule.
But, if you must do this then you could build a no-op constructor in Animal (that you mark as protected so only derived classes can see it):
protected Animal(Noop foo)
{
/*do nothing explicit here*/
}
And call that one explicitly from your derived class using
super(new Noop())
Here I've invented a new class Noop (meaning "no operation") to enable the compiler to distinguish the constructor parameters.
Agreeing with all the answers here on invoking the constructor which cannot be avoided, providing one more workaround which ensures a block of code in constructor that gets executed only when it is directly invoked and not when any sub class constructors are invoked.
public class Animal{
public Animal() {
if(this.getClass() == Animal.class){
System.out.println("Animal");
}
}
}
public class Dog extends Animal{
public Dog() {
System.out.println("Dog");
}
}
That's one of the reasons inheritance is a pain and usually misused:
public interface Animal {
// define behaviour
}
public class Dog implements Animal {
// implement behaviour
}
Use interfaces and aggregation / decoration so you can avoid the struggle of bad design decisions in inheritance chains.
I've put this code in the compiler
package com.employer.constractor;
public class ConstractorDemo extends A{
public ConstractorDemo(){
System.out.print("Demo");
}
public static void main(String[] args){
new ConstractorDemo();
}
}
class A {
A(){
System.out.print("A");
}
}
And it gave "ADemo"
why?
I'll appreciate any detailed answer for this case
and mention how compiler will deal exactly with that
The constructor of a base class (class A in your case) is always executed before the constructor of the class you are instantiating (class ConstractorDemo in your case). That's why A is printed before Demo.
This constructor :
public ConstractorDemo(){
System.out.print("Demo");
}
is equivalent to :
public ConstractorDemo(){
super (); // prints A
System.out.print("Demo"); // prints Demo
}
The child constructor is invoked first. The first line in the child constructor will be a call to super. WHich gives you the illusion that the parent will be invoked first. But in reality the child class's constructor calls the parent class's constructor
When you invoke a child constructor, it automatically chain the calls to it's all super classes until the chain reaches to Object class.
Though you are not invoking Invoking a super class constructor doesn't mean that you are executing only Child class constructor alone. There is a interesting fact that your super class constructors(till n'th super class, which is Object class constructor) also calls in that process(shown in your code). you can observe when you invoke any Child constructor. There is a chain call to the immediate parent class constructor from the current class. And the call continues until the Object class constructor invokes since that the possible most Parent classes super class is.
Thumb rules
If you call any specific super constructor (super or super(args)),
then that specific super constructor invokes.
If you are not calling any specific constructor, then default super
constructor(super()) invokes.
base class constructor is always executed before the class Level Constructor . it automatic call super class . So First Awill print then after that Demo as per Your example. Thanks
Whenever a subclass's constructor is called , the first default statement in it is super(); which is automatically added by the compiler,
The super(); will invoke the constructor of superclass and so, first it will execute A() and then ConstractorDemo()
Refer to this : https://www.javatpoint.com/super-keyword
Even if you want to specify super(); it needs to be the first statement of your constructor else it will give you compile time error!
Your Constructor is like this :
public ConstractorDemo()
{
super(); // u didn't specified this but compiler will automatically add it
System.out.print("Demo");
}
Hey i'm trying to call child class method(ChildClass extends SuperClass())
SuperClass s=new ChildClass();
s.childClassMethod();
It doesn't see the ChildClass method the only methods i can call are from SuperClass()
i know it's propably a stupid question but anyway cheers
That's right, you can't see it because s is type SuperClass which doesn't have this method - this would obviously break Polymorphism principle.
So you either have to change the code like ((ChildClass) s).childClassMethod(); or make s as ChildClass type.
Compiler doesn't know what instance this reference would be pointing to at runtime so it will only allow you to access super class's accessible methods at compile time
See
polymorphism
The parent does not know anything about any new methods the child possesses.
public class SuperClass {
// I have no method named "childClassMethod"...
}
public class ChildClass {
public void childClassMethod() {
// Do something.
}
}
SuperClass does not know about childClassMethod(). You would have to provide both classes with an interface or add that method to the parent and override it in the child.
Or, you could simply cast the object to the child class as others have suggested, but this can be unsafe.
((ChildClass) s).childClassMethod()
That is because the super class does not have that method.
If you want the super class to be able to call the method, you need to make it abstract and give it that method.
The subclass is a form of the super class, the super class is not a form of the sub class.
What happens (if anything) when a constructor calls 'super()' without having any superclass besides Object? Like so:
public class foo implements Serializable, Comparable {
int[] startPoint;
public foo() {
super();
startPoint = {5,9};
}
}
Edit: So if this does nothing, why would anyone explicitly write that in code? Would it make any difference if I just delete that line?
It is always OK to delete the line super(); from any constructor, and there is nothing particular about the constructors of classes that extend Object. The call of the nullary superclass constructor is always implied, so whether you write it down or not, you always get the exact same semantics.
Note that this means that if you omit a call to the superclass constructor that does something big, like start database connections or the whole GUI, all this will happen whether or not you actually write super();.
super() is the first call in constructor either it is done explicitly or implicitly.
(But of course you might need to change parameters to match parent's constructor.)
Your code:
public foo()
{
startPoint = {5,9};
}
What compiler sees from the code above:
public foo()
{
super();
startPoint = {5,9};
}
So super() is invoked whether you put it explicitly in your code or not.
Since all classes derive from Object class, you are calling constructor of Object with your super() call because your class doesn't have any intermediate parents.
There is always a super class called Object, so it will invoke constructor of Object
That just calls the Object() constructor, just as if you had any other superclass with a constructor that has no parameters.
As you stated, there is a super class (Object).
The default object constructor will be called.
It calls Object's constructor, which is empty (does nothing).
super() always call to the constructor to Object class if the class doesn't extends from one class.
Class Object is the root of the class hierarchy. Every class has Object as a super class. All objects, including arrays, implement the methods of this class.
Check this link