Wednesday, June 27, 2007

Chapter 6 - Overloading, Overriding, Runtime Type and Object Orientation

Chapter 6: Overloading, Overriding, Runtime Type, and
Object Orientation

Objectives

This chapter helps you to prepare for the exam by covering the following objectives:

Know how to declare classes and inner classes, making appropriate use of all permitted
modifiers (such as public, final, static, abstract, and so forth). State the significance of
each of these modifiers both singly and in combination and state the effect of package
relationships on declared items qualified by these modifiers.
For a given class, know how to determine if a default constructor will be created, and if so, state
the prototype of that constructor.
State the legal return types for any method given the declarations of all related methods in this
or parent classes.
Know how to identify correctly constructed class declarations (of all forms including inner
classes), interface declarations, and implementations.
State the benefits of encapsulation in object-oriented design, and write code that implements
tightly encapsulated classes and the relationships is a and has a.
Know how to write code to invoke overridden or overloaded methods and parental or overloaded
constructors and describe the effect of invoking these methods.
Know how to write code to construct instances of any concrete class, including normal top-level
classes, inner classes, static inner classes, and anonymous inner classes.

- 95



Study Strategies

As you read through this chapter, you should concentrate on the following key items:

.
How classes and interfaces are declared
.
How inner and anonymous classes are declared and used
.
How constructors are declared
.
When a default constructor is created
.
How one constructor may invoke another constructor of the same class or superclass
.
How overriding and overloading differ
.
What restrictions apply to an overriding method
.
How classes are specified using is a and has a
.
What a fully encapsulated class looks like
Chapter Introduction

Because Java is an object-oriented programming language, the certification exam requires you to be
familiar with the basic concepts and techniques of object-oriented programming. In this chapter, you'll
review object-oriented programming concepts, learn to create classes and interfaces, and learn how to
use inner classes and adapter classes. You'll also learn how to declare and use constructors and
overload and override methods.

Object-Oriented Programming and Java

One of Java's many features is its extensive support of object-oriented programming. Java provides all
of the basics of object-oriented programming: object reuse, class hierarchy, inheritance, encapsulation,
polymorphism, and dynamic binding—in a programming context that is useful and efficient. The
following subsections summarize these capabilities.

Object Composition and Reuse

The fact that one object can be composed of, or built from, other objects is the heart of object-oriented
programming. This allows more complex objects to be constructed from basic building blocks. For
example, suppose that you're developing a drawing program. Your drawing application would consist of
objects such as windows, menus, a drawing canvas, a tool palette, a color palette, and so on. Some of
these objects are available in class libraries and others are built from more primitive components. You
develop your drawing application by gathering and building its component classes and assembling them
into an integrated whole.

Object composition not only enables you to simplify the organization of your programs, it also lets you
reuse the software you develop. For example, you could develop drawing classes as part of your
drawing program and reuse those classes in a paint program and a desktop publishing program. You
could also package your drawing classes and give or sell them to others so that they can use them as a
foundation for building other custom classes. Object reuse provides you with the capability to build a
core library of classes (such as the Java API) from which you can quickly and easily piece together your
programs. Without object reuse, you are forced to start from scratch with every program that you
develop.

Classification and Inheritance

Object reuse is not limited to object composition. It also exploits a powerful capability of object-oriented
programming known as inheritance. Inheritance not only allows objects to be used as is, but also
enables new objects to be created by extending and tailoring existing objects.

- 96



Classification is a way that we organize knowledge in general. We use classification whether or not we
are doing object-oriented programming. When we encounter a new object in our daily experience, we
try to fit that object in our existing classification scheme. If it fits an existing category, we know what kind
of object it is. If it doesn't fit, we add a new category.
Figure 6.1 illustrates how we use classification to represent knowledge. When we classify objects in this
hierarchical fashion, the classes at the top of the tree include all of the classes below them. If a class
appears in the classification tree, it provides the properties of all object categories above it in the tree.
Figure 6.2 presents a classification tree for different types of vehicles. All categories in the tree below
the category car, for example, share the common characteristics of having four wheels, being self-
powered, and being designed for passenger transportation. The fact that a lower-level category shares
the characteristics of the categories above it in the classification tree is known as inheritance. The
lower-level categories are said to inherit the characteristics of the categories above them in the tree.

