JAVA PAGRINDAI DETALIAU

Java metodų perkrovimas

Metodų perkrovimas (angl. method overloading) leidžia klasėje aprašyti kelis vienodo pavadinimo metodus, jei skiriasi jų parametrų sąrašai. Ta pati aiški veiksmo sąvoka gali būti pritaikyta skirtingam argumentų skaičiui ar tipui.

Paprastas pavyzdys: skirtingas parametrų skaičius

class Skaiciuotuvas {
    int sudeti(int pirmas, int antras) {
        return pirmas + antras;
    }

    int sudeti(int pirmas, int antras, int trecias) {
        return pirmas + antras + trecias;
    }
}

Skaiciuotuvas skaiciuotuvas = new Skaiciuotuvas();

System.out.println(skaiciuotuvas.sudeti(4, 6));
System.out.println(skaiciuotuvas.sudeti(4, 6, 5));
Konsolės rezultatas

10
15

  1. Abu metodai vadinasi sudeti, nes abu atlieka tą patį veiksmą.
  2. Pirmasis priima du int parametrus, todėl tinka iškvietimui sudeti(4, 6).
  3. Antrasis priima tris parametrus, todėl tinka iškvietimui sudeti(4, 6, 5).
  4. Kompiliatorius tinkamą metodą pasirenka dar prieš paleidžiant programą.

Skirtingi parametrų tipai

class KainosSpausdintuvas {
    void rodyti(int eurai) {
        System.out.println("Kaina: " + eurai + " Eur");
    }

    void rodyti(double eurai) {
        System.out.printf("Kaina: %.2f Eur%n", eurai);
    }
}

KainosSpausdintuvas spausdintuvas = new KainosSpausdintuvas();
spausdintuvas.rodyti(12);
spausdintuvas.rodyti(12.5);
Konsolės rezultatas

Kaina: 12 Eur
Kaina: 12.50 Eur

  1. Sveikajam skaičiui 12 tiksliai tinka metodas su int parametru.
  2. Reikšmei 12.5 reikia metodo su double parametru.
  3. Metodai gali turėti skirtingą vykdomą kodą, tačiau jų bendras pavadinimas parodo tą pačią paskirtį – parodyti kainą.

Skirtinga parametrų tvarka

class Pristatymas {
    void registruoti(String miestas, int pastoKodas) {
        System.out.println(miestas + ", " + pastoKodas);
    }

    void registruoti(int pastoKodas, String miestas) {
        System.out.println(pastoKodas + ", " + miestas);
    }
}

Pristatymas pristatymas = new Pristatymas();
pristatymas.registruoti("Kaunas", 44280);
pristatymas.registruoti(92118, "Klaipėda");
Konsolės rezultatas

Kaunas, 44280
92118, Klaipėda

Parašai registruoti(String, int) ir registruoti(int, String) yra skirtingi, todėl Java juos leidžia. Vis dėlto tokie panašūs variantai gali klaidinti žmogų. Jei argumentų prasmė iš iškvietimo neaiški, geriau rinktis skirtingus, aiškesnius metodų vardus.

Kas sudaro metodo parašą?

Kas leidžia perkrauti metodą?
PakeitimasAr sukuriamas kitas perkrovimas?Kodėl?
Parametrų skaičiusTaipIškvietimai turi skirtingą argumentų skaičių
Parametrų tipaiTaipKompiliatorius gali parinkti pagal argumentų tipus
Parametrų tipų tvarkaTaipGaunamas kitas parametrų sąrašas
Parametrų vardaiNeVardai nėra metodo parašo dalis
Grąžinamasis tipasNeJava negali pasirinkti metodo vien pagal laukiamą rezultatą
Prieigos modifikatoriusNepublic ar private metodo parašo nekeičia

Tiksliausias atitikmuo ir skaitinio tipo platinimas

class Matavimas {
    void rodyti(int reiksme) {
        System.out.println("int: " + reiksme);
    }

