| Home > Core Java FAQ
> Classes, Interfaces, & Packages FAQ |
| Classes,
Interfaces & Packages |
| Objects,
Classes, and Methods(19) * Sub
Class, Overload, and Overriding(11) * Interfaces
and Abstract Classes (11) * Packages
and Access Modifiers (09) |
| |
|
Q . What is a subclass?
|
Ans :
A subclass
is a class defined as an extension or modification of another
class.
Except
for the Object class in the java.lang
package, every class in the Java language is a subclass of some
other class (called its immediate superclass, or superclass
for short). A subclass behaves like its superclass, except where
it speci-fies extensions or modifications.
A subclass can extend its superclass
by defining additional instance variables and methods for the
subclass instances, or by defining additional class variables and
class methods for the subclass. A subclass can also modify the
behavior of its superclass by replacing some of the superclass's
method definitions with its own. In both cases, the Java language
uses the extends keyword to declare subclass relationships. In the
JDK (1.0.2 and 1.1), for example, the FileInputStream
class in the java.io package is defined as a subclass
of InputStream:
/* in FileInputStream.java (JDK 1.0.2 and 1.1): */
public class FileInputStream extends InputStream {
// ... fields and method definitions
}
If a class
definition omits the extends clause, the class is
defined as an immediate subclass of the root Object
class.
The subclass relation is transitive:
if class Z is a subclass of class Y, and class Y is a subclass of
class X, then class Z is a subclass of class X:
Z
subclass of Y, Y subclass of X => Z subclass of X
By means of
transitivity, Object is the ultimate superclass; all other classes
are direct or indirect subclasses of Object.
Subclasses are fundamental to
object-oriented programming. They enable substitutability (also
called polymorphism), the property by which a subclass
instance can be used anywhere that one of its superclasses is
expected:
|
Substitutability
(Polymorphism)
|
| Using a subclass
instance where a superclass type is expected |
as the object on which a method is
invoked |
| as the argument to a method or
constructor |
| as the value assigned to a variable |
As a final note, the immediate superclass-subclass
relationship in the Java language is one-to-many. A subclass has
only one immediate superclass (single inheritance), but a
superclass can have any number of subclasses.
|
|
Q .
What is inheritance?
|
Ans
:
Inheritance
is the way a subclass uses method definitions and variables from a
superclass just as if they belonged to the subclass itself.
In
general, any instance method or instance variable not defined in a
subclass is inherited from its superclass. (There are
systematic exceptions to this rule) A subclass can use the
inherited methods and variables just as if it had defined them
itself. Inheritance is a powerful mechanism for reusing code: you
can start from existing (and, hopefully, reliable) classes and
write code to provide just the extra functionality you require.
Inheritance provides a chain in
which a class inherits not only from its immediate superclass, but
also from any superclass upwards to the Object class.
All Java classes ultimately inherit from Object.
For example, the Button
class in the java.awt package is defined as a
subclass of the powerful, generic Component class.
The Java language uses the extends keyword to declare
this subclass relationship:
/* in Button.java, JDK 1.0.2: */
public class Button extends Component {
// ... class definition code
}
The
class definition for Button in the JDK 1.0.2 is
surprisingly small. The key extensions from Component
to Button are one instance variable and two methods:
label:
a String instance—the button's text label
getLabel():
returns the button's text label
setLabel(String):
sets the button's text label
Nevertheless, a Button
instance possesses full Component functionality: you
can send events to a Button instance, you can draw it
on screen, you can resize and reposition it, you can enable or
disable it, and so on. All of this functionality is inherited from
the Component class, and is accessed using methods
defined in the Component class.
|
|
Q .
What is an overloaded method?
|
Ans
:
An
overloaded method, strictly speaking, is more than one method: it
is two or more separate methods (defined or inherited) in the same
class that share the same name.
Methods
belong to classes, and methods within a class are distinguished
according to their signatures: the combination of method name,
number of parameters, and types of parameters (Q1.4).
Accordingly, you can use the same name for different methods only
if the methods contain different parameter lists.
Method overloading allows you to
group conceptually similar methods under the same name, and to use
simpler names in general. Your method names can reflect the
behavior of the methods without having to worry about how many or
what types of parameters the methods take.
The Math class in the java.lang
package illustrates method overloading based on parameter types.
It defines four different methods with the name max:
max(int,
int), returns an int
max(long,
long), returns a long
max(float,
float), returns a float
max(double,
double), returns a double
Without method
overloading, each max method would need to have its
own distinct name, such as maxInt, maxLong,
maxFloat, and maxDouble. Using the same
method name is simpler and conveys the unity of purpose among
these four methods.
As a second example, the String
class has two methods named substring. One uses two
parameters to specify both a starting point and an ending point
from which to extract the substring; the other uses one parameter
to specify just the starting point:
substring(int, int),
returns a String instance
substring(int), returns a
String instance
Again, using the same
name for both methods highlights their common functionality; the
difference in parameter lists makes enough of a distinction.
Note: Java, unlike C++,
allows inherited methods to coexist with overloaded methods. In a
subclass, you can define a method with the same name as a method
inherited from a superclass, and the superclass method will be
accessible provided the two method signatures are distinct. (If
the signatures are the same, you've overridden rather than
overloaded the method
|
|
Q .
What does it mean to override a method?
|
Ans
:
Instead of
inheriting a method from its superclass, a subclass can override
the method by providing its own definition for it.
Overriding
complements inheritance: it lets you choose which behaviors of a
superclass to accept as is (inherit) and which to replace with
code that you need specifically for your subclass (override).
Overriding also lets you provide implementations for methods that
the superclass declares as abstract.
Overriding requires a precise
replacement of the superclass's method: the subclass's method must
have the same name, parameter list, and return type as the
superclass's method. Its declared exceptions must also be
compatible with those of the superclass. In the JDK 1.0.2, for
example, the Applet class inherits Component's
update method, which completely clears the background
before redrawing (via paint):
/* in Component.java (JDK 1.0.2): */
public void update(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
g.setColor(getForeground());
paint(g);
}
You can define an Applet
subclass and change this behavior by overriding update
in that subclass, for instance, to avoid clearing the background
first:
/* overriding update in an Applet subclass: */
public void update(Graphics g) {
paint(g);
}
A
key point is that, from the subclass's perspective, overriding a
method completely replaces the superclass's method. Whenever you
invoke the method on an instance of the subclass, you execute the
subclass's code for the method rather than the superclass's. To
include the superclass's implementation as part of your subclass's
method, you use the super keyword
|
|
Q .
What is the difference between overloading and overriding?
|
Ans
:
Overloading
occurs when two or more methods use the same name (but different
parameter lists), such that both methods are available side by
side in the same class; overriding occurs when a subclass method
and a superclass method use the same name (and matching parameter
lists), such that the subclass method blocks out the superclass
method.
Overloading
and overriding are often confused with each other, because
the words are similar and because they both involve a single
method name referring to potentially several different method
implementations. There are clear differences, however, when you
compare the two point by point, as done in Table 1.4.
Table
1.4: Overloading versus Overriding
| Overloading |
Overriding |
| relationship
between methods available in the same class |
relationship
between a superclass method and a subclass method |
| does not
block inheritance from the superclass |
blocks
inheritance from the superclass |
| separate
methods share (overload) the same name |
subclass
method replaces (overrides) the superclass method |
| different
method signatures |
same method
signature |
| may have
different return types |
must have
matching return types |
| may have
different declared exceptions |
must have
compatible declared exceptions |
For example, both
the Object class and the String class
(an immediate subclass of Object) in the java.lang
package define an equals method:
- in
Object:
public boolean equals(Object obj) { /* ... */ }
- in
String:
public boolean equals(Object obj) { /* ... */ }
This is a case of
overriding, since String is a subclass of Object,
and String's equals method has the same
name, parameter types, and return type as Object's equals
method. Now suppose that a String2
class defined equals to take a String2 parameter
instead of an Object parameter:
- in
Object:
public boolean equals(Object obj)
- hypothetical
String2:
public boolean equals(String2 str)
This would be a case
of overloading. The String2 class would have two
alternate equals methods: one defined in String2
and one inherited from Object. Even though the two
methods have the same name and return type, they differ in what
parameter they take.
|
|
Q . Can I override the equals method or clone method from class Object to take a parameter or return a value of the type that I specify?
|
Ans :
No; you can
override a method from a superclass only if your subclass's method
has the same signature and return type.
Overriding
a method requires a close match between the superclass method and
the subclass method:
- the subclass
method and superclass method must have the same signature
- the subclass
method and superclass method must have the same return type
- the subclass
method's level of access must be equal to or greater than that
of the superclass method
Note that the native
and abstract keywords do not have to match between
the subclass and superclass methods.
To override Object's equals
method, you must define precisely the same return type and
parameter type as defined by the Object class. (You
are free, though, to vary the parameter name—obj in
the following example—since parameter names are not carried over
into class files.) For example:
/* overriding equals in a subclass of Object: */
public boolean equals(Object obj) { /* ... */ }
Similarly, you can
override Object's clone method only to
return Object:
/* overriding clone in a subclass of Object: */
public Object clone() { /* ... */ }
Attempting to
return any class other than Object yields a
compile-time error:
/* failed attempt to override clone: */
public MySubclass clone() { /* ... */ }
The
Vector class in the java.util package,
for example, overrides Object's clone
method and therefore returns Object rather than Vector.
To assign the cloned Vector instance to
another Vector variable, you must cast the returned
value from Object to Vector:
Vector vector1 = new Vector();
Vector vector2 = (Vector)vector1.clone();
Note:
Method overloading is an option if you really want to provide a
more specific parameter type than Object, but it is
not an option for return types. Whether you are overriding or
overloading, the return types must match exactly—a
compile-time error occurs if they don't.
|
|
Q . What is the super keyword used for?
|
Ans
:
The super
keyword gives a class explicit access to the constructors,
methods, and variables of its superclass.
The
super keyword works hand in hand with
inheritance to connect a class to its superclasses.
Inheritance gives a class implicit access to its
superclasses. When you invoke an instance method, for example, you
automatically get an inherited superclass method implementation if
the instance's class doesn't define the method for itself.
Implicit access is blocked, though, by method overriding, or by
defining instance or class variables with the same names as the
superclass versions (called hiding). This is where super
comes in. The super keyword gives a class explicit
access to its immediate superclass's parts, even if that access is
otherwise blocked. The two common uses of super are
to access the superclass's constructor and to access the
superclass's version of an overridden method.
The super keyword is
essential to the workings of constructors. Unlike methods,
constructors are not inherited; the super keyword
thus provides the only means to access a constructor in a
superclass. Within a constructor, using super(...)
triggers a call to the superclass constructor with a matching
parameter list. (The compiler issues an error if the superclass
contains no such constructor.) This is how each instance of a
class performs a chain of initializations. An instance initializes
itself as an Object instance and then steps down from
each superclass to an immediate subclass until it finally
initializes those parts that are specific to the subclass at the
end of the chain.
For example, the following Frame
subclass defines two constructors to match the two constructors
provided by the Frame class:
class ExampleFrame extends Frame {
public ExampleFrame() {
super();
}
public ExampleFrame(String title) {
super(title);
}
// ... field and method definitions
}
Even though the
constructors in this example do nothing more than invoke the
superclass constructors, you need to include them because
constructors are not inherited. (If your constructor invokes the
superclass constructor, this invocation must occur as the first
statement in your constructor definition.)
The chain of initialization is so
important that the Java system automatically includes a call to
the superclass constructor if you don't provide one yourself. The
automatic superclass constructor is always a no-parameter
constructor. For example, the JDK 1.0.2 Button class
contains the following constructor code:
/* in Button.java (JDK 1.0.2): */
public Button(String label) {
this.label = label;
}
Because of the
automatic inclusion of the superclass constructor, the above code
is equivalent to:
/* Equivalent Button constructor: */
public Button(String label) {
super();
this.label = label;
}
The automatic
default constructor has no parameters, but you can use whatever
parameter list you need by invoking the superclass constructor
explicitly.
The second common use of super
is within a method definition, to access the superclass version of
the same method. This makes sense in a method definition that is
overriding the method from its superclass. In this context, super
allows you to define an overriding method that builds around its
superclass method rather than replacing it outright. The AWT Button
class again provides a simple example:
/* in Button.java (JDK 1.0.2) */
protected String paramString() {
return super.paramString() + ",label=" + label;
}
Because Button
is a subclass of Component, this paramString
method will invoke Component's version of paramString,
which returns a String instance describing parameters
relevant to all components, and will then append the button's
label to that string. Invoking paramString on a
button thus returns a String instance that includes
the button's size and on-screen position (information all
components have) together with the button's label (information
specific to the Button subclass).
Finally, you can use super
to access a variable in a superclass that is hidden by a variable
in the subclass with the same name. The following code fragment
illustrates how, for a variable named foo:
class X {
int foo = 1; // declares instance variable foo
}
class SubX {
int foo = 2; // declares own version of foo, which hides the
// superclass version
int getSuperFoo() {
return super.foo; // returns 1, not 2
}
}
|
|
Q .
Does the Java language provide virtual methods, like C++?
|
Ans
:
Yes; but
Java methods are virtual by default, whereas C++ methods are not.
"Virtual
methods" are an essential ingredient for taking advantage of
inheritance and polymorphism. Because of inheritance and
polymorphism, an object reference need not match exactly the class
of the object it refers to: the object can belong to a subclass of
the reference's type. For example, the aThread
reference below is of type Thread, but the object it
refers to is of type MyThread, a subclass of Thread:
class MyThread extends Thread { /* ... overrides start() ... */ }
class Example {
// ...
Thread aThread = new MyThread();
myThread.start();
// ...
}
When
you invoke a method on a reference, such as the anObject.start()
expression above, the virtual machine must know which class to use
for looking up the method definition; there are two basic choices:
- static
binding—use compile-time type of object reference
- dynamic
binding—use run-time type of referred-to object
In the preceding Thread
example, dynamic binding will pick up the overridden start
method in the MyThread subclass, whereas static
binding would find only the Thread version.
Programmers familiar with C++ will recognize this distinction as
the difference between nonvirtual and virtual methods.
In the Java language and Virtual
Machine, dynamic binding is the default, and there is no virtual
keyword. The distinction between dynamic and static binding is
generally expressed in terms of whether a method can be
overridden:
|
|
Q .
What is a final class?
|
Ans
:
A final
class is a class that is declared with final keyword
so that it can never be subclassed.
Using
the final keyword in the Java language has the
general meaning that you define an entity once and cannot change
it or derive from it later. More specifically:
- a final class
cannot be subclassed
- a final method
cannot be overridden
- a final variable
cannot change from its initialized value
Classes
are usually declared final for either performance or
security reasons. On the performance side, the compiler can
optimize final classes to avoid dynamic method lookup
because their method implementations are never overridden. Methods
in a final class can work at the speed of straight
function calls, or even as inline code, which may be several times
faster than a typical method invocation on current virtual machine
implementations. The String class, for instance, is
declared final in large part because of the
performance optimizations that can be achieved. Note, however,
that the performance advantage of final classes (or final methods
for that matter) is likely to fade in the next year or two as Java
Virtual Machine implementations apply increasingly sophisticated
techniques to handle method invocation. Relying heavily on final
in your current designs may confine you unnecessarily in the
future.
On the security side, making a class
final is like putting a lock on the class—it
prevents other programmers from subclassing a secure class to
invoke insecure methods.
Note: Making an entire
class final is a fairly extreme measure and should be done only in
exceptional cases. You most often can achieve the security and
performance effects you desire by making selected methods in a
class final, while leaving the class available for subclassing.
|
|
Q . Why isn't there operator overloading?
|
Ans
:
Because C++ has proven by example that operator overloading makes code almost impossible to maintain. In fact there very nearly wasn't even method overloading in Java, but it was thought that this was too useful for some very basic methods like print(). Note that some of the classes like DataOutputStream have unoverloaded methods like writeInt() and writeByte().
|
|
Q .
If I extend/subclass a class, are the constructors inherited?
|
Ans
:
"Constructor declarations are not members. They are never inherited
and therefore are not subject to hiding or overriding." The default
constructor is not inherited, but provided. (See JLS 8.6.7 Default
Constructors)
If you don't give your child class any constructors, a default no-arg constructor that invokes the superclass' constructor is provided for
you. If the superclass doesn't have a no-arg constructor, you should
create a constructor and call the appropriate superclass constructor.
Also in the FAQ:
Compiler message No constructor {superclass}()
Other sites:
JLS 8.6.7 Default Constructors
|
|
|
|