In Java, inheritance applies to the subclass relationship. When a class X extends another class Y, it
inherits all of the (non-private) variables and methods of Y. This is very powerful feature for object
reuse—not only can you reuse classes as they are defined, you can easily extend them and tailor their

definitions by adding additional data and methods to their subclasses.
Figure 6.1: Hierarchical classification of knowledge.


Figure 6.2: A vehicle classification tree.

Encapsulation

One characteristic of object-oriented programming that is often touted is encapsulation. The term carries
the connotation of an object being enclosed in some sort of container—that is exactly what it means.
Encapsulation is the combining of data and the code that manipulates that data into a single
component—that is, an object. Encapsulation also refers to the control of access to the details of an
object's implementation. Object access is limited to a well-defined, controlled interface. This allows
objects to be self-contained and protected from accidental misuse, both of which are important to
reliable software design. When a class is fully encapsulated, it is possible to change the class's

- 97



implementation without impacting other objects that use the class. A fully encapsulated class declares
all of its variables as private and provides methods for getting and setting the properties represented
by field variables.

Note Single and Multiple Inheritance When one class extends another class, it

inherits the data and methods of the class it extends. This is known as single

inheritance. In some languages, but not Java, it is possible for a class to extend

multiple classes on different branches of the class hierarchy tree. This is known

as multiple inheritance. Since Java classes may only have one parent, Java does

not support multiple inheritance.

Tip Encapsulation Make sure that you understand the concept of encapsulation.

You're likely to see at least one question about it on the test.

Polymorphism

Polymorphism is the capability to assume different forms. In object-oriented programming, this refers to
the capability of objects to have many methods of the same name, but with different types of arguments.
The print() and println() method of the PrintStream class are an excellent example of
polymorphism. These methods support printing of objects of different types.

The compiler and runtime system support polymorphism by matching each method invocation to the
form of that method. The capability to figure out which method to use in complex situations is the
essence of polymorphism.

Late Binding

Sometimes a program might need to interface with objects of many different classes. For example,
consider a program that has the responsibility of receiving an object over a communication link. The
program may not know what class an object belongs to until it receives it. The capability to defer until
runtime the decision about what class an object belongs to is known as late binding or dynamic binding.
Late binding is important in object-oriented programming because it allows programs to be developed in
a more flexible manner. Without late binding, a program is required to know beforehand which classes
of objects it will access at compile time. Late binding is key to supporting class inheritance because it
allows an algorithm that is designed for a given class to work with any subclasses of that class. The
runtime system identifies the actual class of an object and invokes any overriding methods of that class.

Object-Oriented Programming and Java

One of Java's many features is its extensive support of object-oriented programming. Java provides all
of the basics of object-oriented programming: object reuse, class hierarchy, inheritance, encapsulation,
polymorphism, and dynamic binding—in a programming context that is useful and efficient. The
following subsections summarize these capabilities.

Object Composition and Reuse

The fact that one object can be composed of, or built from, other objects is the heart of object-oriented
programming. This allows more complex objects to be constructed from basic building blocks. For
example, suppose that you're developing a drawing program. Your drawing application would consist of
objects such as windows, menus, a drawing canvas, a tool palette, a color palette, and so on. Some of
these objects are available in class libraries and others are built from more primitive components. You
develop your drawing application by gathering and building its component classes and assembling them
into an integrated whole.

Object composition not only enables you to simplify the organization of your programs, it also lets you
reuse the software you develop. For example, you could develop drawing classes as part of your
drawing program and reuse those classes in a paint program and a desktop publishing program. You
could also package your drawing classes and give or sell them to others so that they can use them as a
foundation for building other custom classes. Object reuse provides you with the capability to build a
core library of classes (such as the Java API) from which you can quickly and easily piece together your
programs. Without object reuse, you are forced to start from scratch with every program that you
develop.

- 98



Classification and Inheritance

Object reuse is not limited to object composition. It also exploits a powerful capability of object-oriented
programming known as inheritance. Inheritance not only allows objects to be used as is, but also
enables new objects to be created by extending and tailoring existing objects.

