Koja je razlika između Override i Overload metoda?
Zimska noć uvek dolazi rano. Tiho stojim na balkonu, pogledom sežem do nevidljivih armiranobetonskih struktura i onih svetlosti bez ikakvog šarma.
„Erge, ne stoj tu i zuriš. Šta ćemo danas učiti? U 19:30 moram vratiti se u školu, vreme ti ne ostaje mnogo, moraš se potrudi“ — glas Sanmej odmah me vratio iz zamagljenog stanja u realnost.
„Danas ćemo učiti o metodama Overload i Override u Javi.“ Brzo sam išao do računara, otvorio Excel dokument, pogledao napredak „Uči Sanmej Java (predhodnik Ergeovog naprednog Java puta)“ i potom rekao Sanmej.
„Ako klasa ima više metoda istog imena ali različitog broja parametara, obično ih zovemo metodama Overload.“ Nastavio sam sa prostom, iskrenom osmehom, „Ako je funkcija metode ista, ali parametri različiti, korišćenje istog imena može poboljšati čitljivost programa.“
„Ako potklasa ima istu metodu kao nadklasa (isti parametri, isti povratni tip, isto ime metode, ali telo metode može biti različito), to zovemo Override metodom. Override se koristi za pružanje specijalne implementacije metode koju je već deklarisala nadklasa, i osnovni je uslov za polimorfizam."
„Samo, imena Override i Overload su veoma slična, kao dva brata, zbog čega početnici često mešaju ova dva pojma."
„Englesko ime Overload metode je Overloading, a Override metode je Overriding, stoga ne samo da su kineski imena slična, već su i engleska imena slična, što još više zbunjuje početnike."
„Ali u stvari su potpuno različiti! Kroz sledeću sliku možeš jasno videti razliku."
Glasom je upravo padnuo, već sam kucao u IDEA. Dva dela koda, jedan za Override metodu, jedan za Overload metodu. Zatom sam te dva dela koda screenshotovao na draw.io (vrlo lepo online mesto za crtanje), dodao neka tekstualna objašnjenja. Konačno, otvorio sam Photoscape X, spojio dve slike u jednu.

01,Overload metoda
„Sanmej, pažljivo slušaj.“ Nastavio sam nakon što sam zadeo dah.
„U Javi postoje dva načina za postizanje cilja Overload metode."
„Prvi, promenom broja parametara. Pogledaj sledeći kod.“
public class OverloadingByParamNum {
public static void main(String[] args) {
System.out.println(Adder.add(10, 19));
System.out.println(Adder.add(10, 19, 20));
}
}
class Adder {
static int add(int a, int b) {
return a + b;
}
static int add(int a, int b, int c) {
return a + b + c;
}
}„Klasa Adder ima dve metode, prva metoda add() ima dva parametra, pri pozivanju može se proslediti dva parametra; druga metoda add() ima tri parametra, pri pozivanju može se proslediti tri parametra."
„Erge, da li ovakav kod deluje suviše govorni? Ako postoje četiri parametra, da li dodati još jednu metodu?“ Sanmej je iznenada postavila vrlo oštro pitanje.
„To jeste, ovaj primer samo služi da pokaže jedan tip Overload metode. Ako su tipovi parametara isti, Java nudi način varijabilnih parametara, ovako.“
static int add(int ... args) {
int sum = 0;
for ( int a: args) {
sum += a;
}
return sum;
}„Drugi, promenom tipa parametara takođe može se postići cilj Overload metode. Pogledaj sledeći kod.“
public class OverloadingByParamType {
public static void main(String[] args) {
System.out.println(Adder.add(10, 19));
System.out.println(Adder.add(10.1, 19.2));
}
}
class Adder {
static int add(int a, int b) {
return a + b;
}
static double add(double a, double b) {
return a + b;
}
}„Klasa Adder ima dve metode, tip parametra prve metode add() je int, tip parametra druge metode add() je double."
„Erge, zašto promena broja i tipa parametara može realizovati Overload metodu, ali promena povratnog tipa metode ne može?“ Sanmej je vrlo dobro uhvatila bit problema.
„Zato što ako se samo promeni povratni tip, zbunjiće se kompajler.“ Odgovorio sam malo nestašnim tonom.
„Greška pri kompajliranju je bolja od greške pri izvršavanju, stoga kada dve metode imaju isto ime, isti broj i tip parametara, iako su povratni tipovi različiti, i dalje će se prijaviti greška da je metoda već definisana."

