Java Reference
In-Depth Information
It is time to use your abstract Shape class along with its concrete subclasses Rectangle and Circle . Note that
the only restriction that is applied to an abstract class, when it is used in code, is that you cannot create its objects.
Apart from this restriction, you can use it the same way you can use a concrete class. For example, you can declare a
variable of an abstract class type; you can call methods of the abstract class using that variable, etc. How do you call
a method on a Shape variable, if you cannot create an object of the Shape class? This is a good point. Let's consider the
following snippet of code:
// Upcasting at work
Shape s = new Rectangle(2.0, 5.0);
// Late binding at work. s.getArea() will call the getArea() method of
// the Rectangle class.
double area = s.getArea();
If you look at the above code, it makes sense. The first statement creates a Rectangle and assigns its reference to a
variable of the Shape class, which is a simple case of upcasting. In the second statement, you are calling the getArea()
method using the s variable. The compiler only verifies the existence of the getArea() method in the Shape class,
which is the declared type of the s variables. The compiler does not care whether the getArea() method in the Shape
class is incomplete ( abstract ) or not. It does not care if the getArea() method is abstract in the Shape class because
it is an instance method and it knows that late binding at runtime will decide which code for the getArea() method
will be executed. All it cares about is the existence of a method declaration of the getArea() method. At runtime,
the late binding process finds that the variable s is referring to a Rectangle and it calls the getArea() method of
the Rectangle class. Is it not like having one's cake and eating it too. Have an abstract class (incomplete class) and
use it too? If you look at the above two lines of code, you would find that these magical two statements involve so
many concepts of object-oriented programming: abstract class, abstract method, upcasting, method overriding, late
binding, and runtime polymorphism. All of these features are involved in the above two statements to giving you the
ability to write generic and polymorphic code.
Consider a ShapeUtil class as shown in Listing 16-39.
Listing 16-39. A ShapeUtil Class That Has Utility Methods to Draw Any Shapes and Print Details About Them
// ShapeUtil.java
package com.jdojo.inheritance;
public class ShapeUtil {
public static void drawShapes(Shape[] list) {
for (int i = 0; i < list.length; i++) {
// Draw a shape, no matter what it is
list[i].draw(); // Late binding
}
}
public static void printShapeDetails(Shape[] list) {
for (int i = 0; i < list.length; i++) {
// Gather details about the shape
String name = list[i].getName(); // Late Binding
double area = list[i].getArea(); // Late binding
double perimeter = list[i].getPerimeter(); // Late binding
 
Search WWH ::




Custom Search