Classification is a way that we organize knowledge in general. We use classification whether or not we
are doing object-oriented programming. When we encounter a new object in our daily experience, we
try to fit that object in our existing classification scheme. If it fits an existing category, we know what kind
of object it is. If it doesn't fit, we add a new category.
Figure 6.1 illustrates how we use classification to represent knowledge. When we classify objects in this
hierarchical fashion, the classes at the top of the tree include all of the classes below them. If a class
appears in the classification tree, it provides the properties of all object categories above it in the tree.
Figure 6.2 presents a classification tree for different types of vehicles. All categories in the tree below
the category car, for example, share the common characteristics of having four wheels, being self-
powered, and being designed for passenger transportation. The fact that a lower-level category shares
the characteristics of the categories above it in the classification tree is known as inheritance. The
lower-level categories are said to inherit the characteristics of the categories above them in the tree.

In Java, inheritance applies to the subclass relationship. When a class X extends another class Y, it
inherits all of the (non-private) variables and methods of Y. This is very powerful feature for object
reuse—not only can you reuse classes as they are defined, you can easily extend them and tailor their

definitions by adding additional data and methods to their subclasses.
Figure 6.1: Hierarchical classification of knowledge.


Figure 6.2: A vehicle classification tree.

Encapsulation

One characteristic of object-oriented programming that is often touted is encapsulation. The term carries
the connotation of an object being enclosed in some sort of container—that is exactly what it means.

- 99



Encapsulation is the combining of data and the code that manipulates that data into a single
component—that is, an object. Encapsulation also refers to the control of access to the details of an
object's implementation. Object access is limited to a well-defined, controlled interface. This allows
objects to be self-contained and protected from accidental misuse, both of which are important to
reliable software design. When a class is fully encapsulated, it is possible to change the class's
implementation without impacting other objects that use the class. A fully encapsulated class declares
all of its variables as private and provides methods for getting and setting the properties represented
by field variables.

Note Single and Multiple Inheritance When one class extends another class, it

inherits the data and methods of the class it extends. This is known as single

inheritance. In some languages, but not Java, it is possible for a class to extend

multiple classes on different branches of the class hierarchy tree. This is known

as multiple inheritance. Since Java classes may only have one parent, Java does

not support multiple inheritance.

Tip Encapsulation Make sure that you understand the concept of encapsulation.

You're likely to see at least one question about it on the test.

Polymorphism

Polymorphism is the capability to assume different forms. In object-oriented programming, this refers to
the capability of objects to have many methods of the same name, but with different types of arguments.
The print() and println() method of the PrintStream class are an excellent example of
polymorphism. These methods support printing of objects of different types.

The compiler and runtime system support polymorphism by matching each method invocation to the
form of that method. The capability to figure out which method to use in complex situations is the
essence of polymorphism.

Late Binding

Sometimes a program might need to interface with objects of many different classes. For example,
consider a program that has the responsibility of receiving an object over a communication link. The
program may not know what class an object belongs to until it receives it. The capability to defer until
runtime the decision about what class an object belongs to is known as late binding or dynamic binding.
Late binding is important in object-oriented programming because it allows programs to be developed in
a more flexible manner. Without late binding, a program is required to know beforehand which classes
of objects it will access at compile time. Late binding is key to supporting class inheritance because it
allows an algorithm that is designed for a given class to work with any subclasses of that class. The
runtime system identifies the actual class of an object and invokes any overriding methods of that class.

Constructors

Objects are instances of classes that are created using constructors. Every class requires a constructor
in order to create object instances. In fact, if a class does not declare a constructor, the compiler
automatically creates a constructor for the class. However, in most cases, you won't rely on the
compiler to create a constructor for you, and you'll declare your own constructors. The following is the
syntax of a constructor declaration:

modifers ClassName(arguments) throwsClause {

// Constructor body


}
The modifiers, arguments, and throws clause are optional. Valid modifiers are public, protected,
private, or none. No modifier means that the constructor can only be accessed within the package
where the class is declared. The public, protected, and private modifiers are used in the same
manner as methods. The arguments and throws clause are also defined in the same way as methods.
(Refer to Chapter 4, "Declarations and Access Control."
)


One important way in which constructors differ from methods is that they are not inherited. Each class
must define its own constructors. However, if no constructor is defined for a class, the compiler will
supply a default constructor. The default constructor will not have any arguments and will simply invoke
the constructor of the class's superclass to construct an object of the class.

- 100



Tip
Private Constructors Suppose that you want to create a class but you don't want
it to be instantiated as an object. Just declare the class's constructors as private.

Using this() and super()

