Abstract Classes
Tags: java, programming, learning, beginners
Published: 2024-06-17 16:10:14

An abstract class cannot be used to create objects. An abstract class can contain abstract methods, which are implemented in concrete subclasses. In the inheritance hierarchy, classes become more specific and concrete _with each new subclass_. If you move from a subclass back up to a superclass, the classes become more general and less specific. Class design should ensure that a superclass contains common features of its
subclasses. Sometimes a superclass is so abstract that it cannot be used to create any specific instances. Such a class is referred to as an _abstract class_.

[In this post](https://dev.to/paulike/inheritance-superclasses-and-subclasses-5ede), **GeometricObject** was defined as the superclass for **Circle** and **Rectangle**. **GeometricObject** models common features of geometric objects. Both **Circle** and **Rectangle** contain the **getArea()** and **getPerimeter()** methods for computing the area and perimeter of a circle and a rectangle. Since you can compute areas and perimeters for all geometric objects, it is better to define the **getArea()** and **getPerimeter()** methods in the **GeometricObject** class. However, these methods cannot be implemented in the **GeometricObject** class, because their implementation depends on the specific type of geometric object. Such methods are referred to as _abstract methods_ and are denoted using the **abstract** modifier in the method header. After you define the methods in **GeometricObject**, it becomes an abstract class. Abstract classes are denoted using the **abstract** modifier in the class header. In UML graphic notation, the names of abstract classes and their abstract methods are italicized, as shown in progeam below. The program gives the source code for the new **GeometricObject** class.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/15rg7k6j4uaos5m5m8ta.png)


```
package demo;

public abstract class GeometricObject {
	private String color = "white";
	private boolean filled;
	private java.util.Date dateCreated;
	
	/** Construct a default geometric object */
	protected GeometricObject() {
		dateCreated = new java.util.Date();
	}
	
	/** Construct a geometric object with color and filled value */
	protected GeometricObject(String color, boolean filled) {
		dateCreated = new java.util.Date();
		this.color = color;
		this.filled = filled;
	}
	
	/** Return color */
	public String getColor() {
		return color;
	}
	
	/** Set a new color */
	public void setColor(String color) {
		this.color = color;
	}
	
	/** Return filled. Since filled is boolean, the get method is named isFilled */
	public boolean isFilled() {
		return filled;
	}
	
	/** Set a new filled */
	public void setFilled(boolean filled) {
		this.filled = filled;
	}
	
	/** Get dateCreated */
	public java.util.Date getDateCreated(){
		return dateCreated;
	}
	
	@Override
	public String toString() {
		return "created on " + dateCreated + "\ncolor: " + color + " and filled: " + filled;
	}
	
	/** Abstract method getArea */
	public abstract double getArea();
	
	/** Abstract method getPerimeter */
	public abstract double getPerimeter();
}

```

Abstract classes are like regular classes, but you cannot create instances of abstract classes using the **new** operator. An abstract method is defined without implementation. Its implementation is provided by the subclasses. A class that contains abstract methods must be defined as abstract.

The constructor in the abstract class is defined as protected, because it is used only by subclasses. When you create an instance of a concrete subclass, its superclass’s constructor is invoked to initialize data fields defined in the superclass.

The **GeometricObject** abstract class defines the common features (data and methods) for geometric objects and provides appropriate constructors. Because you don’t know how to compute areas and perimeters of geometric objects, **getArea()** and **getPerimeter()** are defined as abstract methods. These methods are implemented in the subclasses. The implementation of **Circle** and **Rectangle** is the same as in the programs below, except that they extend the **GeometricObject** class defined.

```
package demo;

public class Circle extends GeometricObject {
private double radius;
	
	public Circle() {}
	
	public Circle(double radius) {
		this.radius = radius;
	}
	
	public Circle(double radius, String color, boolean filled) {
		this.radius = radius;
		setColor(color);
		setFilled(filled);
	}
	
	/** Return radius */
	public double getRadius() {
		return radius;
	}
	
	/** Set a new radius */
	public void setRadius(double radius) {
		this.radius = radius;
	}
	
	/** Return area */
	public double getArea() {
		return radius * radius * Math.PI;
	}
	
	/** Return diameter */
	public double getDiameter() {
		return 2 * radius;
	}
	
	/** Return perimeter */
	public double getPerimeter() {
		return 2 * radius * Math.PI;
	}
	
	/** Print the circle info */
	public void printCircle() {
		System.out.println("The circle is created " + getDateCreated() + " and the radius is " + radius);
	}
}

```


```
package demo;

public class Rectangle extends GeometricObject {
	private double width;
	private double height;
	
	public Rectangle() {}
	
	public Rectangle(double width, double height) {
		this.width = width;
		this.height = height;
	}
	
	public Rectangle(double width, double height, String color, boolean filled) {
		this.width = width;
		this.height = height;
		setColor(color);
		setFilled(filled);
	}
	
	/** Return width */
	public double getWidth() {
		return width;
	}
	
	/** Set a new width */
	public void setWidth(double width) {
		this.width = width;
	}
	
	/** Return height */
	public double height() {
		return height;
	}
	
	/** Set a new height */
	public void setHeight(double height) {
		this.height = height;
	}
	
	/** Return area */
	public double getArea() {
		return width * height;
	}
	
	/** Return perimeter */
	public double getPerimeter() {
		return 2 * (width + height);
	}
}

```

## Why Abstract Methods?

You may be wondering what advantage is gained by defining the methods **getArea()** and **getPerimeter()** as abstract in the **GeometricObject** class. The example in Listing 13.4 shows the benefits of defining them in the **GeometricObject** class. The program creates two geometric objects, a circle and a rectangle, invokes the **equalArea** method to check whether they have equal areas, and invokes the **displayGeometricObject** method to display them.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4l8elebz8r2nt5hvuvka.png)

