Java Programming Notes # 1628
Preface
This series of lessons is designed to teach you about the essence of Object-Oriented
Programming (OOP) using Java.
The first lesson in the series was entitled
The
Essence of OOP Using Java, Objects, and Encapsulation. The previous
lesson was entitled
The
Essence of OOP using Java, Array Objects, Part 3.
You may find it useful to open another copy of this lesson in a separate
browser window. That will make it easier for you to scroll back and
forth among the different listings while you are reading about them.
For further reading, see my extensive collection of online Java tutorials
at
Gamelan.com. A consolidated
index is available at
Baldwin’s
Java Programming Tutorials.
Preview
This lesson explains the use of the keywords this and super.
Short sample programs illustrate how you can use these keywords for several
purposes.
I will discuss and illustrate the use of the this keyword in
the following situations:
-
To bypass local variables or parameters that hide member variables having
the same name, in order to access the member variable. -
To make it possible for one overloaded constructor to invoke another overloaded
constructor in the same class. -
To pass a reference to the current object to a method belonging to a different
object (as in implementing callbacks, for example).
I will also discuss and illustrate the use of the super keyword
in the following situations:
-
To bypass the overridden version of a method in a subclass and execute
the version in the superclass. -
To bypass a member variable in a subclass in order to access a member variable
having the same name in a superclass. -
To cause a constructor in a subclass to invoke a parameterized constructor
in the immediate superclass.
Discussion
and Sample Code
You already know quite a lot about OOP
By now you know that an object is an instance of a class.
You know that all variables and methods in Java must be contained in a
class or an object. You know that the three primary characteristics
of an object-oriented programming language are:
- encapsulation
- inheritance
- polymorphism.
If you have been studying this series of lessons on the Essence of OOP
in Java, you already know quite a lot about OOP in general, and the implementation
of OOP in Java in particular.
A few more important OOP/Java concepts
However, there are a few more important concepts that I haven’t previously
discussed in this series of lessons. In this lesson, I will explain
the use of the keywords this and super.
Data and methods
The class provides the plan from which objects are built. This plan
defines the data that is to be stored in an object, and the methods
for manipulating that data. The data is variously referred to as
data
members, fields, and variables, depending on which book
you are reading.
Non-static and static
The data can be further sub-divided into non-static and static,
often referred to as instance variables and class variables
respectively.
The methods are also often referred to as member methods, and
they can also be static or non-static. Static methods
are often referred to as class methods while non-static methods
are often referred to as instance methods.
Instance variables and instance methods
The class body contains the declarations for, and possibly the
initialization
of
all data members (both class variables and instance variables) as
well as the full definition of all methods.
In this lesson, we will be particularly interested in instance variables
and instance methods.
Every class is a subclass of Object
By default, every class in Java extends (either directly or indirectly)
the class named Object. A new class may either extend Object,
or extend another class that extends
Object, or extend another class
further down the inheritance hierarchy.
The immediate parent class of a new class is known as its superclass,
and the new class is known as the subclass.
(Sometimes we use
the word superclass to indicate the collection of classes in the inheritance
hierarchy from which a specific class is derived.)
If you do not specify the superclass for a new class, it will
extend Object by default.
The extends keyword
The keyword extends is used in the class declaration to specify
the immediate superclass of the new class using the syntax shown
in Figure 1.
class NewClass extends SuperClassName{ //body of class }//end class definition Figure 1 |
Inheritance
A class inherits the variables and methods of its superclass, and of
the superclass of that class, etc., all the way back up the family tree
to the single class Object, which is the root of all inheritance.
Thus, an object that is instantiated from a class contains all the instance
variables and all the instance methods defined by that that class and defined
by all its ancestors.
However, the methods may have been overridden one or more times
along the way. Also, access to those variables and methods may have been
restricted through the use of the public, private, and protected
keywords. (There is another access level, often referred to as
package
private, which is what you get when you don’t use an access keyword.)
The this keyword
Every instance method in every object in Java receives a reference named
this
when the method is invoked. The reference named this is a
reference to the object on which the method was invoked. It can be
used for any purpose for which such a reference is needed.
Three common situations
There are at least three common situations where such a reference is
needed:
-
To bypass local variables or parameters that hide member variables having
the same name, in order to access the member variable. -
To make it possible for one overloaded constructor to invoke another overloaded
constructor in the same class. -
To pass a reference to the current object to a method belonging to a different
object (as in implementing callbacks, for example).
Hidden member variables
Normally, instance methods belonging to an object have direct access
to the instance variables belonging to that object, and to the class variables
belonging to the class from which that object was instantiated. (Class
methods never have access to instance variables or instance methods.)
Name can be duplicated
However, the name of a method parameter or constructor parameter can
be the same as the name of an instance variable belonging to the object
or a class variable belonging to the class. It is also allowable
for the name of a local variable to be the same as the name of an instance
variable or a class variable. In this case, the local variable or
the parameter is said to hide the member variable having the same
name.
Reference named this is passed to instance
methods
As mentioned above, whenever an instance method is invoked on an object,
a hidden reference named this is always passed to the method. The
this
reference
always refers to the object on which the method was invoked. This
makes it possible for the code in the method to refer back to the object
on which the method was invoked.
The reference named this can be used to access the member variables
hidden by the local variables or parameters having of the same name.
The sample program named This01
The sample program shown in Listing 1 illustrates the use of the this
reference
to access a hidden instance variable named myVar and a hidden class
variable named yourVar.
/*File This01.java Copyright 2002, R.G.Baldwin Illustrates use of this keyword to access hidden member variables. Tested using JDK 1.4.0 under Win2000 The output from this program is: myVar parameter = 20 local yourVar variable = 1 Instance variable myVar = 5 Class variable yourVar = 10 **************************************/ class This01 { int myVar = 0; static int yourVar = 0; //Constructor with parameters named // myVar and yourVar public This01(int myVar,int yourVar){ this.myVar = myVar; this.yourVar = yourVar; }//end constructor //---------------------------------// //Method with parameter named myVar // and local variable named yourVar void myMethod(int myVar){ int yourVar = 1; System.out.println( "myVar parameter = " + myVar); System.out.println( "local yourVar variable = " + yourVar); System.out.println( "Instance variable myVar = " + this.myVar); System.out.println( "Class variable yourVar = " + this.yourVar); }//end myMethod //---------------------------------// public static void main( String[] args){ This01 obj = new This01(5,10); obj.myMethod(20); }//end main method }//End This01 class definition. Listing 1 |
The key points
The key points to observe in the program is Listing 1 are:
-
When the code refers to myVar or yourVar, the reference resolves
to either an incoming parameter or to a local variable having that name. -
When the code refers to this.myVar or this.yourVar, the reference
resolves to the corresponding instance variable and class variable having
that name.
To summarize this situation, every time an instance method is invoked,
it receives a hidden reference named this. That is a reference
to the object on which the method was invoked.
The code in the method can use that reference to access any instance
member of the object on which it was invoked, or any class member of the
class from which the object was instantiated.
However, when class methods are invoked, they do not receive such a
hidden reference, and therefore, they cannot refer to any instance members
of any object instantiated from the class. They can only access class
members of the same class.
Invoking other constructors of the same class
Now I am going to discuss and illustrate the second common situation
listed earlier.
A class can define two or more overloaded constructors having the same
name and different argument lists. Sometimes it is useful for one
overloaded constructor to invoke another overloaded constructor in the
same class. When this is done, the constructor being invoked is referred
to as though it were a method whose name is this, and whose argument
list matches the argument list of the constructor being invoked.
The sample program named This02
This situation is illustrated in the program named This02 shown
in Listing 2.
/*File This02.java Copyright 2002, R.G.Baldwin Illustrates use of this keyword for one overloaded constructor to access another overloaded constructor of the same class. Tested using JDK 1.4.0 under Win2000 The output from this program is: Instance variable myVar = 15 **************************************/ class This02 { int myVar = 0; public static void main( String[] args){ This02 obj = new This02(); obj.myMethod(); }//end main method //---------------------------------// //Constructor with no parameters public This02(){ //Invoke parameterized constructor this(15); }//end constructor //---------------------------------// //Constructor with one parameter public This02(int var){ myVar = var; }//end constructor //---------------------------------// //Method to display member variable // named myVar void myMethod(){ System.out.println( "Instance variable myVar = " + myVar); }//end myMethod }//End This02 class definition. Listing 2 |
Invoking a noarg constructor
Pay particular attention to the boldface code in Listing 2. The
main
method instantiates a new object by applying the new operator to
the noarg constructor for the class named This02. (The
common jargon for a constructor that doesn’t take any parameters is a noarg
constructor.)
The noarg constructor invokes a parameterized
constructor
The code in the noarg constructor uses the this keyword
to invoke the other overloaded constructor, passing an int value of 15
as a parameter.
That constructor stores the value of the incoming parameter (15) in
the instance variable named myVar. Then control returns to
the noarg constructor, which in turn returns control to the main
method. When control returns to the main method, the new object
has been constructed, and the instance variable named myVar belonging
to that object contains the value 15.
Display the value of the instance variable
The next statement in the main method invokes the method named
myMethod
on the object, which causes the value stored in the instance variable (15)
to be displayed on the screen.
The most important statement
For purposes of this discussion, the most important statement in the
program is the statement that reads:
this(15);
This is the statement used by one overloaded constructor to invoke another
overloaded constructor.
Callbacks
An extremely important concept in programming is the third situation
mentioned in the earlier list. This is a situation where a method
in one object invokes a method in another object and passes a reference
to itself as a parameter. (This is sometimes referred to as registration.
That is to say, one object registers itself on another object.)
The method in the second object saves the reference that it receives
as an incoming parameter. This makes it possible for a method in
the second object to make a callback to the first object sometime later.
This is illustrated in the program named This03, shown in Listing
3.
/*File This03.java Copyright 2002, R.G.Baldwin Illustrates using the this keyword in a callback scenario. Tested using JDK 1.4.0 under Win2000 The output from this program is: Instance variable myVar = 15 **************************************/ class This03 { public static void main( String[] args){ ClassA objA = new ClassA(); ClassB objB = new ClassB(); objA.goRegister(objB); objB.callHimBack(); objA.showData(); }//end main method }//End This03 class definition. //===================================// class ClassA{ int myVar; void goRegister(ClassB refToObj){ refToObj.registerMe(this); }//end goRegister //---------------------------------// void callMeBack(int var){ myVar = var; }//end callMeBack //---------------------------------// void showData(){ System.out.println( "Instance variable myVar = " + myVar); }//end showData }//end ClassA //===================================// class ClassB{ ClassA ref; void registerMe(ClassA var){ ref = var; }//end registerMe //---------------------------------// void callHimBack(){ ref.callMeBack(15); }//end callHimBack }//End ClassB class definition Listing 3 |
Not intended to be useful
Note that the program in Listing 3 is intended solely to illustrate
the concept of a callback, and is not intended to do anything useful.
This is a rather long and convoluted explanation, so please bear with me.
The main method begins by instantiating two objects, one each
from the classes named ClassA and ClassB.
Go register yourself
Then the main method sends a message to objA telling it
to go register itself on objB. A reference to objB
is passed as a parameter to the method named goRegister belonging
to objA.
The code in objA uses this reference to invoke the method named
registerMe
on objB, passing this as a parameter. In other words,
the code in objA invokes a method belonging to objB passing
a reference to itself as a parameter. The code in objB saves
that reference in an instance variable for later use.
Make a callback
Then the main method sends a message to objB asking it
to use the saved reference to make a callback to objA. The
code in the method named callHimBack uses the reference to objA
saved earlier to invoke the method named callMeBack on objA,
passing 15 as a parameter. The method named callMeBack belonging
to objA saves that value in an instance variable.
Show the data
Finally, the main method invokes the showData method on
objA
to cause the value stored in the instance variable belonging to objA
to be displayed on the computer screen.
Callbacks are important
Again, this program is provided solely to illustrate the concept of
a callback using the this keyword. In practice, callbacks
are used throughout Java, but they are implemented in a somewhat more elegant
way, making use of interfaces.
For example, interfaces with names like Observer and MouseListener
are commonly used to register observer objects on observable
objects (sometimes referred to as listeners and sources).
Then later in the program, when something of interest happens on the observable
object (the source), all registered observer objects (the
listeners), are notified of the event.
The main point regarding the this reference
The main point of this discussion is that the this reference
is available to all instance methods belonging to an object, and can be
used whenever there is a need for a reference to the object on which the
method is invoked.
To disambiguate something
At least one prominent author uses the word disambiguate to describe
the process discussed above, where the this keyword is used to bypass
one variable in favor of a different variable having the same name.
I will also use that terminology in the following discussion.
Three uses of the super keyword
If your class overrides a method in a superclass, you can use
the super keyword to bypass the overridden version in the class
and execute the version in the superclass.
If a local variable in your method or a member variable in your class
hides a member variable in the superclass (having the same name),
you can use the super keyword to access the member variable
in the superclass.
You can also use super in a constructor of your class to invoke
a parameterized constructor in the superclass.
The program named Super3
The program in Listing 4 uses super to invoke a parameterized
constructor in the superclass from the subclass constructor. This
is an important use of super.
The program also uses this and super to disambiguate a
local variable, an instance variable of the subclass, and an instance variable
of the superclass. All three variables have the same name.
/*File Super3.java Copyright 2002, R.G.Baldwin Illustrates use of super reference to access constructor in superclass. Also illustrates use of super to disambiguate instance variable in subclass from instance variable in superclass. Illustrates use of this to disambiguate local variable from instance variable in subclass. Tested using JDK 1.4.0 under Win2000 The output from this program is: In SuperClass constructor. Setting superclass instance var to 500 In subclass constructor. Setting subclass instance var to 400 In main Subclass instance var = 400 In method myMeth Local var = 300 Subclass instance var = 400 SuperClass instance var = 500 **************************************/ class SuperClass{ int data; //Parameterized superclass // constructor public SuperClass(int val){ System.out.println( "In SuperClass constructor. "); System.out.println( "Setting superclass instance " + "var to " + val); data = val; System.out.println();//blank line }//end SuperClass constructor }//end SuperClass class definition //===================================// class Super3 extends SuperClass{ //Instance var in subclass has same // name as instance var in superclass int data; //Subclass constructor public Super3(){ //Call parameterized SuperClass // constructor super(500); System.out.println( "In subclass constructor."); System.out.println( "Setting subclass instance var " + "to 400"); data = 400; System.out.println();//blank line }//end subclass constructor //---------------------------------// //Method illustrates use of this and // super to disambiguate local // variable, instance variable of // subclass, and instance variable // of superclass. All three // variables have the same name. void myMeth(){ int data = 300;//local variable System.out.println( "In method myMeth"); System.out.println("Local var = " + data); System.out.println( "Subclass instance var = " + this.data); System.out.println( "SuperClass instance var = " + super.data); }//end method myMeth //---------------------------------// public static void main( String[] args){ Super3 obj = new Super3(); System.out.println("In main"); System.out.println( "Subclass instance var = " + obj.data); System.out.println();//blank line obj.myMeth(); }//end main method }//End Super3 class definition. Listing 4 |
The keyword super is used twice in the program in Listing 4 (both
cases are highlighted in boldface).
Invoke a parameterized constructor
The first usage of the keyword super appears as the first executable
statement in the noarg constructor for the class named Super3.
This statement reads as follows:
super(500);
This statement causes the parameterized constructor for the immediate
superclass (the class named SuperClass) of the class named
Super3,
to be executed before the remaining code in the constructor for Super3
is executed.
This is the mechanism by which you can cause a parameterized constructor
in the immediate superclass to be executed.
What if you don’t do this?
If you don’t do this, an attempt will always be made to invoke a noarg
constructor on the superclass before executing the remaining code in the
constructor for your class. (That is why you should almost always
make certain that the classes that you define have a noarg constructor
in addition to any parameterized constructors that you may define.)
First executable statement in constructor
When super(parameters) is used to invoke the superclass constructor,
it must always be the first executable statement in the constructor.
Whenever you invoke the constructor of a class to instantiate an object,
if your constructor doesn’t have a call to super as the first executable
statement in the constructor, the call to the noarg constructor
in the superclass is made automatically.
In other words, in order to construct an object of a class, it is necessary
to first construct that part of the object attributable to the superclass.
That normally happens automatically, making use of the superclass constructor
that doesn’t take any parameters.
Invoking a parameterized constructor
If you want to use a version of the superclass constructor that takes
parameters, you can make your own call to super(parameters) as the
first executable statement in your constructor (as was done in this
program).
Accessing a superclass member variable
The second use of the super keyword in the program shown in Listing
4 uses the keyword to bypass an instance variable named data in
the class named Super3, to access and display the value of an instance
variable named data in the superclass named SuperClass.
Note that in that same section of code, the this keyword is used
to bypass a local variable named data in order to display the value
of an instance variable named data in the class named Super3.
Similarly, a statement without the use of either this or super
is used to display the value of a local variable named data.
To disambiguate
Therefore, as stated earlier, the program uses this and super
to disambiguate a local variable, an instance variable of the subclass,
and an instance variable of the superclass, where all three variables have
the same name.
Accessing overridden superclass method
As mentioned earlier, if your method overrides a method in its
superclass, you can use the keyword super to invoke the overridden
version in the superclass, possibly completely bypassing the overridden
version in the subclass.
The program named Super4.
This is illustrated by the program in Listing 5. This program contains
an overridden version of a superclass method named meth. The
subclass version uses the value of an incoming parameter to decide whether
to invoke the superclass version and then to invoke some of its own code,
or to execute its own code exclusively.
/*File Super4.java Copyright 2002, R.G.Baldwin Illustrates invoking the superclass version of an overridden method from code in the subclass version. Tested using JDK 1.4.0 under Win 2000. The output from this program is: In main Entering overridden method in subclass Incoming parameter is false Subclass version only is invoked Back in or still in subclass version Goodbye from subclass version Entering overridden method in subclass Incoming parameter is true SuperClass method invoked Back in or still in subclass version Goodbye from subclass version Back in main **************************************/ class SuperClass{ //Following method is overridden in // the subclass. void meth(boolean par){ System.out.println( "Incoming parameter is " + par); System.out.println( "SuperClass method invoked"); }//end meth }//end SuperClass class definition //===================================// class Super4 extends SuperClass{ //Following method overrides method // in the superclass void meth(boolean par){ System.out.println( "Entering overridden method " + "in subclass"); //Decide whether to invoke // superclass version if(par) //Invoke superclass version super.meth(par); else{ //Don't invoke superclass version System.out.println( "Incoming parameter is " + par); System.out.println( "Subclass version only is " + "invoked"); }//end else //Execute some additional code System.out.println( "Back in or still in subclass " + "version"); System.out.println( "Goodbye from subclass version"); System.out.println();//blank line }//end overridden meth() //---------------------------------// public static void main( String[] args){ //instantiate an object of // this type Super4 obj = new Super4(); System.out.println("In main"); //Invoke overridden version of // method obj.meth(false); //Invoke superclass version of // method obj.meth(true); System.out.println("Back in main"); }//end main method }//End Super4 class definition. Listing 5 |
Only one statement contains super
The super keyword is used in only one statement in the program
in Listing 5. That statement appears in the subclass version of an
overridden method, and is as follows:
super.meth(par);
This statement is inside the body of an if statement. If
the value of par is true, then this statement is executed, causing
the superclass version of the method named meth to be executed (passing
the value of par as a parameter to the superclass method).
When the method returns, the remaining code in the subclass version of
the method is executed.
If the value of par is false, the above statement is bypassed,
and the superclass version of the method doesn’t get executed. In
this case, only the code in the subclass version is executed.
Summary
I have discussed and illustrated the use of the this keyword in
the following common situations:
-
To bypass local variables or parameters that hide member variables having
the same name, in order to access the member variable. -
To make it possible for one overloaded constructor to invoke another overloaded
constructor in the same class. -
To pass a reference to the current object to a method belonging to a different
object (as in implementing callbacks, for example).
I have also discussed and illustrated the use of the super keyword
in the following situations:
-
To bypass the overridden version of a method in a subclass and execute
the version in the superclass. -
To bypass a member variable in a subclass in order to access a member variable
having the same name in a superclass. -
To cause a constructor in a subclass to invoke a parameterized constructor
in the immediate superclass.
What’s Next?
The next lesson in this miniseries will teach you how to use exception
handling in Java.
Copyright 2002, Richard G. Baldwin. Reproduction in whole or in
part in any form or medium without express written permission from Richard
Baldwin is prohibited.
About the author
Richard Baldwin
is a college professor (at Austin Community College in Austin, TX) and
private consultant whose primary focus is a combination of Java and XML.
In addition to the many platform-independent benefits of Java applications,
he believes that a combination of Java and XML will become the primary
driving force in the delivery of structured information on the Web.
Richard has participated in numerous consulting projects involving
Java, XML, or a combination of the two. He frequently provides onsite
Java and/or XML training at the high-tech companies located in and around
Austin, Texas. He is the author of Baldwin’s Java Programming Tutorials,
which has gained a worldwide following among experienced and aspiring Java
programmers. He has also published articles on Java Programming in Java
Pro magazine.
Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology
to real-world problems.
-end-