In some cases, you might want to define several constructors where each of the constructors takes
some subset of the arguments used to create an object. One constructor takes all the arguments and
supplies the code that constructs the object, and the other constructors take a partial list of arguments,
supply default values, and invoke the main constructor. As an example, consider the example shown in
Listing 6.1.

This()Listing 6.1: Box's Constructors Use to Access One Another

public class Box {
double x, y, width, height;
public Box(double x, double y, double width, double height) {

this.x = x;
this.y = y;
this.width = width;
this.height = height;


}
public Box(double x, double y)
{


this(x,y,10,10)
;
}
public Box()
{


this(1,1)
;
}


}
The first Box() constructor takes the arguments x, y, width, and height and assigns them to the
appropriate field variables. The second Box() constructor takes just the box's coordinates as
arguments and invokes the first constructor, passing 10 as the default value for the box's height and
width. The third constructor has no arguments and invokes the second constructor with the default value
of 1 for the box's x and y coordinates.
The this(x,y,10,10) and this(1,1) used in the second and third constructors is a special
notation provided by Java to enable you to invoke a constructor of the same class from another
constructor of that class. It is referred to as a constructor call statement. In order to use a constructor
call statement, there must be a constructor whose argument list matches those supplied with this().

Note Using this() If this() appears in a constructor, it must appear as the first

statement in the constructor.
In other cases, instead of invoking the constructor of the same class as the object being constructed,
you invoke the constructor of its superclass. To do this, you use the superclass constructor call
statement, super(). To see how super() works consider the MyBox class declared by the following
code (Listing 6.2).

Listing 6.2: Mybox Uses Super() to Access the Constructor of Box

- 101



import java.awt.Color;

public class MyBox extends Box {

Color outerColor;

Color innerColor;

public MyBox(double x, double y, double width, double height,

Color outer, Color inner) {

super(x,y,width,height);

outerColor = outer;

innerColor = inner;

}

public MyBox(Color outer, Color inner) {

super(10,10,100,100);

outerColor = outer;

innerColor = inner;

}

public MyBox() {

super();

outerColor = Color.black;

innerColor = Color.white;

}

}
The MyBox class extends Box with the capability to specify the box's outer (perimeter) and inner colors.
The first constructor invokes super(x,y,width,height) to invoke the superclass (Box) constructor
to initialize the box's location and dimensions. The second constructor also uses the superclass
constructor and passes it the default values of 10 for the box's x and y coordinates and 100 for its
width and height. The third constructor simply invokes super() to invoke the parameterless Box()
constructor of its superclass.
If either this() or super() is used in a constructor, it must appear as the first statement of the
constructor. This means that either this() or super() (but not both) may be used in a constructor. If
neither this() nor super() is supplied, an implicit super() (with no arguments) is supplied by the
compiler. This causes the superclass portion of an object to be created before that of the class itself. If a
superclass does not have a parameterless constructor, an explicit constructor invocation must be used

- 102



in the constructors of its subclasses. Also, if a class does not define an accessible constructor, it cannot
be extended.
Note Using super() If super() appears in a constructor, it must appear as the first
statement in the constructor.

Declaring Interfaces

An interface defines a collection of methods that is implemented by a class. However, it may also be
used to define constants, inner classes, and inner interfaces. The syntax of an interface declaration is
as follows:

modifiers interface InterfaceName extendsClause {

// Interface body

}
An interface may use the modifiers public and abstract. However, the use of abstract is
redundant—all interfaces are abstract because they only declare abstract methods. An interface
that is declared as public may be accessed outside its package.
The extends clause consists of the keyword extends followed by a comma-separated list of the
interfaces that are extended. An extending interface inherits all the constants and methods of the
interfaces that it extends.
An interface body may contain constant declarations, abstract method declarations, inner classes, and
inner interfaces. Inner classes and interfaces are less common and covered later in this chapter. A
constant definition declares and initializes a variable that is public, static, and final (a constant).
If you omit these modifiers the compiler will supply them for you.
Abstract methods are covered in Chapter 4.

Inner and Anonymous Classes

Inner classes and inner interfaces were introduced in JDK 1.1. An inner class (also referred to as a
nested class) is a class that is defined as a member of another class or local to a statement block. Inner
interfaces are less common than inner classes. They are defined as members of another class or
interface.

Tip
Inner and Anonymous Classes Make sure that you understand how inner and
anonymous classes are used. You'll see several exam questions that cover inner
and anonymous classes.

