Overloading means having two or more methods defined in a class with the same name. Their numbers or types of parameters must differ. Similarly we can have overloaded constructors.
Overriding is when we have a method in a base class, and a definition of a method with the same name in a subclass. The subclass method overrides the base class method.
An example
System.out.println("Overloaded Base method2 with an int");
}
void method2(char x) {
System.out.println("Overloaded Base method2 with a char");
} }
class Sub extends Base {
void method1() {
System.out.println("Overriding method1 in Sub");
} }
The output is:
In method1 in Base
Overriding method1 in Sub
Overloaded Base method2 with an int Overloaded Base method2 with a char
Remember that constructors are not inherited.
super
'super' is a Java keyword which can be used in several contexts. In general it refers from a subclass to the base class.
super in method calls
A method in a base class can be invoked from a subclass by using the syntax super.methodName().
For example
class Test {
public static void main(String args[]) { Sub sub = new Sub();
sub.method1();
} }
class Base {
void method1() {
System.out.println("In method1 in Base");
} }
class Sub extends Base {
void method1() {
super.method1();
System.out.println("Overriding method1 in Sub");
} }
which outputs In method1 in Base
Overriding method1 in Sub
You might do this if a subclass method needs to execute the code in the base class, plus extra code.
super and data fields
super can be used to refer to data members in a base class from a subclass, if the subclass
introduces a new field with the same name. The following example is followed by a health warning:
class Test {
public static void main(String args[]) { Sub sub = new Sub();
sub.method();
} }
class Base { int x = 3;
}
class Sub extends Base { int x = 4;
void method() {
System.out.println(super.x);
System.out.println(x);
} }
This outputs 3 then 4.
Note carefully - this code fragment is unusual and not normally good practice. A subclass inherits the data members of the base class, so in this case Sub already has a data member called x. When Sub declares it again, the 'x' hides the base class 'x'. A reference to x in the subclass is not to the x in the base class - we have to say super.x to get to it.Now x was probably declared in the base class for some reason or purpose, and its now hidden in the subclass, so the sublass may not work properly.
You might well do this accidentally, declaring x in the subclass because you forgot it was a field already in the base class. For this reason most IDEs will warn you if you do this.
super in constructors
Remember that constructors are not inherited.
In a subclass, you can invoke the constructor of the base class by saying super(). This must be the first line in the constructor. For example:
class Test {
class Sub extends Base { int y;
This is a typical example (but see later) - the subclass constructor first invokes the base class constructor, then does further work.
Constructors with arguments
If the base class has a constructor which takes arguments, we can invoke it with super and an argument value:
class Sub extends Base { int y;
class Test {
class Sub extends Base { int y;
Sub() { y = 4;
} }
which again outputs 3 4. Note Sub() does not call super(), but x became 3 anyway. The compiler inserts the super call.
But what if the base class does not have a no-args constructor?
class Test {
class Sub extends Base { int y;
Sub() { y = 4;
} }
This is a compile-time error. The compiler would call Base(), but there is no no-arg constuctor in Base.
You would fix this either by writing one, or by an explicit use of super with arguments:
class Test {
public static void main(String args[]) { Sub sub = new Sub();
System.out.println(sub.x + " " + sub.y);
} }
class Base { int x;
Base(int val) { x = val;
} }
class Sub extends Base { int y;
Sub() { super(3);
y = 4;
} }
Exercise
Add comments to the last example saying what is happening.
this
In Java 'this' is a keyword. Inside a method, it is a reference to the object executing the method.
Inside a constructor, it is a reference to the object being constructed.
Example - this.x = x
Suppose we are defining a class Circle, which might have data members for radius and colour:
class Circle
We would need to pass values for the radius and colour in the constructor:
Circle(double... , Color ...) {
radius =..
color=..
}
What to name the arguments? The sensible names are color and radius, but then how to tell the difference between the arguments and the data members if they have the same name? The usual solution is to use 'this':
Circle(double radius, Color color) {
this.radius = radius;
this.color = color;
}
Now this.radius is the object data member, while radius is the argument.
Example in Swing
We will expand this example later, but this is a start. When using Swing to program a GUI, we might subclass a JFrame to make a window:
class MyFrame extends JFrame {
MyFrame() // the constructor {
..
} }
Suppose we want a button on our window. This is what a JButton is. We have to make one, then 'add' it to the window:
class MyFrame extends JFrame {
MyFrame() // the constructor {
JButton myButton = new JButton("Click here");
add(myButton);
} }
But to make the button work, we have to say what object will 'listen' for button clicks. This is done by the addActionListener method. This could be the window itself. But how to refer to the window being constructed? Use 'this':
class MyFrame extends JFrame {
MyFrame() // the constructor {
JButton myButton = new JButton("Click here");
add(myButton);
myButton.addActionListener(this);
} }
We will expand this to fully working code later.
Exercise
If you use 'this' in a method - what does it mean?
static
Data members and methods can be declared to be 'static'. That means they are per class not per object.
Despite its name, static does not mean constant. To make a data member constant, use the keyword 'final'.
Example
Suppose we were defining some different types of animals:
class Test {
class Mammal extends Animal {
int numberOfLegs;
Mammal(String name, int numberOfLegs, double height) {
this.name=name;
this.numberOfLegs=numberOfLegs;
this.height=height;
} }
class Insect extends Animal {
int numberOfLegs;
Insect(String name, int numberOfLegs, double height) {
this.name=name;
this.numberOfLegs=numberOfLegs;
this.height=height;
} }
But - all Mammals have four legs, and all Insects have six legs. The number of legs is not a
characteristic of the individual mammal - the object. It is a characteristic of the class. We can capture that idea by making numberOfLegs to be static - per class not per object:
class Test {
class Mammal extends Animal {
static int numberOfLegs;
Mammal(String name, double height) {
class Insect extends Animal {
static int numberOfLegs;
Insect(String name, double height) {
Methods as well as data members can be static. The idea is the same - per class not per object.
Example - the Math class
We often need to use maths functions like sine and cosine, and constants like π. These are bundled together in the Math class. This has a set of static methods, which are used like:
double val = Math.sin(0.6);
The method is invoked with the syntax <class>.<method>(), instead of <object>.<method>() used for non-static methods.
If the methods had not been static, we would have to have said
Math math = new Math();
double val = math.sin(0.6);
In fact you cannot say this, because the Math constructor is private. All classes have a constructor - even if just the compiler-generated no-args one. A common way of preventing a class being instantiated is to make the constructor private.
How to do it? The usual method is to have the constructor private, so it cannot be called from outside the class. You have a static method called getInstance. This checks whether there is already an instance, and if so, it returns a reference to it. Otherwise it creates one instance:
class Test {
public static void main(String args[]) {
MySingleton one = MySingleton.getInstance();
MySingleton two = MySingleton.getInstance();
if (one == two) {
System.out.println("Only got one");
} } }
class MySingleton {
static MySingleton instance = null;
private MySingleton() { }
static MySingleton getInstance() { if (instance == null) {
instance = new MySingleton();
}
return instance;
} }
Example - autonumber
We often want to have a set of objects each having a unique key field to identify it. For example a bank account needs a unique account number. This is achieved in databases by having an
'autonumber' field which automatically increases every time a new record is added. We can achieve the same thing in Java if the class maintains a static field which 'remembers' how many objects have been created:
class Test {
BankAccount(String owner) {
System.out.println("Owner: "+owner+ " Account number: "+accountNumber);
} }
which outputs:
Owner: Tom Account number: 0 Owner: Dick Account number: 1 Owner: Harry Account number: 2 Owner: Tom Account number: 3 Example - main
main is static. It has to be. The key point about main is that execution starts there. If it had been non-static, the class would have first to have been instantiated, and then main invoked on that object. But calling main by definition is the first thing that happens.
cannot be referenced from a static context Beginners often get this
compile-time error:
They will often get rid of the error message by making the method to be static. But then no objects are instantiated and there is no OO programming.
The solution is to construct an object, then invoke the method on it:
class Test {
void someMethod() {
System.out.println("hello");
}
public static void main(String args[]) { Test test = new Test();
test.someMethod();
} }
Exercise
Describe three situations where the use of 'static' is appropriate.