Abstract classes. Abstract methods. Keyword abstract. Examples

Abstract classes. Abstract methods. Keyword abstract. Examples


Contents



 1. What is an abstract class? Purpose of abstract classes. The general form of an abstract class declaration. Keyword abstract

An abstract class is a class that contains methods that have no implementation. An abstract class is created to create a common interface between different implementations of classes that are derived from an abstract class. An abstract class is created to define some common features of its derived classes.

It is forbidden (it makes no sense) to create an object of an abstract class.

A class is considered abstract if at least one abstract method is declared in the class. Before declaring an abstract class, the abstract keyword is placed.

The general form of the abstract class declaration is as follows:

abstract class ClassName {
    // class methods and variables
    ...
    abstract type AbstractMethod1(parameters1);
    abstract type AbstractMethod2(parameters2);
    ...
    abstract type AbstractMethodN(parametersN);
}

here

  • ClassName – the name of the abstract class that is declared;
  • AbstractMethod1, AbstractMethod2, AbstractMethodN – names of abstract methods declared in an abstract class;
  • type – some type;
  • parameters1, parameters2, parametersN – the list of parameters that receive the corresponding abstract methods with the names AbstractMethod1, AbstractMethod2, AbstractMethodN.

 

2. What is an abstract method? General form

Abstract method – a method whose implementation in the program does not make any sense. The abstract method is only a declaration of a form (interface) and not an implementation. As with the abstract class, the abstract method starts from the abstract keyword.

If an abstract method is declared in a class, then the class is also considered abstract. In this case, the abstract keyword is also placed before the class name.

If a certain class is inherited from an abstract class, then this class must override all abstract methods of the base abstract class. Otherwise, an error will be generated.

The general form for declaring an abstract method in an abstract class is as follows:

abstract class ClassName {
    // ...
    type AbstractMethod(parameters);
}

here

  • ClassName – the name of an abstract class that contains an abstract method called AbstractMethod;
  • AbstractMethod – the name of an abstract method that returns a value of specified type and receives parameters.

In the class inheritance hierarchy (extensions), abstract methods are something common. Specific implementations of abstract methods are placed on classes inherited from abstract classes.

 

3. A schematic representation of the declaration and use of an abstract method in an abstract class. Example

The diagram shows a simple example of declaring an abstract class called AbstractClass. This class contains an abstract method declaration named ShareMethod().

From the abstract class AbstractClass two classes are inherited with the names Class1, Class2. These classes implement the ShareMethod() method, which is declared in the AbstractClass class as abstract.

Java scheme interaction abstract class derived classes

Figure. The scheme of interaction between the abstract class and derived classes in Java

 

4. An example that demonstrates the use of abstract classes

The example declares an abstract class Figure, describing general information about a certain geometric figure on a plane. From the class Figure two classes are inherited (Triangle and Circle), which override the abstract methods of the class Figure.

In the class Figure are declared:

  • hidden (protected) property name, which defines the name of a geometric figure;
  • hidden (protected) constant pi;
  • abstract method ShowName(), which displays the name of the figure;
  • abstract method Area(), which calculates the area of the figure;
  • method that returns the name of the figure (the value of the name field).
// abstract class that describes some geometric figure
abstract class Figure {
    protected String name = ""; // the name of figure
    protected double pi = 3.1415; // constant Pi

    // abstract methods that will be redefined in derived classes
    abstract void ShowName(); // display the name of the figure
    abstract double Area(); // the calculation of area

    // method that returns the name of the figure
    String GetName() {
        return name;
    }
}

Two classes with the names of Triangle and Circle also implemented. These classes inherit (extend) the class Figure.

In the class Triangle() are implemented:

  • internal variables a, b, c, which are sides of a triangle;
  • class constructor;
  • the ShowName() method, which overrides the abstract ShowName() method of the Figure class. This method displays the class name “Triangle”;
  • the Area() method, which overrides the abstract Area() method from the Figure class. The method calculates the area of a triangle.
// a class that implements the triangle
class Triangle extends Figure {
    double a, b, c; // sides of a triangle

    // constructor
    Triangle(double a, double b, double c) {
        name = "Triangle";
        this.a = a;
        this.b = b;
        this.c = c;
    }

    // override abstract method ShowName()
    void ShowName() {
        System.out.println("Triangle");
    }

    // override abstract method Area()
    // area of a triangle
    double Area() {
        // check whether it is possible to form a triangle from distances a, b, c
        if (((a+b)<c) || ((b+c)<a) || ((a+c)<b))
            return 0.0;
        double p = (a+b+c)/2; // semiperimeter
        double s;

        // Heron's formula
        s = Math.sqrt(p*(p-a)*(p-b)*(p-c));
        return s;
    }
}