Inner Classes

When an inner class is defined as a member of another class, it may have the access modifiers
(public, protected, private, or package access). It may also be declared as abstract, final,
or static. The access modifiers determine how the inner class may be accessed outside the class
and outside the package in which it is declared. These modifiers are used in the same manner as with
variables and methods.
Abstract or final inner classes are rarely used. However, the distinction between static and non-
static inner classes is important.

The following is an example of a simple inner class declaration:

class Outer {

class Inner {

// Inner class body

}

}
The Outer class is a normal top-level class. The Inner class is a simple class that is declared as an
inner class of Outer.

Non-Static Inner Classes

Non-static inner classes may be used to create objects which are instances of the class. Every
instance of a non-static inner class is associated with an instance of the outer class in which it is

- 103



declared. In fact, an instance of an inner class cannot be created without first creating an instance of its
outer class. The following program illustrates this point:

class Outer {
public static void main(String[] args) {

Inner inner = new Inner();
}
class Inner {

Inner() {
}
}
}

If you attempt to compile the above program you'll get the following error message (assuming you're
using the same version of the javac compiler):
Outer.java:4: No enclosing instance of class Outer is in scope; an explicit one
must be provided when creating inner class Outer. Inner, as in "outer. new Inner
()" or "outer. super()".
Inner inner = new Inner();

^
1 error
To fix the above problem, you can create an instance of Outer and pass it as the enclosing object
instance for a new Inner object:

class Outer
{


public static void main(String[] args)
{
Outer outer = new Outer()
;
Inner inner = outer.new Inner()
;


}


class Inner
{
Inner()
{
}


}
}
The notation outer.new Inner() indicates that the Outer object referenced by outer is the
enclosing object instance that is associated with the new instance of Inner.


You can also create an instance of Inner when this refers to the instance of the enclosing object.
The following provides an example of this approach:
class Outer
{


public static void main(String[] args)
{


new Outer()
;
}
Outer()
{


new Inner()
;
}
class Inner
{


Inner()
{
}


- 104



}
}
Because the Inner() constructor is invoked from within the Outer() constructor, this refers to the
instance of the Outer object being created.


You can also construct the Outer and Inner objects within the same statement. The following
example shows you how:
class Outer
{


public static void main(String[] args)
{


new Outer().new Inner()
;
}
class Inner
{
}


}
The statement new Outer().new Inner() creates the Outer object and the Inner object in
a
compact form.
Variables and methods that are declared in an outer class are accessible from within the inner class.
However, static inner classes may only access static variables and methods in the outer class.


Note Multiple Levels of Inner Classes Multiple levels of inner classes are possible.

However, this is seldom practical.
In some cases, it is important to distinguish between an instance of an inner class and an instance of an
outer class. The this keyword refers to the current object instance. When it is used within the scope of
an inner class, it refers to the inner class. When used within the scope of an outer class, it refers to the
outer class. However, in some cases, it is desirable to refer to the instance of the outer class from within
the inner class. The following example shows how this is done.

class Outer {
String s = "Outer";
public static void main(String[] args) {

new Outer().new Inner();
}
class Inner {

String s = "Inner";

Inner()
{
System.out.println(this.s)
;
System.out.println(Outer.this.s)
;


}
}
}
The program displays the line Inner followed by the line Outer. In the Inner() constructor, this.s,
yields the value of the s variable corresponding to the Inner class and Outer.this.s refers to the s
variable of the Outer class. To refer to the instance of an outer class prepend the outer class name and
a period to this.

Static Inner Classes

Static inner classes differ from non-static inner classes in that (because they are static) they are
not instantiated as separate object instances. In addition, static classes are not associated with an
object instance of their surrounding class (although they may access static variables and methods of
the surrounding class).
Static inner classes have a static enclosing scope and are treated as top-level classes. They are
even referred to as top-level classes in some Java documentation. This leads to a contradiction in
terms—that is, a top-level inner class.

The following is a simple example of a static inner class:

- 105



class Outer {
public static void main(String[] args) {

new Inner();
}
static class Inner {

Inner() {
System.out.println("some static");
}
}
}
Note that because Inner is static, no instance of Outer is required before an instance of Inner
can be created.

Local Inner Classes

