USE:- We use super key word to access those features or members which are not inherited by the subclass from the super class. Example of such members are private members overridden methods, constructors.
Use of super key word to access private members or overridden methods.
SYNTAX:- super. member.
Here in the above code super is a key word which is accessing the private or overridden member using the dot(.) operator .Private members could be variables as well as methods.
Example:-The first form of super acts somewhat like this, except that it always refers to
the superclass of the subclass in which it is used. This usage has the following
general form:
super.member
Here, member can be either a method or an instance variable.
class A {
int i;
}
// Create a subclass by extending class A.
class B extends A {
int i; // this i hides the i in A
B(int a, int b) {
super.i = a; // i in A
i = b; // i in B
}
void show() {
System.out.println("i in superclass: " + super.i);
System.out.println("i in subclass: " + i);
}
}
class UseSuper {
public static void main(String args[]) {
B subOb = new B(1, 2);
subOb.show();
}
}
This program displays the following:
i in superclass: 1
i in subclass: 2
Although the instance variable i in B hides the i in A, super allows access to the i
defined in the superclass.
Use of super keyword to call the constructors of the super class.
super();
The above syntax is a second form of super key word which is used to call the constructors based on the parameters, in the above code we have called the default constructor of the super class we can also call another constructor of the super class by passing different parameters to the super()
Constructors are not inherited because they are part of the class and not part of the object.
Example:- super(); //Constructor Call
The super() construct is used in a subclass constructor to invoke a constructor in the immediate superclass. This allows the subclass to
influence the initialization of its inherited state when an object of the subclass is created. A super() call in the constructor of a subclass
will result in the execution of the relevant constructor from the superclass, based on the signature of the call. Since the superclass name
is known in the subclass declaration, the superclass constructor invoked is determined by the signature of the parameter list.
A constructor in a subclass can access the class's inherited members directly (i.e., by their simple name). The keyword super can also
be used in a subclass constructor to access inherited members via its superclass. One might be tempted to use the super keyword in a
constructor to specify initial values of inherited fields. However, the super() construct provides a better solution, using superclass
constructors to initialize the inherited state.
In Example , the non-default constructor at (3) of the class Light has a super() call (with no arguments) at (4). Although the constructor
is not strictly necessary, as the compiler will insert one—as explained below—it is included for expositional purposes. The non-default
constructor at (6) of class TubeLight has a super() call (with three arguments) at (7). This super() call will match the non-default
constructor at (3) of superclass Light. This is evident from the program output.
Example:- super() Constructor Call
class Light {
// Fields
private int noOfWatts;
private boolean indicator;
private String location;
// Constructors
Light() { // (1) Explicit default constructor
System.out.println(
"Returning from default constructor no. 1 in class Light");
}
Light(int watt, boolean ind) { // (2) Non-default
System.out.println( "Returning from non-default constructor no. 2 in class Light");
}
Light(int noOfWatts, boolean indicator, String location) { // (3) Non-default
super(); // (4)
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
System.out.println(
"Returning from non-default constructor no. 3 in class Light");
}
}
class TubeLight extends Light {
// Instance variables
private int tubeLength;
private int colorNo;
TubeLight(int tubeLength, int colorNo) { // (5) Non-default
System.out.println( "Returning from non-default constructor no. 1 in class TubeLight");
}
TubeLight(int tubeLength, int colorNo, int noOfWatts,
boolean indicator, String location) {
// (6)Non-default
super(noOfWatts, indicator, location); // (7)
this.tubeLength = tubeLength;
this.colorNo = colorNo;
System.out.println(
"Returning from non-default constructor no. 2 in class TubeLight");
}
}
public class Chaining {
public static void main(String[] args) {
System.out.println("Creating a TubeLight object.");
TubeLight tubeLightRef = new TubeLight(20, 5); // (8)
}
}
this Keyword
Sometimes a method will need to refer to the object that invoked it. To allow this, Java
defines the this keyword. this can be used inside any method to refer to the current object.
That is, this is always a reference to the object on which the method was invoked. You
can use this anywhere a reference to an object of the current class To better understand what this refers to, consider the following version of Box( ):
// A redundant use of this.
Box(double w, double h, double d) {
this.width = w;
this.height = h;
this.depth = d;
}
This version of Box( ) operates exactly like the earlier version. The use of this is redundant,
but perfectly correct. Inside Box( ), this will always refer to the invoking object. While
it is redundant in this case, this is useful in other context which is described below..
Instance Variable Hiding
As you know, it is illegal in Java to declare two local variables with the same name
inside the same or enclosing scopes. Interestingly, you can have local variables,
including formal parameters to methods, which overlap with the names of the class’
instance variables. However, when a local variable has the same name as an instance
variable, the local variable hides the instance variable. This is why width, height, and
depth were not used as the names of the parameters to the Box( ) constructor inside the
Box class. If they had been, then width would have referred to the formal parameter,
hiding the instance variable width. While it is usually easier to simply use different
names, there is another way around this situation. Because this lets you refer directly
to the object, you can use it to resolve any name space collisions that might occur
between instance variables and local variables. For example, here is another version of
Box( ), which uses width, height, and depth for parameter names and then uses this to
access the instance variables by the same name:-
// Use this to resolve name-space collisions.
Box(double width, double height, double depth) {
this.width = width;
this.height = height;
this.depth = depth;
}
The use of this in such a context can sometimes be confusing,
and some programmers are careful not to use local variables and formal parameter
names that hide instance variables. Of course, other programmers believe the contrary,
that it is a good convention to use the same names for clarity, and use this to overcome
the instance variable hiding. It is a matter of taste which approach you adopt.
Method overriding
Method overriding requires the same method signature(name and parameters).Method overriding is implemented when the subclass defines the same method with the same signature in its body. In this way it provides us a same methos but different implementation type of polymorphism.
Only non final methods in the super class which are directly accessible in the subclass are eligible for overriding .The method defined in the super class is called overriding method and the method defined in the sub class is called method overriding. The sub class does not inherit overriding methods in the super class because the sub class is providing a specialized implementation of the overriding method in the super class. But they are accessible using super key word in the sub class.
Example:-
// Method overriding.
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
// display i and j
void show() {
System.out.println("i and j: " + i + " " + j);
}
}
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
// display k – this overrides show() in A
void show() {
System.out.println("k: " + k);
}
}
class Override {
public static void main(String args[]) {
B subOb = new B(1, 2, 3);
subOb.show(); // this calls show() in B
}
}
The output produced by this program is shown here:-
k: 3
When show( ) is invoked on an object of type B, the version of show( ) defined
within B is used. That is, the version of show( ) inside B overrides the version
declared in A.
If you wish to access the superclass version of an overridden function, you can do
so by using super. For example, in this version of B, the superclass version of show( ) is
invoked within the subclass’ version. This allows all instance variables to be displayed.
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {
super.show(); // this calls A's show()
System.out.println("k: " + k);
}
}
If you substitute this version of A into the previous program, you will see the
following output:
i and j: 1 2
k: 3
Here, super.show( ) calls the superclass version of show( ).
Method overriding occurs only when the names and the type signatures of the two
methods are identical. If they are not, then the two methods are simply overloaded. For
example, consider this modified version of the preceding example:
// Methods with differing type signatures are overloaded – not overridden.
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
// display i and j
void show() {
System.out.println("i and j: " + i + " " + j);
}
}
// Create a subclass by extending class A.
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
// overload show()
void show(String msg) {
System.out.println(msg + k);
}
}
class Override {
public static void main(String args[]) {
B subOb = new B(1, 2, 3);
subOb.show("This is k: "); // this calls show() in B
subOb.show(); // this calls show() in A
}
}
The output produced by this program is shown here:
This is k: 3
i and j: 1 2
The version of show( ) in B takes a string parameter. This makes its type signature
different from the one in A, which takes no parameters. Therefore, no overriding takes place.