    void rodyti(double reiksme) {
        System.out.println("double: " + reiksme);
    }
}

Matavimas matavimas = new Matavimas();
short trumpasSkaicius = 7;

matavimas.rodyti(5);
matavimas.rodyti(5.5);
matavimas.rodyti(trumpasSkaicius);
Konsolės rezultatas

int: 5
double: 5.5
int: 7

  1. 5 yra int, todėl pasirenkamas tiksliai sutampantis variantas.
  2. 5.5 yra double, todėl pasirenkamas antras metodas.
  3. short varianto nėra, todėl Java saugiai išplečia short į int.
  4. Jei įmanomi keli variantai, kompiliatorius ieško konkrečiausio tinkamo atitikmens.

Dviprasmiškas iškvietimas

class Pastaba {
    void issaugoti(String tekstas) { }
    void issaugoti(StringBuilder tekstas) { }
}

Pastaba pastaba = new Pastaba();

// Klaida: null tinka abiem metodams
pastaba.issaugoti(null);
Rezultatas

Kodas nesukompiliuojamas: null gali būti ir String, ir StringBuilder nuoroda, o nė vienas tipas čia nėra aiškiai tinkamesnis.

Per daug panašių perkrovimų apsunkina naudojimą. Metodo API turėtų būti ne tik techniškai leidžiamas, bet ir lengvai suprantamas.

Galima perkrauti ir statinius metodus

class Tekstas {
    static String sujungti(String pirmas, String antras) {
        return pirmas + " " + antras;
    }

    static String sujungti(String pirmas, String antras, String trecias) {
        return pirmas + " " + antras + " " + trecias;
    }
}

System.out.println(Tekstas.sujungti("Labas", "Ieva"));
System.out.println(Tekstas.sujungti("Gražios", "tau", "dienos"));
Konsolės rezultatas

Labas Ieva
Gražios tau dienos

Perkrovimas galioja ir egzemplioriaus, ir static metodams. Svarbiausia, kad vienodo pavadinimo metodų parametrų sąrašai būtų skirtingi.

Kodėl tai vadinama kompiliavimo laiko polimorfizmu?

Kompiliatorius iš argumentų jau gali nustatyti, kurį perkrautą metodą kviesti. Pasirinkimas nėra paliekamas vykdymo laikui. Dėl to metodų perkrovimas dar vadinamas statiniu arba kompiliavimo laiko polimorfizmu.

Nepainiok su metodo perrašymu.

Perkrovimas reiškia kelis vienodo vardo, bet skirtingų parametrų metodus. Perrašymas (overriding) vyksta paveldėjime, kai poklasis pateikia savo paveldėto metodo įgyvendinimą.

Metodų ir konstruktorių perkrovimas

Dviejų perkrovimo rūšių palyginimas
SavybėMetodų perkrovimasKonstruktorių perkrovimas
PaskirtisLeisti atlikti panašų veiksmą su skirtingais duomenimisLeisti skirtingais būdais sukurti objektą
PavadinimasTas pats metodo vardasVisada klasės vardas
Grąžinamasis tipasYra, tačiau perkrovimo nenulemiaNerašomas
IškvietimasPer objektą arba klasę, jei metodas staticDažniausiai su new

Plačiau apie Java konstruktorių perkrovimą

Ką verta prisiminti?

  • Perkrauti metodai turi tą patį pavadinimą ir skirtingus parametrų sąrašus.
  • Galima keisti parametrų skaičių, tipus arba jų tvarką.
  • Parametrų vardai ir grąžinamasis tipas perkrovimo nesukuria.
  • Kompiliatorius renkasi tiksliausią galimą atitikmenį.
  • Java gali atlikti saugų primityviojo tipo išplėtimą, jei tikslaus varianto nėra.
  • Venk perkrovimų, kuriuos žmogui arba kompiliatoriui lengva supainioti.