Inner classes may also be declared local to a block of code. These inner classes are referred to as local
inner classes. Since local inner classes are not class members they are not tied to an instance of an
outer class. In addition, they may not be declared as private, public, protected, or static.
Because local inner classes are defined local to a code block (like a local variable), they may only
access the local variables or method parameters of the code block in which they are defined. An
additional restriction is placed on local inner classes in that they may only access variables or
parameters that are declared as final and have been assigned a value. The following program
illustrates the use of local inner classes.

class MyClass {

public static void main(String[] args) {
final String s = "some local results";
class Local {

Local()
{
System.out.println(s)
;


}
}
new Local()
;


}
}
The Local inner class is defined within the context of the main() method. Note that s must be
declared final in order to be accessed from Local.

Anonymous Classes

It is sometimes convenient to declare and use a class on the spot. A good example of this is writing a
class to implement an event listener interface or to extend an event adapter class.

Anonymous classes fill the need to define and use a class within a single statement. Anonymous
classes (as their name implies) are classes without a name. They are declared using the name of the
class that they extend or the interface that they implement. The following describes both forms of their
syntax:

Extending a class
new SuperClassName(arguments) {
// Class body
}

Implementing an interface

- 106



new InterfaceName() {

// Implement interface methods

}
In the first form, the superclass of the class being declared is identified. No modifiers or extends
clause are allowed. The arguments (optional) that are supplied are passed to the superclass constructor
when the object is created. The superclass must have a constructor with a signature that accepts the
arguments, or a compiler error will be generated. Anonymous classes do not have constructors.
In the second form, the anonymous class is declared in terms of the interface that it implements. The
interface name is specified as the type of object being created. No implements clause is required or
possible. When an anonymous class is defined in this fashion, it is declared as a subclass of Object. A
valid declaration requires that the anonymous class implement all the methods of the interface. No
arguments may be supplied when an anonymous class is created as an interface.
The following program (Listing 6.3) illustrates the use of both forms of anonymous inner classes.

Listing 6.3: Anonymous Classes Are Handy for Defining and Using Event Handlers
import java.awt.*;
import java.awt.event.*;

class Anonymous extends Frame {
public static void main(String[] args) {

new Anonymous()
;
}
Anonymous()
{


setTitle("Anonymous")
;
setLayout(new FlowLayout())
;
final Button button = new Button("Click here!")
;
button.addActionListener(new ActionListener()
{


public void actionPerformed(ActionEvent e)
{
String label = button.getLabel()
;
if(label.equals("Click here!")
)


button.setLabel("Try again")
;
else
button.setLabel("Click here!")
;


}
})
;
add(button)
;
addWindowListener(new WindowAdapter()
{


- 107



public void windowClosing(WindowEvent e) {
System.exit(0);

}
});
pack();
setSize(200,200);
show();

}

}
The Anonymous program uses an anonymous inner class in two places. First, it creates an instance of
the ActionListener interface, which it passes as an argument to the addActionListener()
method of a Button object:

button.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

String label = button.getLabel();

if(label.equals("Click here!"))

button.setLabel("Try again");
else
button.setLabel("Click here!");
}
});
The actionPerformed() method of the ActionListener interface is implemented to handle the
clicking of the Button. You'll learn more about events in Chapter 13, "The java.awt Package: Event
Handling."
The Anonymous program also uses an anonymous class to create an object that is passed as an
argument to the addWindowListener() method. It extends the WindowAdapter class to handle the
closing of the application window.
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
The Anonymous program displays the window shown in Figure 6.3. When you click the button, it
changes its label as shown in Figure 6.4.

- 108



Figure 6.3: The opening window of the Anonymous program.


Figure 6.4: The button's label changes when you click it.

Overloading Methods

Earlier in the chapter, polymorphism was mentioned as an important feature of object-oriented
programming languages. Although polymorphism is not unique to object-oriented programming, it tends
to provide the greatest benefit in an object-oriented setting. Method overloading is the primary way in
which polymorphism is implemented in Java. Method overloading consists of using the same method
name with different arguments and return types within the same class. The only restriction placed on
overloading is that two methods may not have the same name and the same argument list. In other
words, at least one argument must be different. Argument lists differ if they are a different sequence of
types. The argument names do not matter.

Note
Operator Overloading Some languages, such as C++, support operator
overloading. Operator overloading allows the same operator to be used with
different types of operands. Java does not allow new operators to be defined.
However, it does overload the + operator, which can be used for both arithmetic
and String operations.