„Razmisli, Sanmej. Kada pozivamo metodu, možemo specificirati povratni tip, ali i ne moramo. Kada ne specificiramo, direktno pozivamo add(1, 2), kompajler ne zna da li pozvati metodu add() koja vraća int ili metodu add() koja vraća double, dolazi do nejasnoće."
„Povratna vrednost metode služi samo kao stanje nakon izvršenja metode, to je veza koja održava komunikaciju između pozivaoca i pozvanog, ali ne može služiti kao „identifikator“ metode."
„Erge, mislim na jednu tačku, da li se može primeniti Overload na main() metodu?“
„Sanmej, to je odlično pitanje! Odgovor je potvrdan, main() metoda je takođe metoda, samo Java virtuelna mašina pri izvršavanju poziva samo onu main() metodu sa nizom Stringova."
public class OverloadingMain {
public static void main(String[] args) {
System.out.println("String[] args");
}
public static void main(String args) {
System.out.println("String args");
}
public static void main() {
System.out.println("Bez parametara");
}
}„Parametar prve metode main() je oblika String[] args, to je standardni oblik; parametar druge metode main() je oblika String args, bez zagrada; treća metoda main() nema parametre."
„Pogledaj rezultate izvršenja programa.“
String[] args„Iz rezultata možemo videti, iako se metoda main() može primeniti Overload, program prepoznaje samo standardni oblik."
„Budući da se Overload metoda može realizovati promenom tipa parametra, kada prosleđeni parametar ne nađe odgovarajuću metodu, dogodiće se implicitna konverzija tipa."

„Kao što je prikazano na gornjoj slici, bajt može se konvertovati u gore u short, int, long, float i double, short može se konvertovati u gore u int, long, float i double, char može se konvertovati u gore u int, long, float i double, i tako redom."
„Sanmej, pogledaj sledeći primer."
public class OverloadingTypePromotion {
void sum(int a, long b) {
System.out.println(a + b);
}
void sum(int a, int b, int c) {
System.out.println(a + b + c);
}
public static void main(String args[]) {
OverloadingTypePromotion obj = new OverloadingTypePromotion();
obj.sum(20, 20);
obj.sum(20, 20, 20);
}
}„Pri izvršavanju obj.sum(20, 20), ne nalazi se metoda sum(int a, int b), stoga se drugi 20 konvertuje u gore u long, pa se poziva metoda sum(int a, long b)."
„Još jedan primer."
public class OverloadingTypePromotion1 {
void sum(int a, int b) {
System.out.println("int");
}
void sum(long a, long b) {
System.out.println("long");
}
public static void main(String args[]) {
OverloadingTypePromotion1 obj = new OverloadingTypePromotion1();
obj.sum(20, 20);
}
}„Pri izvršavanju obj.sum(20, 20), nalazi se metoda sum(int a, int b), stoga se neće konvertovati u gore u long."
„Pogledaj rezultate izvršenja programa.“
int„Nastavimo sa primerima."
public class OverloadingTypePromotion2 {
void sum(long a, int b) {
System.out.println("long int");
}
void sum(int a, long b) {
System.out.println("int long");
}
public static void main(String args[]) {
OverloadingTypePromotion2 obj = new OverloadingTypePromotion2();
obj.sum(20, 20);
}
}„Erge, ponovo sam mislila na jedno pitanje. Kada postoje dve metode sum(long a, int b) i sum(int a, long b), isti broj parametara, isti tip parametara, samo je različita pozicija, šta će se desiti?"
„Kada se poziva metoda sum kroz obj.sum(20, 20), kompajler će prijaviti grešku."