The Circle class implements a circle that belongs to geometric shapes. Therefore, the Circle class inherits (extends) the Figure class. In the class Circle are implemented:

  • internal variable r, defining the radius of a circle;
  • constructor;
  • the Area() method, redefining the same-named abstract method of the Figure class. The method calculates the area of a circle;
  • the method ShowName(), which overrides the abstract method of the same name of the class Figure. The method displays the class name “Circle”.
// a class that implements a circle inherits a class Figure
class Circle extends Figure {
    double r;

    // constructor
    Circle(double r) {
        name = "Circle";
        this.r = r;
    }

    // override abstract method Area()
    double Area() {
        return pi*r*r;
    }

    // override abstract method ShowName()
    void ShowName() {
        System.out.println("Circle");
    }
}

In order to demonstrate the use of abstract classes, an additional class is created called UseAbstractClass. This class implements:

  • GetName() method that returns the name of the instance f, which is passed as an input parameter. The parameter f is a reference to the class Figure;
  • GetName() method that returns the name of the instance f, which is passed as an input parameter. The parameter f is a reference to the class Figure;
  • method GetArea(), which returns the area of the instance f of the class Figure. An instance (object) f of class is an input parameter of the method. This method clearly demonstrates the so-called late binding, the essence of which is described below;
  • static method main(), which is the entry point to the program. This method implements the demonstration of the abstract class Figure.
// class that uses the abstract class Figure
public class UseAbstractClass {
    // method that receives reference to base class
    static String GetName(Figure f) {
        return f.GetName(); // invoke the method to base class
    }

    // method that returns the area of the figure, f - reference to the base class
    // late binding is used,
    // the method for calculating the area is determined based on the value of f
    static double GetArea(Figure f) {
        return f.Area(); // invoke the area calculation method
    }

    public static void main(String[] args) {
        // Demonstration of using the Area() and ShowName() abstract methods
        Figure f1 = new Triangle(3.5, 1.8, 2.2); // an instance of the Triangle class
        Figure f2 = new Circle(3.0); // instance of the Circle class
        double area;

        // display the names of the instances f1, f2
        f1.ShowName(); // Triangle
        f2.ShowName(); // Circle

        String name;
        name = GetName(f1); // name = "Triangle"
        System.out.println(name);

        name = GetName(f2); // name = "Circle"
        System.out.println(name);

        // calculating the area for a triangle
        // implementation of late binding
        area = GetArea(f1); // area = 1.6833281765597579
        System.out.println("area = " + area);

        // calculating the area of a circle
        // implementation of late binding
        area = GetArea(f2); // area = 28.2735
        System.out.println("area = " + area);
    }
}

As a result of the use of the function main() of class UseAbstractClass, the following result will be displayed:

Triangle
Circle
Triangle
Circle
area = 1.6833281765597579
area = 28.2735

 

5. Explanation to the example of paragraph 4

Explanation of an example (see previous paragraph) in the form of questions.

5.1. Why are the Area() and ShowName() methods are declared abstract in the Figure class?

The class Figure is a generalization of a geometric figure. This class defines the general properties of the whole variety of geometric shapes. Specific shapes (triangle, circle) extend (extends) the capabilities of the class Figure or, in other words, inherit the class Figure. In our case, the triangle (class Triangle) and the circle (class Circle) are chosen as concrete figures.

In the Figure class, the Area() method is declared as abstract, since it is impossible to determine the area of a generalized figure, since it is not yet known what figure it is (triangle or circle). For a triangle (class Triangle) the area is determined by the Heron’s formula. For a circle, the area is determined by the standard formula S = π·R2.

From here we can conclude: it makes no sense to call the Area() method from the base class Figure. This method is declared only for organizing a hierarchical call to the Area() methods, which calculate the areas of shapes of specific implementations of the classes derived from the Figure class.

In our case, these derived classes are the Triangle and Circle classes.

 

5.2. Why Figure class is declared as abstract?

If a class contains at least one abstract method, then this class is considered as abstract. The Figure class contains two abstract methods, so the abstract keyword is placed before the class declaration.

 

5.3. Why in the class Figure methods Area() and ShowName() do not contain the implementation code (method body)?

If the method is declared abstract in the abstract class (with the abstract keyword), then this method should not contain implementations (according to Java syntax). This is explained by the fact that calling this method does not make sense.

 

