You are on page 1of 13

Leksion 07

Java
Trashegimia dhe Nderfaqet
Trashegimia eshte nje mekanizem per te zhvilluar klasat ekzistuese. Nese kemi
nevoje per te implementuar nje klase te re dhe nje klase qe perfaqeson nje concept
me te pergjithshem eshte tashme e disponueshme, atehere klasa e re mund te
trashegoje nga klasa ekzistuese, cdo gje te parapercaktuar duke e mosdeklaruar dy
here apo duke e mbishkruar per nevoja me specifike. Per shembull, Supozojme se
na duhet te percaktojme nje klase me emrin SavingsAccount (LlogariKursimesh), per
te modeluar njellogari qe paguan nje interes fiksmbi depozitat. Ju tashme e keni
llogarine BankAccount dhe nje llogari kursimesh seshte gje tjeter vecse nje lloj
llogarie BankAccount, e vecante! Ne raste te tilla, ben sens qe te perdorim si
konstrukt gjuhe trashegimine. Ja sintaksa per percaktimin e klases ne kete menyre:

class SavingsAccount extends BankAccount


{
new methods
new instance variables
}

Ne percaktimin e klases Savings Account ju specifikoni vetem metoda te reja dhe


variabla instance. Gjithe metodat dhe variablat e instances se klases bankAccount ,
automatikisht trashegohen nga klasa SavingsAccount.Per shembull, metoda deposit
automatikisht I aplikohet llogarive te kursimit:
SavingsAccount collegeFund = new SavingsAccount(10);
collegeFund.deposit(500);

// OK to use BankAccount method with SavingsAccount object

Na duhet te percaktojme edhe disa terminologji te tjera. Klasa me e pergjithshme


qe formon bazen e trashegimise quhet superclass. Kurse klasa me e specializuar
quhet subclass. Ne shembullin tone, BankAccount eshte superclass kurse
SavingsAccount eshte subclass.

Ne Java, cdo klase qe nuk trashegon specifikisht nga nje klase tjeter, atehere kjo
eshte automatikisht nje subclass e klases Object. Klasa Object ka nje numer me te
vogel metodash qe kane kuptim ti aplikohen te gjitha klasave ne Java, si per
shembull: toString() qe ju mund te perdorni per te marre nje string qe pershkruan
gjendjene e objektit.
Figura me poshte eshte nje diagrame klase qe tregon
lidhjet mes tre klasave: Object, BankAccount dhe
SavingsAccount.

Figura e paraqitur nuk eshte nje vizatim I thjeshte por nje


modelim I ralacioneve mes klasash, qe ndjek simbolet e
nje gjuhe modelimi.

Nje arsye tjeter per te perdorur trashegimine eshte


riperdorimi I kodit! Duke trasheguar nga nje klase
ekzistuese, ju nuk keni pse te replikoni perpjekjen qe u
dha ne dizenjimin dhe perfeksionimin e klases. Per
shembull, kur implementojme klasen SavingsAccount, ne
mund te mbeshtetemi mbi metodat: withdraw, deposit dhe
getbalance te klases BankAccount pa I prekur ato.

Le te shohim se ne cmenyre objektet ton ate llogarive te


kursimit dallojne nga objektet BankAccount. Pra pervec tre
metodave qe mund ti aplikohen cdo llogarie, kemi edhe
nje metode shtese addInterest. Keto metoda te reja dhe
variabla instance duhet te specifikohenne subclass(ose
nenklase!).

Copez kodi:
public class SavingsAccount extends BankAccount
{ public SavingsAccount(double rate)
{ constructor implementation
}
public void addInterest()
{ method implementation
}
private double interestRate;

Figura 2 tregon layout-in e objektit SavingsAccount. Ajo trashegon variablin e


instances balance nga superklasa BankAccount dhe fiton nje variabel shtese
instance: interesin apo interestRate;

Me tej, ju duhet te implementoni metoden addInterest. Kjo metode llogarit interesin


ne baze sipas balances korrekte dhe depoziton interesin llogarise.

Copez kodi:
public class SavingsAccount extends BankAccount
{ public SavingsAccount(double rate)
{ interestRate = rate;
}

Sintaksa ne Java:
class SubclassName extends SuperclassName
{ methods
instance variables
}
Example:
public class SavingsAccount extends BankAccount
{ public SavingsAccount(double rate)
{ interestRate = rate;
}
public void addInterest()
{ double interest = getBalance() * interestRate / 100;
deposit(interest);
}
private double interestRate;
}
Qellimi: te percaktojme nje klase te re qe trashegon nga klasa ekzistuese dhe te
percaktojme metodat dhe variablat e instances qe I shtohen klases se re.

Ne menyre figurative le te kuptojme se kush eshte porcioni qe ze superklasa ne nje


objekt SavingsAccount:

Copez kodi:
public void addInterest()
{ double interest = getBalance() * interestRate / 100;
deposit(interest);
}
private double interestRate;

Vini re se si metoda addInterest() therret metodat getBalance dhe deposit te


superklases. Per shkak se asnje objekt nuk specifikohet per thirrjet ndaj getBalance
dhe deposit(), thirrjet Iu aplikohen parametrave implicite te metodes addInterest.
Me fjale te tjera, ekzekutohen deklarimet me poshte:
double interest = this.getBalance() * this.interestRate / 100;

this.deposit(interest);

Per shembull, nese thirrim collegeFund.addinterest(); atehere ekzekutohen keto


instruksione:
double interest = collegeFund.getBalance() *collegeFund.interestRate / 100;

collegeFund.deposit(interest);

Gabime te zkonshme dhe konfuzione

Nese ju krahasoni nje objekt te tipit SavingsAccount me nje objekt te tipit


BankAccount, atehere shohim se:

1. Fjalakyce extends, sygjeron qe objekti SavingsAccount eshte nje version I


zgjeruar I BankAccount.
2. Objekti Savings Account eshte me I gjere, me i madh; ka nje variabel
instance shtese: interestRate.
3. Objekti SavingsAccount eshte me I afte: ka nje metode shtese me emrin
addInterest().

Duket nje objekt superior ne cdo menyre. Atehere pse Savings Account thirret
nenklase dhe BankAccount nje superklase?! Super/sub si terminologji vjen nga
teoria e bashkesive. Nese shohim bashkesine e gjithe llogarive bankare disa prej
tyre jane llogari bankare e te tjera jane objekte SavingsAccount dhe bashkesia e
objekteve SavingsAccount eshte nje nenbashkesi e bashkesive te gjithe objekteve
BankAccount.

Objektet me te specializuar ne nenbashkesi kane gjendje me te pasur dhe me


shume aftesi.

Konvertimi mes tipeve te klasave


Klasa SavingAccount trashegon nga klasa BankAccount. Me fjale te tjera, nje objekt
SavingsAccount eshte nje rast special I objektit BankAccount. Ndaj, ne mund te
ruajme nje reference mbi objektin SavingsAccount ne nje variabel objekt te tipit
BankAccount.

Copez kodi:
SavingsAccount collegeFund = new SavingsAccount(10);
BankAccount anAccount = collegeFund;

Object anObject = collegeFund;

Tani, tre referencat e objekteve te ruajtura ne collegeFund,anAccount dhe anObject


te gjithe I referohen te njejtit objekt te tipit SavingsAccount, figura:
Sidoqofte, variabli objekt anAccount di me pak sesa e gjithe permbajtja e objektit
te cilit I referohet. Per shkak se anAccount eshte nje objekt I tipit BankAccount, ju
mund teperdorni metodat withdraw dhe deposit per te ndryshuar balancen e
llogarive te kursimit.

Kujdes!

Ne nje situate te tille deklarimesh duhet te dime se nga nje reference e tille, nuk
mund te perdorim metoden addInterest, megjithese eshte nuk eshte nje metode e
superklases BankAccount:
anAccount.deposit(1000); // OK
anAccount.addInterest();

// Nojo metode e klases se ciles anAccount I takon.

Dhe sigurisht variabli anObject di me pak! Ne mundet edhe tI aplikojme atij


metoden deposit(deposit nuk eshte metode e klases Object).

Perse dikush do te donte te dinte me pak per nje objekt dhe te ruante nje reference
ne nje variabel objektte superklases? Kjo mund te ndodhe nese doni te riperdorni
kodin qe di per superklasen por jo nenklasen.

Ja nje shembull tipik. Le te konsiderojme metoden transfer e cila transferon para


nga nje llogari ne tjetren. Kodi:
void transfer(BankAccount other, double amount)
{ withdraw(amount);
other.deposit(amount);

Ne mund te perdorim kete metode per te transferuar para nga nje llogari thame, tek
tjetra:
BankAccount momsChecking = . . . ;
BankAccount harrysChecking = . . . ;

momsChecking.transfer(harrysChecking, 1000);

Ju mundet

Ju mundet po ashtu te transferoni para drejt nje tipi llogarie SavingsAccount:


SavingsAccount collegeFund = . . . ;
momsChecking.transfer(collegeFund, 1000);
// OK to pass a SavingsAccount reference to a

// method expecting a BankAccount

Metoda transfer() pret nje reference mbi nje obnjekt BankAccount, dhe merr nje
reference mbi nenklase SavingsAccount. Fatmiresisht, ne vend qe te ankohet
kompilatori per mosperputhje tipesh, kompilatori thjesht kopjon referencen e
nenklases collegeFund drejt references se superklases(emri I references other).
Metoda transfer() nuk e di aktualisht kete, Ne kete rast, other I referohet nje
reference Savings Account. Di vetem se other eshte nje BankAccount dhe nuk ka
perse te dije me teper! Ajo per te cilen ai duhet te kujdeset, eshte qe objekti other
mund te trajtoje metoden tone deposit().

Sidoqofte, nderkohe qe ju mund te konvertoni nje reference objekti ne nje reference


superklase, ju nuk mund te konvertoni mes klasash pa relacione apo lidhje mes tyre.
Ja nje gabim:

Rectangle r = collegeFund; // Errorklase pa lidhje me klasen Rectangle

Kompilatori e di qe Rectangle nuk eshte superklase e SavingsAccount dhe refuzon


te kompiloje kete deklarim!

Ndonjehere, ndodh qe kur konvertoni nje objekt ne nje reference superklase na


duhet ta rikthejme pastaj prapsh. Supozojme se kemi nje reference mbi nje llogari
kursimesh ne nje variabel te tipit Object:
Object anObject = collegeFund;

Me vone, duam te shtojme interes llogarise, por nuk kemi me akses mbi variablin
original objekt. Eshte e mundur qe ti caktohet nje reference supertipi , nje reference
nentipi! Sidoqofte, nese jemi te sigurte se nje objekt I referohet nje objekti
SavingsAccount, ne mund te perdorim operatorin cast per ta ri-konvertuar prapsh!

Kodi:

SavingsAccount aSavingsAccount = (SavingsAccount)anObject;

Ne rast gabimi programi do te leshoje nje perjashtim dhe do te perfundoje.

Qe kjo te mos ndodhe Java ofron nje operator me emrin instanceOf per te testuar
nese objekti I perket nje klase te vecante. Per shembull:

anObject instanceof SavingsAccount

Kthen true nese tipi I anObject eshte SavingsAccount dhe false ne rast te kundert.
Ndaj eshte e sigurte tem und te programojme si me tej:
SavingsAccount aSavingsAccount;
if (anObject instanceof SavingsAccount)
aSavingsAccount = (SavingsAccount)anObject;
else
aSavingsAccount = null;

Hierarkite e Trashegimise
Ne boten reale ne shpesh perpiqemi te kategorizojme konceptet ne hierarki.
Hierarkite perfaqesohen me shpesh si peme, me konceptin me te pergjithshem ne
rrenje te pemes dhe konceptet me te specializuar ne deget me poshte te
pemes.

Ja nje figure qe tregon pjese te nderfaqeve te perdoruesit te komponenteve Swing


ne Java.
Shtese

Ja hierarkia e deritanishme e klasave te shembullit te llogarive bankare.


Te trasheguarit e variablave te instances dhe metodave
Thame qe kur krijojme nje nenklase ten je klase te caktuar, ne specifikojme edhe
variabla e metoda shtese. Le te shohim fillimisht metodat. Kur percaktojme metodat
kemi tre mundesi:

1. Mund te mbishkruajme (ovrride) metodat e superklases. Nese specifikojme


nje metode me te njejten firme pra me te njejtin emer, me te njejtat
parametra, kjo e fundit mbishkruan metoden me te njejtin emer ne
superklase. Ne terma kodi:

CheckingAccount.deposit mbishkruan BankAccount.deposit.

2. Mund te trashegojme metoda te superklases. Nese nuk mbishkruani ne


menyre eksplicite nje metode te superklases, ju automatikisht e trashegoni
ate. Metoda e superklases mund tI aplikohet objekteve te nenklases.
Shembull: CheckingAccount trashegon metoden BankAccount.getBalance
3. Mund te percaktojme metoda te reja. Nese ne percaktojme nje metode qe
nuk ekzistonte ne superklase atehere metoda e re I aplikohet vetem
objekteve te nenklases

Situata per variablat e instances eshte pak ndryshe.

1. Mund te trashogojme variabla nga superklasa. Gjithe variablat e instances


nga superklasa trashegohen automatikisht.
2. Mund te percaktojme variabla te rinj. Cfaredo variabli instance qe ne
percaktojme ne nenklase jane vetem prezente ne objektet e nenklsases.

Por cfare ndodh kur percaktojme nje variabel me te njejtin emer si ne superklase?!
Per shembull cfare ndodh nese ne perccaktojme nje variabel tjeter me emrin
balance ne klasen SavingsAccount? Ne kete rast cdo objekt SavingsAccount ka dy
variabla instance me te njejtin emer. Variabli I ri I percaktuar hijezon variablin e
superklases. Pra variabli I superklases eshte akoma present por nuk mund te
aksesohet. Sa here qe ne I referohemi metodes balance ne SavingsAccount ne
aksesojme variablin e ri te instances. Sigurisht nese variabli I instances se
superklases eshte privat (dhe keshtu duhet te jene te gjithe, metodat e nenklases
nuk jane te afta ti aksesojne ato variabla. Hijezimi I variablave te instances nuk
eshte I demshem por mund te jete burim konfuzioni!

Tashme kemi implementuar klasat: BankAccount dhe Savings Account. Tanile te


implementojme nenklasen CheckingAccount qe te shohim me detaje se si
trashegohen metodat dhe variablat e instances. Kujtojme klasen BankAccount qe ka
tre metoda dhe nje variabel instance:

Ja nje skelet fillestar:


public class BankAccount
{ public double getBalance() { . . . }
public void deposit(double d) { . . . }

public void withdraw(double d) { . . . }


private double balance;

Klasa CheckingAccount ka nje metode deductFees dhe nje variabel instance


transactionCount dhe mbi shkruan metodt deposit dhe withdraw per te rritur numrin
e transaksioneve:
public class CheckingAccount extends BankAccount
{ public void deposit(double d) { . . . }
public void withdraw(double d) { . . . }
public void deductFees() { . . . }
private int transactionCount;

Cdo objekt I klases CheckingAccount ka dy variabla instance:


Balance(e trasheguar nga BankAccount), por edhe transactionCount(I ri per klasen
CheckingAccount).

Ne mund te aplikojme kater metoda mbi objektet CheckingAccount:

getbalance() e trasheguarnga klasa BankAccount

deposit(double) mbishkruan metoden e BankAccount

withdraw(double) mbishkruan metoden BankAccount

deductFees() variabel I ri per klasen CheckingAccount

Me tej le te implementojme keto metoda. Metoda deposit rrit numrin e


transaksioneve dhe depoziton parate:
public class CheckingAccount extends BankAccount
{ public void deposit(double amount)
{ transactionCount++;
// now add amount to balance
...
}
...

Ne kete pike kemi nje problem. Ne nuk mundemi thjesht tI shtojme amount-in si
vlere variablit balance:
public class CheckingAccount extends BankAccount
{ public void deposit(double amount)
{ transactionCount++;
// now add amount to balance
balance = balance + amount; // ERROR
}
...

Megjithese cdo objet CheckingAccount ka nje variabel instance balance, ai


variabel instance eshte privat per superklasen BankAccount. Metodat e nenklases
nuk kane me akses ne te dhenat private te superklase sesa cilado metode tjeter.
Nese ju doni te modifikoni nje variabel privat superklase, duhet te perdorim nje
metode publike te superklases, si cdo tjeter.

Si mund te shtojme amount-in per depozitim balances, perdorimi I nderfaqes


publike te klases BankAccount?

Kemi nje metode te mire per kete qellim, metoden deposit te klases BankAccount.
Atehere duhet te thirrim metoden deposit mbi ndonje objekt- pra parametric
implicit I metodes deposit te klases CheckingAccount. Si e pame ne leksionet me
pare, per te thirrur nje metode tjeter mbi parametrin implicit, nuk specifikojme
parameter por vetem shkruajme emrin e metodes:
public class CheckingAccount extends BankAccount
{ public void deposit(double amount)
{ transactionCount++;
// now add amount to balance
deposit(amount); // not complete
}
...

Por kjo nuk do te ece sepse kompilatori e interpreton si me poshte:

deposit(amount)

si

this.deposit(amount)

parametric this eshte I tipit CheckingAccount. Kemi nje metode te quajtur deposit
ne klasen CheckingAccount. Prandaj eshte kjo ajo metode qe do thirret- por kjo
eshte vetem metoda qe po whkruajme aktualisht! Kjo metode do therrase veten
gjithe Kohen dhe programi do te bjere nerekursioj te pafund.

Ne vend te kesaj, duhet te jemi me specifike qe ne duam te therrasim vetem


metoden deposit te superklases dhe per kete kemi fjalen kyce super. Jan je copez
kodi:
public class CheckingAccount extends BankAccount
{ public void deposit(double amount)
{ transactionCount++;
// now add amount to balance
super.deposit(amount);
}
...

Ky eshte version korrekt I metodes deposit. Per te depozituar te ardhura ne nje


llogari CheckingAccount update-ojme numrin e transaksioneve dhe therret me
pas metoden deposit te superklases.

Metodat e ngelura tani jane te thjeshta!


public class CheckingAccount extends BankAccount
{...
public void withdraw(double amount)
{ transactionCount++;
// now subtract amount from balance
super.withdraw(amount);
}
public void deductFees()
{ if (transactionCount > FREE_TRANSACTIONS)
{ double fees = TRANSACTION_FEE
* (transactionCount - FREE_TRANSACTIONS);
super.withdraw(fees);
}
transactionCount = 0;
}
...
private static final int FREE_TRANSACTIONS = 3;
private static final double TRANSACTION_FEE = 2.0;

You might also like