A great example of overloading are the print() and println() methods of the
java.io.PrintStream class. These methods are overloaded to support each of the primitive types
as well as objects.

Overriding Methods

In addition to overloading, Java also supports overriding. Overriding is similar to overloading in that it
deals with the use of functions of the same name. However, overriding is different in that it applies to the
use of methods with the same name, arguments, and return type between a class and its superclasses.
Where overloading allows more methods of the same name to be defined, overriding allows a subclass
to redefine the methods it inherits from its superclasses and therefore specialize the behavior of the
superclass.

Note
Constraints on Overloading Overloaded methods may have different return
types. However, it is illegal to define two methods with the same arguments and a
different return type. Remember, overloaded methods have the same name but
different arguments.

- 109



When a class extends its superclass, it inherits all of the non-private methods of its superclass. In some
cases, you may want to redefine some of the methods that are inherited. If the subclass creates a
method with the same name as an inherited method, but with different arguments, that is overloading.
However, if the subclass declares a method with the same name and same arguments, that's overriding.
The following rules apply to overriding:

.
The overriding (subclass) and overridden (superclass) methods must have the same return
type.
.
The accessibility of the overriding method must not be more restrictive than the overridden
method.
.. The throws clause of the overriding method must only specify exceptions that are in the
throws clause of the overridden method.

Let's look at each of the restrictions. The first one follows from the golden rule that a class may not have
two methods with the same name, same arguments, and a different return type. If a class were allowed
to declare a method with the same name, same arguments, and a different return type than a
superclass method, the method would conflict with the one inherited from the superclass.

The second restriction is a little more complicated. Its purpose is to ensure that an extending class does
not make the extended class's methods less accessible. However, what is more or less accessible is
sometimes difficult to ascertain. The following rules apply:

.
If the overridden method is public, the overriding method must also be public.
.
If the overridden method is protected, the overriding method must be public or
protected.
.
If the overridden method is package access (that is, having no modifiers), the overriding
method must be public, package access, or protected.
.
If the superclass method is private, it is not inherited by its subclasses, and overriding is
not an issue.
The third restriction requires that any exception thrown by the overriding method be throwable by the
overridden method. This means that the exception must be a subclass of some exception that is thrown
by the overridden method.

Chapter Summary

In this chapter, you reviewed the object-oriented programming used by Java. You learned how to
declare top-level classes and interfaces, and how to use inner classes and adapter classes. You also
learned how to declare and use constructors, and overload and override methods. The following review
questions will test your knowledge of these topics and help to prepare you for the certification exam.

Key Terms

.
Object reuse
.
Classification
.
Single inheritance
.
Multiple inheritance
.
Encapsulation
.
Polymorphism
.
Late binding
.
Parent class
.
Superclass
.
Direct superclass
.
Subclass
.
Strict subclass
- 110



.
Class member
.
Abstract class
.
Inner class
.
Local inner class
.
Anonymous class
.
Overloading
.
Overriding
Review Questions

1.
What is the difference between multiple inheritance and single inheritance? Which does
Java support?
2.
What modifiers may be used with a top-level class?
3.
Can an abstract class be final?
4.
What is the difference between a public and a non-public class?
5.
What must a class do to implement an interface?
6.
Is a class a subclass of itself?
7.
Does a class inherit the constructors of its superclass?
8.
When does the compiler supply a default constructor for a class?
9.
How are this() and super() used with constructors?
10. What modifiers may be used with an interface declaration?
11. What modifiers may be used with an inner class that is a member of an outer class?
12. What is the difference between a static and a non-static inner class?
13. What modifiers can be used with a local inner class?
14. Can an anonymous class be declared as implementing an interface and extending a
class?
15. What restrictions are placed on method overloading?
16. What restrictions are placed on method overriding?
Exam Questions

1.
What is the output of the following program?
2. class S1 {
3. public static void main(String[] args) {
4. new S2();
5. }
6. S1() {
7. System.out.print("S1");
8. }
9. }
10. class S2 extends S1 {
11. S2() {
12. System.out.print("S2");
13.
}
}
A. S1
B. S2
C. S1S2
D. S2S1
14. Which of the following are characteristic of a fully encapsulated class?
A.
All variables are private.
B.
All methods are private.
- 111