„Nije jasno, kompajler će biti u neprilici, da li da pretvori prvi 20 iz int u long ili drugi 20 iz int u long, glupe je! Stoga, nemoj pisati takav kod koji stavlja kompajler u nepriliku."
02,Override metoda
„Sanmej, umorna si? Odmorimo se malo.“ Sklonio sam naočare, stavio na sto, zatvorio oči i počeo da maštam.
- godine, Jay Chou se iznenada pojavio, dajući novi život records industriji koja je bila u tranziciji, otvarajući zlatno doba nove borbe kraljeva. 2020. godine, Jay je postao debeli, voli da se igra, objavljivanje jedne singlice godišnje postalo je retko.
Pre 20 godina, programeri su bili retki; posle 20 godina, programeri su postali konkurentni. Vreme nikada ne staje, da li će sledeće godine biti bolja?
„Erge, probudi se, rekoh smo da odmorimo malo, ne rekosmo da da zaspavš. Hitno, imam još pola sata da odem."
Sreo sam naočare i rekao Sanmej: „U Javi, Override metoda mora zadovoljiti sledeća tri pravila."
- Override metoda mora imati isto ime kao metoda u nadklasi;
- Override metoda mora imati iste parametre kao metoda u nadklasi;
- Mora biti is-a veza (veza nasleđivanja).
„Pogledaj sledeći kod."
public class Bike extends Vehicle {
public static void main(String[] args) {
Bike bike = new Bike();
bike.run();
}
}
class Vehicle {
void run() {
System.out.println("Vozilo se kreće");
}
}„Pogledaj rezultate izvršenja programa."
Vozilo se kreće„Bike is-a Vehicle, bicikl je vrsta vozila, tačno. Klasa Vehicle ima metodu run(), što znači da se vozilo može kretati, Bike nasleđuje Vehicle, takođe se može kretati. Ali ako Bike ne Override-uje metodu run(), bicikl može biti samo 'vozilo se kreće', a ne 'bicikl se kreće', zar ne?"
„Ako postoji Override metoda, sve je lako."
public class Bike extends Vehicle {
@Override
void run() {
System.out.println("Bicikl se kreće");
}
public static void main(String[] args) {
Bike bike = new Bike();
bike.run();
}
}
class Vehicle {
void run() {
System.out.println("Vozilo se kreće");
}
}Pomerao sam miša do metode run() klase Bike i rekao Sanmej: „Vidi, pri Override metode, IDEA će predložiti korišćenje @Override anotacije, eksplicitno pokazujući da je ovo Override metoda, iako se može izostaviti."
„Pogledaj rezultate izvršenja programa."
Bicikl se kreće„Bike je Override-ovao metodu run(), što znači da Bike može trčati svojim stilom."
Dobro, sada recimo o 12 pravila koja treba poštovati pri Override, treba ih pamtitii.
Pravilo 1: Mogu se Override-ovati samo nasleđene metode.
Zato što se Override dešava kada potklasa ponovo implementira metodu nasleđenu od nadklase, stoga se mogu Override-ovati samo nasleđene metode, što je lako razumeti. To znači da se mogu Override-ovati samo metode modifikovane sa public, protected ili default, private metode se ne mogu Override-ovati.
Klasa Animal ima tri metode move(), eat() i sleep():
public class Animal {
public void move() { }
protected void eat() { }
void sleep(){ }
}Klasa Dog Override-uje ove tri metode:
public class Dog extends Animal {
public void move() { }
protected void eat() { }
void sleep(){ }
}OK, potpuno bez problema. Ali ako je metoda u nadklasi private, neće proći.
public class Animal {
private void move() { }
}U ovom trenutku, metoda move() u klasi Dog više nije Override metoda, zato što je metoda move() nadklase private, za potklasu nije vidljiva.
public class Dog extends Animal {
public void move() { }
}Pravilo 2: final i static metode se ne mogu Override-ovati.
Ako je metoda final, to znači da se ne može nasleđivati u potklasu, stoga se ne može Override-ovati.
public class Animal {
final void move() { }
}Budući da je metoda move() u nadklasi Animal final, kada potklassa pokuša da Override-uje ovu metodu, dogodiće se greška pri kompajliranju!