5.4. Is it possible to add other non-abstract methods in the abstract Figure class?

Yes, it is. An abstract class may contain non-abstract methods (as opposed to an interface).

 

5.5. Is it possible to create an instance of the Figure class in the main() function of the UseAbstractClass class?

No, it is not. That is, the following line

Figure f3 = new Figure();

is a Java compiler error: “Cannot instantiate the type Figure”.

However, it is possible to declare a reference to the class Figure. Since the Figure class is basic for the Triangle and Circle classes, using this link, you can create instances of classes derived from Figure. The following code demonstrates the use of the reference to the base class Figure:

// base class reference declaration
Figure f3;

// creating an instance of the class Circle, derived from Figure
f3 = new Circle(2.5);

// invoke the class method Circle
f3.ShowName();

 

5.6. What is the essence of late binding in the GetArea() method of the class UseAbstractClass?

The GetArea() method gets a link with the name f of the abstract class Figure, which is the base class hierarchy (two classes, Triangle and Circle, are inherited from the Figure class).

static double GetArea(Figure f) {
    return f.Area(); // invoke the area calculation method
}

Then the Area() method in the string is called by reference.

...
return f.Area();
...

At the time of compiling of the GetArea() method, it is impossible to say which instance of a class (Triangle or Circle) will be passed to the method. So you can’t say which Area() method will be called. Therefore, a reference to the base class Figure is passed to the method.

In the main() function when calling the GetArea() method

...
Figure f1 = new Triangle(3.5, 1.8, 2.2); // the instance of class Triangle
Figure f2 = new Circle(3.0); // the instance of class Circle
...
// calculating the area for a triangle
// implementation of late binding
area = GetArea(f1); // the instance of the Triangle class is passed.
...
area = GetArea(f2); // the istance of Circle class is passed
...

various references (f1, f2) are passed to this method which are instances of classes derived from the class Figure. These references are instances of the Triangle and Circle classes.

In the first case

area = GetArea(f1);

inside the GetArea() method, the compiler assigns to the reference f the value of the link f1, which points to the class that contains the Area() method of the Triangle class.

Thus, the binding of the generalized reference f to the class Triangle occurs due to the inheritance hierarchy. This binding is called late binding. Details of late binding – this is another topic.

In exactly the same way, an instance of f2 of the Circle class is associated with a generalized reference f in the GetArea() method

area = GetArea(f2);

 

6. Is it possible to declare in an abstract class some non-abstract methods, that have a (body) implementation?

Yes, it is. The abstract class allows the implementation of non-abstract methods.

 

7. An example of creating a hierarchy of abstract classes

If a class derived from an abstract is declared, and in this class there is no implementation of abstract methods, then this class is automatically considered as abstract. You must specify abstract before the name of this class, otherwise the compiler will generate an error.

Example. Below is an example of a hierarchy of abstract classes.

// abstract class hierarchy
abstract class A {
    abstract void Show();
}

// Class B has no implementation of the abstract Show() method from Class A,
// so this class is also abstract
abstract class B extends A {
    abstract void Show(); // no implementation
}

// in class C, an abstract method Show() of classes A, B is implemented
class C extends B {
    // implementation of method Show()
    void Show() {
        System.out.println("Class C");
    }
}

As you can see from the example, in class B, the abstract Show() method is inherited, which has no implementation. Therefore, you must specify the abstract keyword before declaration a class B.

Using class C may be, for example, the following

A obj = new C(); // reference to base class A
obj.Show(); //
C obj2 = new C(); // reference to class C
objC2.Show();

 

8. Can an abstract class does not contain abstract methods?

Yes, it can. This is necessary in cases where abstract methods in the class are not needed, but the creation of instances of this class must be prohibited.

 

9. What are the differences between using abstract classes and using interfaces?

The following differences exist between abstract classes and interfaces:

  • abstract classes can contain implementations of methods, interfaces cannot;
  • in interfaces, all the methods that are declared are abstract. In abstract classes, you can declare both abstract and non-abstract methods;
  • variables that are declared in interfaces must be initialized. In abstract classes, internal variables can be not initialized;
  • in interfaces, all declared variables are implicitly considered as constants (declared with the keywords final, static). In abstract classes, declared variables are not considered as constants.

 

10. The advantages of using abstract classes

Using abstract classes provides the following benefits:

  • using the abstract keyword before declaring a class emphasizes the abstractness of this class. This, in turn, tells the developer how to use this class;
  • abstract classes are useful when reworking programs. With the help of abstract classes, you can easily “move” general methods up the hierarchy.

 


Related topics