Liigu peamise sisu juurde

Abstraktsed klassid

Sissejuhatus

Mõnikord esindab klass mõistet, mis on liiga üldine, et seda iseseisvalt instantseerida. Näiteks Shape võib kirjeldada mis tahes geomeetrilist kujundit, kuid abstraktset "kujundit" sellisena ei eksisteeri. Eksisteerivad ainult konkreetsed kujundid, nagu ringid, ristkülikud ja kolmnurgad.

Kõigil neil kujunditel on ühised omadused, näiteks pindala, kuid selle arvutamise viis sõltub konkreetsest kujundist.

Selliste olukordade jaoks pakub Java märksõna abstract, mis võimaldab defineerida abstraktseid klasse ja meetodeid. Abstraktne klass kirjeldab ühist struktuuri ja käitumist, kuid seda ei saa otse instantseerida. Selle asemel kasutatakse seda teiste, konkreetsemate klasside baasklassina.

abstract märksõna

Abstraktne klass on klass, mida ei saa otse instantseerida. Seda kasutatakse baasklassina, mida teised klassid saavad laiendada.

abstract class Shape {
// cannot create: new Shape() — compile error
}

Abstraktne meetod on meetod, millel puudub keha. See määrab meetodi signatuuri, kuid jätab selle teostuse alamklasside ülesandeks.

abstract class Shape {
public abstract double area(); // no body — subclasses must implement this
}

Iga klass, mis laiendab abstraktset klassi, peab teostama kõik selle abstraktsed meetodid. Kui klass ei teosta kõiki abstraktseid meetodeid, peab ta ise olema deklareeritud abstraktse klassina.

Praktiline näide

abstract class Shape {
private String color;

public Shape(String color) {
this.color = color;
}

public String getColor() {
return color;
}

// Every shape must be able to calculate its area,
// but the formula is different for each shape.
public abstract double area();

// A concrete method shared by all shapes.
public void describe() {
System.out.println(color + " shape with area " + area());
}
}

Alamklassid laiendavad Shape'i ja teostavad meetodit area():

class Circle extends Shape {
private double radius;

public Circle(String color, double radius) {
super(color);
this.radius = radius;
}

@Override
public double area() {
return Math.PI * radius * radius;
}
}

class Rectangle extends Shape {
private double width;
private double height;

public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}

@Override
public double area() {
return width * height;
}
}

See võimaldab kirjutada üldist koodi abstraktse tüübi (Shape) vastu, ilma et peaks teadma konkreetset alamklassi (Circle, Rectangle). Näiteks:

Shape[] shapes = {
new Circle("red", 5.0),
new Rectangle("blue", 4.0, 6.0)
};

for (Shape shape : shapes) {
shape.describe(); // works on all Shape subclasses
}

// red shape with area 78.53981633974483
// blue shape with area 24.0

Pane tähele, et describe() on defineeritud ainult üks kord abstraktses klassis Shape, kuid see kutsub välja meetodi area(), millel puudub seal teostus. Kui describe() käivitatakse näiteks Circle objektil:

Shape circle = new Circle("red", 5.0);
circle.describe();

siis Java kutsub automaatselt välja Circle klassis defineeritud area() meetodi, mitte Shape oma (sest Shape-il puudub selle teostus). Antud nähtusega peaksite juba tuttavad olema polümorfismi teemast.

Abstraktsete klasside reeglid

  • Abstraktset klassi ei saa instantseerida (new Shape() põhjustab kompileerimisvea).
  • Abstraktsel klassil võivad olla abstraktsed meetodid (ilma kehata, alamklassid peavad need teostama).
  • Abstraktsel klassil võivad olla konkreetsed meetodid (kehaga, need päritakse muutmata kujul).
  • Abstraktsel klassil võivad olla väljad ja konstruktorid (alamklasside konstruktorid kutsuvad neid super() kaudu).
  • Abstraktne klass võib sisaldada nii abstraktseid kui ka konkreetseid meetodeid samal ajal.
  • Kui alamklass ei teosta kõiki päritud abstraktseid meetodeid, peab ka see klass olema deklareeritud abstraktseks.
hoiatus

Levinud viga on jätta abstraktne meetod konkreetses alamklassis teostamata. Sellisel juhul annab kompilaator vea, mis näitab täpselt, milline meetod on puudu.

Millal kasutada abstraktseid klasse

Kasuta abstraktset klassi, kui:

  • Mitu omavahel seotud klassi jagavad ühiseid välju või konkreetset käitumist.
  • Soovid pakkuda osalist teostust, mida alamklassid saavad otse kasutada või vajadusel üle kirjutada.
  • Soovid sundida alamklasse teostama teatud meetodid (abstraktsed meetodid).
  • Soovid defineerida ühise baastüübi, mille kaudu saab käsitleda erinevaid alamklasse ühtselt (polümorfism).

Abstraktsed klassid sobivad hästi siis, kui klasside vahel on tõeline IS-A seos ning ühisel baasil on sisukas olek (väljad), jagatud loogika või mõlemad.