Slično, ako je metoda static, takođe se ne dozvoljava Override, zato što static metode mogu koristiti svi instance nadklase i potklase.
public class Animal {
final void move() { }
}Cilj Override-a je da pokazuje polimorfizam prema tipu objekta, a static metode ne zahtevaju kreiranje objekata za korišćenje. Bez objekata, „tip objekta“ potreban za Override nema značenja.

Pravilo 3: Override metoda mora imati istu listu parametara.
public class Animal {
void eat(String food) { }
}Metoda eat() u klasi Dog održava isti nivo kao metoda eat() nadklase, oba imaju jedan parametar — food tipa String.
public class Dog extends Animal {
public void eat(String food) { }
}Jednom kada potklassa ne poštuje ovo pravilo, na primer, ako doda jedan parametar:
public class Dog extends Animal {
public void eat(String food, int amount) { }
}Ovo više nije oblast Override-a, naravno ni oblast Overload-a, zato što Overload razmatra istu klasu.
Pravilo 4: Override metoda mora vratiti isti tip.
Nadklasa nema povratni tip:
public class Animal {
void eat(String food) { }
}Potklassa pokušava da vrati String:
public class Dog extends Animal {
public String eat(String food) {
return null;
}
}Dolazi do greške pri kompajliranju (povratni tip nije kompatibilan).

Pravilo 5: Override metoda ne može koristiti strože restriktivne modifikatore pristupa.
Može se razumeti na sledeći način:
- Ako je Override-ovana metoda default, onda može biti default, protected ili public.
- Ako je Override-ovana metoda protected, onda može biti samo protected ili public.
- Ako je Override-ovana metoda public, onda može biti samo public.
Na primer, metoda u nadklasi je protected:
public class Animal {
protected void eat() { }
}Metoda u potklasi može biti public:
public class Dog extends Animal {
public void eat() { }
}Ako metoda u potklasi koristi strože restriktivnije modifikatore pristupa, kompajler će prijaviti grešku.