C.
Methods are provided to access the class's properties.
D.
The class's design may be changed with minimal impact on its
implementation.
15. What is an example of polymorphism?
A.
Inner classes
B.
Anonymous classes
C.
Method overloading
D.
Method overriding
16. Which of the following modifiers may not be used with a top-level class?
A.
public
B.
private
C.
abstract
D.
final
17. Which of the following are true about constructors?
A.
A class inherits its constructors from its parent.
B.
The compiler supplies a default constructor if no constructors are provided
for a class.
C.
All constructors have a void return type.
D.
A constructor may throw an exception.
18. What is the output of the following program?
19. class Outer {
20. String s = "Outer";
21. public static void main(String[] args) {
22. new Outer().new Inner();
23. }
24. Outer() {
25. System.out.print(s);
26. }
27. class Inner {
28. String s = "Inner";
29. Inner() {
30. System.out.print(s);
31. }
32.
}
}
A. Outer
B. Inner
C. OuterInner
D. InnerOuter
33. Which of the following are true about method overriding?
A.
The overriding and overridden methods must have the same name,
argument list, and return type.
B.
The overriding method must not limit access more than the overridden
method.
C.
The overriding method must not throw any exceptions that may not be
thrown by the overridden method.
D.
The overriding method may not be private.
34. Which of the following are true about local inner classes?
A.
They are not associated with an instance of an outer (enclosing) class.
- 112



B.
They may access final initialized variables and parameters that are in the
scope of the statement block in which the class is declared.
C.
They may be declared public, protected, or private.
D.
They may not implement an interface.
35. Given non-static classes Outer and Inner where Inner is declared as an inner
class of Outer, how is an instance of Outer accessed from within the scope of Inner?
A.
this
B.
this.Outer
C.
Outer.this
D.
this.this
36. What is the output of the following program?
37. class Question {
38. String s = "Outer";
39. public static void main(String[] args) {
40. S2 s2 = new S2();
41. s2.display();
42. }
43. }
44. class S1 {
45. String s = "S1";
46. void display() {
47. System.out.println(s);
48. }
49. }
50. class S2 extends S1 {
51. String s = "S2"
;
}
A. S1
B. S2
C. null
D. S1S2
Answers to Review Questions

1.
Multiple inheritance occurs when a class extends multiple direct superclasses. Single
inheritance occurs when a class extends a single direct superclass. Since Java classes
may have only one parent, Java does not support multiple inheritance. However, Java
does support single inheritance.
2.
A top-level class may be public, abstract, or final.
3.
An abstract class may not be declared as final.
4.
A public class may be accessed outside of its package. A non-public class may not
be accessed outside of its package.
5.
It must provide all of the methods in the interface and identify the interface in its
implements clause.
6.
A class is a subclass of itself.
7.
A class does not inherit constructors from any of its superclasses.
8.
The compiler supplies a default constructor for a class if no other constructors are
provided.
9.
this() is used to invoke a constructor of the same class. super() is used to invoke a
superclass constructor.
10. An interface may be declared as public or abstract.
- 113



11. A (non-local) inner class may be declared as public, protected, private, static,
final, or abstract.
12. A non-static inner class may have object instances that are associated with instances
of the class's outer class. A static inner class does not have any object instances.
13. A local inner class may be final or abstract.
14. An anonymous class may implement an interface or extend a superclass, but may not
be declared to do both.
15. Two methods may not have the same name and argument list but different return types.
16. Overridden methods must have the same name, argument list, and return type. The
overriding method may not limit the access of the method it overrides. The overriding
method may not throw any exceptions that may not be thrown by the overridden method.
Answers to Exam Questions

1.
C The superclass (S1) constructor is invoked before the subclass (S2) constructor.
2.
A and C A fully encapsulated class declares its variables as private and provides
methods to access the properties represented by these variables.
3.
C Method overloading is an example of polymorphism.
4.
B A top-level class may not be declared as private.
5.
B and D The compiler supplies a default constructor if no constructors are provided for a
class. Constructors may throw exceptions. These exceptions must be declared in the
constructors' throws clause.
6.
C An instance of Outer is created, followed by an instance of Inner.
7.
All are true.
8.
A and B Local inner classes may not be declared public, protected, or private.
They may implement interfaces.
9.
C An instance of Outer is accessed as Outer.this.
10. A The display() method displays the svariable of the S1 class.

No comments: