JAVA PAGRINDAI DETALIAU
Java metodų perrašymas
Metodo perrašymas (angl. method overriding) vyksta tada, kai poklasis pateikia savo iš tėvinės klasės paveldėto metodo įgyvendinimą. Metodo paskirtis išlieka, tačiau konkretaus objekto elgesys gali skirtis.
Pirmasis perrašyto metodo pavyzdys
class Pranesimas {
void siusti() {
System.out.println("Siunčiamas bendras pranešimas");
}
}
class ElPastas extends Pranesimas {
@Override
void siusti() {
System.out.println("Siunčiamas el. laiškas");
}
}
ElPastas laiskas = new ElPastas();
laiskas.siusti();Siunčiamas el. laiškas
Pranesimasaprašo bendrą metodąsiusti().ElPastas extends Pranesimasreiškia, kadElPastaspaveldi šį metodą.- Poklasis parašo tokį patį metodo parašą ir pateikia jam konkretesnį veiksmą.
- Kadangi objektas yra
ElPastas, vykdomas jo perrašytas metodas.
Kodėl verta rašyti @Override?
Anotacija @Override aiškiai pasako kompiliatoriui: „šiuo metodu ketinu perrašyti paveldėtą metodą“. Ji nėra vien papuošimas – kompiliatorius patikrina, ar tėvinėje klasėje tikrai yra tinkamas metodas.
Jei netyčia parašysi siust() vietoje siusti() arba pakeisi parametrus, gausi kompiliavimo klaidą, o ne tyliai sukursi visai kitą metodą.
Java žiūri į tikrąjį objektą
class Pranesimas {
void siusti() {
System.out.println("Bendras pranešimas");
}
}
class ElPastas extends Pranesimas {
@Override
void siusti() {
System.out.println("El. laiškas");
}
}
class Sms extends Pranesimas {
@Override
void siusti() {
System.out.println("SMS žinutė");
}
}
Pranesimas pirmas = new ElPastas();
Pranesimas antras = new Sms();
pirmas.siusti();
antras.siusti();El. laiškas
SMS žinutė
- Abiejų kintamųjų tipas yra bendras
Pranesimas. - Pirmasis kintamasis iš tikrųjų rodo į
ElPastasobjektą, antrasis – įSms. - Vykdymo metu Java pasirenka metodą pagal tikrąjį objekto tipą.
- Tai vadinama dinaminiu metodo parinkimu arba vykdymo laiko polimorfizmu.
Perrašomo metodo parašas turi sutapti
class Dokumentas {
void atidaryti() {
System.out.println("Dokumentas atidarytas");
}
}
class TekstinisDokumentas extends Dokumentas {
@Override
void atidaryti(String programa) { // Klaida
System.out.println("Atidaryta su " + programa);
}
}Kodas nesukompiliuojamas dėl @Override: tėvinė klasė neturi metodo atidaryti(String).
Norint perrašyti metodą, turi sutapti jo pavadinimas ir parametrų sąrašas. Pakeitus parametrus sukuriamas perkrautas, o ne perrašytas metodas.
Tėvinį metodą galima papildyti su super
class Kvitas {
void spausdinti() {
System.out.println("Parduotuvė: Miesto krautuvė");
}
}
class PirkimoKvitas extends Kvitas {
@Override
void spausdinti() {
super.spausdinti();
System.out.println("Suma: 18.50 Eur");
}
}
PirkimoKvitas kvitas = new PirkimoKvitas();
kvitas.spausdinti();Parduotuvė: Miesto krautuvė
Suma: 18.50 Eur
super.spausdinti() pirmiausia iškviečia tėvinės klasės variantą. Tada poklasis prideda savo informaciją. Taip nereikia kopijuoti bendros kvito antraštės.
Prieigos negalima susiaurinti
class Paskyra {
public void rodyti() {
System.out.println("Paskyra");
}
}
class DarboPaskyra extends Paskyra {
@Override
private void rodyti() { // Klaida: siauresnė prieiga
System.out.println("Darbo paskyra");
}
}Kodas nesukompiliuojamas, nes public metodas poklasyje bandomas pakeisti į private.
Perrašytas metodas gali palikti tokią pačią arba suteikti platesnę prieigą, tačiau negali pažeisti pažado, kad tėvinės klasės metodas buvo viešai pasiekiamas.
Kurių metodų perrašyti negalima?
| Metodas | Kas nutinka? |
|---|---|
final | Perrašyti draudžiama, nes tėvinė klasė užfiksavo galutinį elgesį. |
private | Poklasis metodo nemato, todėl toks pat jo metodas būtų naujas, o ne perrašytas. |
static | Neperrašomas. Toks pats poklasio metodas paslepia tėvinės klasės statinį metodą. |
| Egzemplioriaus metodas | Gali būti perrašomas, jei kitos taisyklės tai leidžia. |
class Saskaita {
final void rodytiNumeri() {
System.out.println("LT123");
}
}
class VersloSaskaita extends Saskaita {
// Klaida: final metodo perrašyti negalima
void rodytiNumeri() { }
}Kodas nesukompiliuojamas, nes rodytiNumeri() tėvinėje klasėje pažymėtas final.
static metodo paslėpimas nėra perrašymas
class Tevas {
static void rodytiTipa() {
System.out.println("Tėvo statinis metodas");
}
void rodytiBusena() {
System.out.println("Tėvo egzemplioriaus metodas");
}
}
class Vaikas extends Tevas {
static void rodytiTipa() {
System.out.println("Vaiko statinis metodas");
}
@Override
void rodytiBusena() {
System.out.println("Vaiko egzemplioriaus metodas");
}
}
Tevas objektas = new Vaikas();
objektas.rodytiTipa(); // Leidžiama, bet nerekomenduojama
Tevas.rodytiTipa(); // Rekomenduojamas tiesioginis iškvietimas
Vaikas.rodytiTipa(); // Kviečiamas Vaikas klasės statinis metodas
objektas.rodytiBusena();Tėvo statinis metodas
Tėvo statinis metodas
Vaiko statinis metodas
Vaiko egzemplioriaus metodas
staticmetodas priklauso klasei, todėl aiškiausia jį kviesti tiesiogiai per klasės pavadinimą:Tevas.rodytiTipa()arbaVaikas.rodytiTipa().- Java taip pat leidžia parašyti
objektas.rodytiTipa(), norsobjektasyra nuorodos kintamasis. Toks užrašymas veikia, bet yra klaidinantis ir nerekomenduojamas. - Kviečiant statinį metodą per nuorodą Java nežiūri į tikrąjį objektą. Ji žiūri į deklaruotą nuorodos tipą
Tevas, todėl vykdoTevas.rodytiTipa(). Vaikas.rodytiTipa()aiškiai pasirenkaVaikasklasėje aprašytą statinį metodą.rodytiBusena()yra egzemplioriaus metodas, todėl Java žiūri į tikrąjį objektąVaikasir vykdo perrašytą jo variantą.
Statinį metodą kviesk per klasę, kuriai jis priklauso. Taip iš kodo iš karto matyti, kad metodui nereikia konkretaus objekto.
Perrašytas metodas gali grąžinti poklasio tipą
class Dokumentas {
Dokumentas kopijuoti() {
return new Dokumentas();
}
}
class Saskaita extends Dokumentas {
@Override
Saskaita kopijuoti() {
return new Saskaita();
}
}
Saskaita originalas = new Saskaita();
Saskaita kopija = originalas.kopijuoti();
System.out.println(kopija.getClass().getSimpleName());Saskaita
Tėvinis metodas grąžina Dokumentas, o perrašytas metodas – konkretesnį jo poklasį Saskaita. Tai vadinama kovariantiniu grąžinamuoju tipu ir Java tai leidžia.
Patikrintų išimčių taisyklė
Perrašytas metodas negali paskelbti naujos arba platesnės patikrintos (checked) išimties nei tėvinis metodas. Jis gali paskelbti tokią pačią, siauresnę arba išvis jos nepaskelbti. Neprivalomoms RuntimeException tipo išimtims ši riba netaikoma.
Kodas, dirbantis su tėvinės klasės tipu, jau žino, kokias patikrintas išimtis privalo apdoroti. Poklasis negali netikėtai pareikalauti apdoroti platesnio klaidų rinkinio.
Perkrovimas ir perrašymas nėra tas pats
| Savybė | Perkrovimas | Perrašymas |
|---|---|---|
| Angliškai | overloading | overriding |
| Kur vyksta? | Dažniausiai toje pačioje klasėje | Tarp tėvinės klasės ir poklasio |
| Parametrai | Privalo skirtis | Privalo sutapti |
| Pasirinkimo laikas | Kompiliavimo metu | Vykdymo metu pagal tikrąjį objektą |
| Paskirtis | Tas pats veiksmas skirtingiems argumentams | Konkretesnis paveldėto elgesio įgyvendinimas |
Ką verta prisiminti?
- Perrašymas leidžia poklasiui pakeisti paveldėto egzemplioriaus metodo elgesį.
- Metodo pavadinimas ir parametrų sąrašas turi sutapti.
- Visada naudok
@Override, kad kompiliatorius patikrintų tavo ketinimą. - Perrašytas metodas parenkamas vykdymo metu pagal tikrąjį objekto tipą.
- Prieigos negalima susiaurinti.
final,privateirstaticmetodai nėra perrašomi.- Su
super.metodas()galima panaudoti ir papildyti tėvinį elgesį.