The methods **getArea()** and **getPerimeter()** defined in the **GeometricObject** class are overridden in the **Circle** class and the **Rectangle** class. The statements (lines 7–8)

`GeometricObject geoObject1 = new Circle(5);
GeometricObject geoObject2 = new Rectangle(5, 3);`

create a new circle and rectangle and assign them to the variables **geoObject1** and **geoObject2**. These two variables are of the **GeometricObject** type.

When invoking **equalArea(geoObject1, geoObject2)** (line 10), the **getArea()** method defined in the **Circle** class is used for **object1.getArea()**, since **geoObject1** is a circle, and the **getArea()** method defined in the **Rectangle** class is used for **object2.getArea()**, since **geoObject2** is a rectangle.

Similarly, when invoking **displayGeometricObject(geoObject1)** (line 13), the methods **getArea()** and **getPerimeter()** defined in the Circle class are used, and when invoking **displayGeometricObject(geoObject2)** (line 16), the methods **getArea** and **getPerimeter** defined in the **Rectangle** class are used. The JVM dynamically determines which of these methods to invoke at runtime, depending on the actual object that invokes the method.

Note that you could not define the **equalArea** method for comparing whether two geometric objects have the same area if the **getArea** method were not defined in **GeometricObject**. Now you have seen the benefits of defining the abstract methods in **GeometricObject**.

##  Interesting Points about Abstract Classes

The following points about abstract classes are worth noting:

- An abstract method cannot be contained in a nonabstract class. If a subclass of an abstract superclass does not implement all the abstract methods, the subclass must be defined as abstract. In other words, in a nonabstract subclass extended from an abstract class, all the abstract methods must be implemented. Also note that abstract methods are nonstatic.
- An abstract class cannot be instantiated using the **new** operator, but you can still define its constructors, which are invoked in the constructors of its subclasses. For instance, the constructors of **GeometricObject** are invoked in the **Circle** class and the **Rectangle** class.
- A class that contains abstract methods must be abstract. However, it is possible to define an abstract class that doesn’t contain any abstract methods. In this case, you cannot create instances of the class using the **new** operator. This class is used as a base class for defining subclasses.
- A subclass can override a method from its superclass to define it as abstract. This is very _unusual_, but it is useful when the implementation of the method in the superclass becomes invalid in the subclass. In this case, the subclass must be defined as abstract.
- A subclass can be abstract even if its superclass is concrete. For example, the **Object** class is concrete, but its subclasses, such as **GeometricObject**, may be abstract.
- You cannot create an instance from an abstract class using the _new_ operator, but an abstract class can be used as a data type. Therefore, the following statement, which creates an array whose elements are of the **GeometricObject** type, is correct.

`GeometricObject[] objects = new GeometricObject[10];`

You can then create an instance of **GeometricObject** and assign its reference to the array like this:

`objects[0] = new Circle();`