A limited form of multiple inheritance is achieved with interfaces,
which is the next topic.
Inheritance Example
public class NormedComplex
extends Complex // the inheritance
{
private double norm;
NormedComplex(double x, double y)
{
super(x,y); // if this is not here, super() is assumed.
// if super() not defined, compiler error.
norm = x*x-y*y;
}
NormedComplex()
{
this(0,0); // No call to super() as "this" will call super.
}
public void normalize()
{
setReal(getReal()/norm); // getReal is inherited
setComplex(getImaginary()/norm);
}
....
}
Shadowing/Overriding
- Super can be used to access data member and member functions of the
superclass (the one which was extended).
- In the subclass, one can use the same variable name or method name
as in the superclass.
This shadows (hides) the inherited value. To get the inherited
value use super.x.
- One can also shadow methods, which is called overriding .
Again to get the inherited method, use super.method(...).
- You cannot go up more than one level, by using super.super....
- You can prevent shadowing/overriding by declaring the member
to be final. It is common to declare constants to be final.
- You cannot increase the accessibility in subclasses.
Casting
- Casting converts an instance of one type to another type, via
the prefix operator (type).
- Casting can be explicit or implicit.
- Examples of implicit casting:
- 3+4.2 Here 3 is cast from integer to float.
- "sam"+3 Here 3 is cast from integer to String.
- Implicit casting is also called upcasting or widening,
as the object gains additional fields, usually set to
some default value.
- Explicit casting typical narrows or removes fields, which
is called downcasting.
This can be dangerous as information maybe lost. For example:
int i = 1000;
byte b = (byte) i;
If you are sure of the range of variable's value, casting may not
hurt, as in:
int i = 4;
byte b = (int)4;
-
A typical use of casting occurs when retrieving elements
from some container, such as a Vector.
Vector v = new Vector();
v.addElement(Complex c = new Complex(3,4)); // c is upcast to object
Complex c1 = v.getElementAt(0); // This is an error, instead use
Complex c1 = (Complex) v.getElementAt(0); // downcasting
Notice that in Java Vectors are unsafe as Vectors (and other containers)
only hold Objects. Without undue cost, you can't enforce a Vector
of a particular type. Here Java is not as strongly typed as C++ is,
which would accomplish the task via templates.
Abstract Classes
- An abstract method consists of the signature followed by
a semicolon, e.g. double area();
- An abstract method is used to set up a promise or contract that
every concrete subclass will implement the abstract method.
- A class is abstract
if it has at least one method without an implementation or
if it is declared abstract.
- A class that contains an abstract method must be declared
abstract.
- You cannot instantiated (have an instance of) an abstract class.
- Subclasses of an abstract class may be abstract.
- Subclasses of a concrete class can be abstract.
- If a subclass overrides all the abstract methods, then it
can be instantiated.
Polymorphism Example
abstract class Shape // can't be instantiated
{
double area(); // notice prototype
double perimeter();
}
class Rectangle extends Shape
{
double length, width;
Rectangle(double length , double width)
{
this.length = length;
this.width = width;
}
double area()
{
return length*width;
}
double perimeter()
{
return 2*length + 2*width;
}
}
class Square extends Rectangle
{
square(double side)
{
super(side,side);
}
}
class Circle extends Shape
{
double radius;
circle(double radius)
{
this.radius = radius;
}
double area()
{
return Math.PI*radius*radius;
}
double perimeter()
{
return Math.PI*diameter(); // you don't worry about order of declaration
}
double diameter()
{
return 2*radius;
}
Polymorphism Example 2
Suppose we have graphical objects like buttons, scrollbars,
textfields, canvas, radio buttons and the like.
Suppose each is derived from a superclass class component, which
has a paint method.
Suppose each graphical object overrides the paint method, saying
how it should be drawn on display.
Suppose we have a method update() which has a container for
all the objects on display and simple calls paint on each of them.
Notice how easy it will be to add a new graphical object.
This is how Applet draw on the screen.
What have we accomplished?
- guaranteed that all implementation of shape have area function,
otherwise compile-time error.
- allowed for uniform determination of area via polymorphism,
e.g. we could have a vector of shapes which was a mixture of
rectangles, squares, and circles and we could loop through them
and determine each objects area. But remember we need to cast them
to shape.
Accessibility Rules
The boundaries of accessibility are determined by class, subclass
and package. If you write your code(classes) in one directory, then the
classes are all part of the same anonymous package.
- Public means accessible to anyone.
- Private means accessible only to members of the class
or to its inner classes.
- No designation means package or friendly accessibility,
ie. full visibility of methods and data to anyone in the same package.
- Protected means accessible to subclasses
and to package members.
- Private Protected means accessible only to subclasses.
- Note: when you subclass and override, you cannot increase the
accessibility. This would lead to a compile error.