This page assumes that you have an understanding of interfaces and inheritance. Please review those pages first.
public abstract void draw();
Since there really isn't such a thing as a generic shape, we could rewrite our Shape class example from the inheritance page. Each particular type of shape (like a rectangle or a circle) will need to provide its own implementation of the draw(), erase(), and zoom(), so we declare them as abstract in the Shape class, and don't bother to create a dummy implementation.
import java.awt.Color; public abstract class Shape { private Color color; protected double xCoord; protected double yCoord; public Shape(){ color = Color.WHITE; xCoord = 0.0; yCoord = 0.0; System.out.println("Shape: constructor"); } public abstract void draw(); public abstract void erase(); public Color getColor(){ System.out.println("Shape: getColor"); return color; } public void move(){ xCoord += 2.0; yCoord += 2.0; System.out.println("Shape: move"); } public void setColor(Color color){ this.color = color; System.out.println("Shape: setColor"); } public abstract void zoom(double magnitude); }
Just as an interface is only useful if there exists a class that implements the interface, an abstract class is only useful if there is another class that extends it and implements all of the abstract methods.
Making the Shape class abstract does not require us to modify the Circle and Rectangle classes (except that we no longer call the Shape's erase() method within the subclass' erase() methods.
public class Circle extends Shape { private double radius; public Circle() { super(); radius = 0; System.out.println("Circle: constructor"); } public void draw(){ System.out.println("Circle: draw"); } public void erase(){ radius = 0; System.out.println("Circle: erase"); } public double getRadius(){ System.out.println("Circle: getRadius"); return radius; } public void setRadius(double radius){ this.radius = radius; System.out.println("Circle: setRadius"); } public void zoom(double magnitude){ radius *= magnitude; System.out.println("Circle: zoom"); } }
public class Rectangle extends Shape { protected double height; protected double width; public Rectangle(){ super(); height = 0.0; width = 0.0; System.out.println("Rectangle: constructor"); } public void draw(){ System.out.println("Rectangle: draw"); } public void erase(){ height = 0.0; width = 0.0; System.out.println("Rectangle: erase"); } public void zoom(double magnitude){ height *= magnitude; width *= magnitude; System.out.println("Rectangle: zoom"); } }
In order to understand the rationale behind abstract classes, let's rehash some rules regarding references…
Circle ref1;
Shape ref2;
List<Shape> ref3;
List<Shape> shapes = readShapes("shapeData.txt"); for(Shape shape : shapes) { shape.zoom(Math.random()*10.0); }