Java dovoljuje, da razrede in metode proglasimo za abstraktne (
abstract
).
Za abstraktno metodo je značilno, da nima telesa. V razredu obstaja le njena deklaracija (prototip, najava), ne pa tudi njeno telo. Se pravi, da v definiciji razreda dejansko ne obstaja implementacija take metode. Primer abstraktne metode je podan spodaj:
public abstract void narisi();
Abstrakna metoda je vedno del abstraknega razreda (ali pa, kot bomo videli kasneje, del vmesnika).
Abstraktna metoda nima telesa.
Primerka abstraktnega razreda ni mogoče narediti.
Razlog za zgornji izjavi leži v naslednjem :
abstraktno lahko opišemo z neoprijemljivo, mogoče neobstoječe. Abstrakno je npr. nebo, abstraktni sta sreča in žalost. Vse te termine, stanja, lahko opisujemo, niso pa oprijemljivi. Enako velja npr. za lik. Neopredeljen lik ne more obstajati, lahko pa obstaja lik-kvadrat, saj je njegova oblika definirana (lahko ga narišemo oz. naredimo objekt) . Kvadrat je pri tem le eden izmed primerov lika.
V primeru, da razred vsebuje abstraktno metodo, je tudi sam abstrakten. Vsebuje namreč metodo (abstraktno), ki nima telesa. Če razred s tako metodo ne bi bil abstrakten, bi na njegovi osnovi lahko naredili primerek-objekt in klicali metodo tega objekta. Izvajanje metode se doseže tako, da se njen naslov vpiše v programski števec procesorja. Če metoda nima telesa, njen naslov ne more biti naslov (ustrezne, pravilne,..) izvajalne kode, tipično bi šlo v tem primeru za naključno vrednost ali vrednost 0. V vsakem primeru bi izvajanje 'ukazov' z naključne lokacije v pomnilniku povzročilo neželjeno (ne)delovanje programa, izvajalnega okolja oz. operacijskega sistema. Zato :
naredimo tako, da po dostopnem določilu navedemo besedico abstract :
public abstract class Lik {V primeru, da poskušamo narediti primerek tega razreda z npr.:
Lik mojLikec = new Lik();prevajalnik generira napako z opozorilom, da tega pač ne moremo narediti.
Primer abstraktnega razreda za lik :
public abstract class Lik{ int x,y; // celoštevilska pozicija lika v ravnini, //podana z odsekoma po x in y osi (x,y) public abstract void narisi(); // izrise lik s prijemališčem (x,y) v ravnini public void premakni(int dx, int dy){ x+=dx; y+=dy; } }
Lik definira trenutno pozicijo lika v ravnini, metodi za premik in izris lika. Dokler ne vemo, kakšen je lik, ki ga želimo izrisati, je vsakršna implementacija metode narisi nesmiselna.
Kakšna pa je potem korist od takega razreda, katerega primerka ne moremo zgraditi ?
Seveda objekta ne moremo narediti, ker metode narisi dejansko nimamo. Lahko pa iz razreda Lik izvedemo drug razred, npr. Kvadrat. Kvadrat s podano stranico osnovnice znamo izrisati oz. napisati metodo za njegov izris:
public class Kvadrat extends Lik{int a; // dolzina stranice kvadrata
public void narisi(){ // koda za izris kvadrata z atributi a,x,y } }
Kot vidimo iz zgornjega primera smo abstraktno metodo narisi() preobložili z običajno (ne-abstraktno) metodo narisi() znotraj izvedenega razreda Kvadrat. S tem smo metodo dejansko definirali (implementirali). Ker razred Kvadrat ne vsebuje nobene abstraktne metode več, tudi sam ni abstrakten. To pa pomeni, da lahko kadarkoli naredimo primerek tega razreda :
Kvadrat mojKvadratek = new Kvadrat();V primeru, da v razredu Kvadrat podedovane abstraktne metode ne bi implementirali, bi moral biti tudi razred Kvadrat abstrakten.
To pa pomeni, da nam abstraktni razredi lahko služijo kot predpis, katere izmed metod moramo znotraj izvedenega razreda realizirati.