Pravilo 6: Override metoda ne može bacati viši nivo izuzetaka od nadklase.
Na primer, ako metoda u nadklasi baca IOException, onda Override-ovana metoda u potklasi ne može bacati Exception, može baciti podklasu IOException ili ne bacati nikakve izuzetke. Ovo pravilo važi samo za proverljive (checked) izuzetke.
Proverljivi (checked) izuzetci moraju se eksplicitno uhvatiti i obraditi u izvornom kodu, neproverljivi (unchecked) izuzetci su tzv. izuzetci pri izvršavanju, na primer NullPointerException, ArrayIndexOutOfBoundsException, neće se tražiti od strane kompajlera.
Nadklasa baca IOException:
public class Animal {
protected void eat() throws IOException { }
}Potklassa koja baca FileNotFoundException može zadovoljiti pravila Override, zato što je FileNotFoundException podklasa IOException.
public class Dog extends Animal {
public void eat() throws FileNotFoundException { }
}Ako potklassa baca novi izuzetak, i to je checked izuzetak:
public class Dog extends Animal {
public void eat() throws FileNotFoundException, InterruptedException { }
}Kompajler će prijaviti grešku:
Greška:(9, 16) java: com.itwanger.overriding.Dog.eat() ne može prekriti com.itwanger.overriding.Animal.eat()
Prekrivena metoda ne baca java.lang.InterruptedExceptionAli ako potklassa baca unchecked izuzetak, nema konflikta:
public class Dog extends Animal {
public void eat() throws FileNotFoundException, IllegalArgumentException { }
}Ako potklassa baca viši nivo izuzetka:
public class Dog extends Animal {
public void eat() throws Exception { }
}Kompajler će takođe prijaviti grešku, zato što je Exception nadklasa IOException.
Greška:(9, 16) java: com.itwanger.overriding.Dog.eat() ne može prekriti com.itwanger.overriding.Animal.eat()
Prekrivena metoda ne baca java.lang.ExceptionPravilo 7: U potklasi se može pozvati Override-ovana metoda nadklase kroz super ključnu reč.
Vrlo je čest način da potklassa nasleđuje metodu nadklase umesto da je ponovo implementira, u ovom slučaju može se pozvati metoda nadklase na sledeći način:
super.overriddenMethodName();Pogledaj primer.
public class Animal {
protected void eat() { }
}Potklassa je Override-ovala metodu eat(), zatim u metodi eat() potklase, može se u prvom redu pozvati metoda nadklase kroz super.eat(), a zatim dodati kod pripadajuć potklasi.
public class Dog extends Animal {
public void eat() {
super.eat();
// Pass-eat
}
}Pravilo 8: Konstruktori se ne mogu Override-ovati.
Zato što konstruktoriisu vrlo specifični, i konstruktor potklase ne može imati isto ime kao konstruktor nadklase (različita imena klasa), stoga konstruktori i Override nemaju nikakve veze.
Pravilo 9: Ako klasa nasleđuje apstraktnu klasu, apstraktne metode apstraktne klase moraju biti Override-ovane u potklasi.
Prvo pogledajmo sledeći interfejs:
public interface Animal {
void move();
}Metode u interfejsu su podrazumevano apstraktne, može se videti kroz dekompajliranje:
public interface Animal
{
public abstract void move();
}Ako apstraktna klasa implementira interfejs Animal, metoda move() nije obavezna za Override:
public abstract class AbstractDog implements Animal {
protected abstract void bark();
}Ali ako klasa nasleđuje apstraktnu klasu AbstractDog, onda se moraju Override-ovati metoda move() iz interfejsa Animal i apstraktna metoda bark() iz apstraktne klase AbstractDog:
public class BullDog extends AbstractDog {
public void move() {}
protected void bark() {}
}Pravilo 10: synchronized ključna reč ne utiče na pravila Override.
synchronized ključna rečse koristi za uzimanje i puštanje monitoring objekta u višethreadnom okruženju, stoga ne utiče na pravila Override, to znači da synchronized metoda može Override-ovati nesinhronizovanu metodu.
Pravilo 11: strictfp ključna reč ne utiče na pravila Override.
Ako želite da floating-point operacije budu preciznije, i da se rezultati izvršenja ne razlikuju zbog različitih hardverskih platformi, možete dodati strictfp ključnu reč na metodu, ranije smo govorili. Stoga strictfp ključna reč nije vezana za pravila Override.
03,Zaključak
„Dobro, Sanmej, napraviću jednostavan zaključak.“ Bacio sam pogled na sat u gornjem desnom uglu računara, do Sanmejinog odlaska manje od 10 minuta.
„Prvo, recimo nešto o napomenama pri Overload metodi, 'dva ista, jedno različito'."
„'Dva ista': u istoj klasi, isto ime metode."
„'Jedno različito': parametri su različiti."
„Zatim recimo nešto o napomenama pri Override metodi, 'dva ista, jedno manje, jedno veće'."
„'Dva ista': isto ime metode, isti parametri."
„'Jedno manje': tip izuzetka koje deklariše metoda potklase treba biti manji ili jednak od nadklase."
„'Jedno veće': prava pristupa metoda potklase trebaju biti veća ili jednaka nadklasi."
„Zapamtila? Sanmej. Stavi masku, uzmi telefon, spremimo se za izlazak.“ Danas je ograničenje broja, ne mogu voziti Sanmej u školu.
