Declararea metodelor

În programarea orientată pe obiecte, clasa conține, în mod normal, nu numai câmpuri de date, ci și metodele prin care se tratează aceste câmpuri.

Sub aspect conceptual, metoda este o funcție sau o procedură, care folosește drept date atât valorile argumentelor sale, cât și câmpurile clasei căreia îi aparține metoda respectivă.
 
În principiu, deosebirea dintre funcție și procedură este că funcția "întoarce" o valoare, în timp ce metoda nu întoarce o valoare, ci are numai efect lateral. O funcție fără efect lateral este realizarea în program a conceptului matematic de funcție și este folosită în expresiile de calcul numai pentru valoarea ei. În limbajele C/C++ și Java, procedurile se scriu, din punct de vedere sintactic, la fel ca funcțiile, dar se consideră că ele intorc o valoare specială numită void. Acesta este un artificiu pentru a indica faptul că o asemenea "funcție" nu întoarce o valoare.

În limbajele de programare tradiționale, o funcție (sau procedura) folosește ca date argumentele sale și variabilele globale. În limbajul Java nu există variabile globale și nici funcții independente (care să nu fie metode ale unor clase). În schimb, fiecare metodă poate folosi ca date atât argumentele saleși variabilele locale, cât și câmpurile clasei căreia îi aparține metoda respectivă.

Cea mai simplă formă sintactică a declarației de metodă este următoarea:
    tip_valoare_intoarsa nume_metoda(declaratii_de_argumente) {
       corpul_metodei
    }
în care:
    tip_valoare_intoarsa - este tipul valorii primitive sau clasa valorii-referință întoarsă de aceasta metodă;
    nume_metoda- este un identificator care, în mod uzual, începe cu literă mică și constituie numele metodei;
    declaratii_de argumente - este o listă de declarații de argument separate prin virgulă, deci ea poate avea forma:
    declaratie_argument1, declaratie_argument2, ... declaratie_argumentN
dar poate fi și vidă. Lista declarațiilor de argument este cuprinsă între paranteze rotunde. Fiecare declarație de argument are forma
    tip_argument nume_argument
în care
    tip_argument - este tipul sau clasa argumentului respectiv;
    nume_argument- este un identificator care, în mod uzual, începe cu literă mică.
După această listă de argumente se deschide acolada unui bloc, care conține corpul metodei, adică secvența de instrucțiuni prin care se calculează valoarea funcției respective și/sau - dacă este cazul - se efectuează acțiunile care constituie efectele laterale ale acesteia.

Instrucțiunea return

Dacă funcția întoarce o valoare (diferită de void), aceasta se indică prin instrucțiunea
    return expresie;
Efectul acestei instrucțiuni este următorul: se evalueaza expresia expresie și se încheie executarea funcției respective, întorcând valoarea astfel obținută. În consecință, chiar dacă după instrucțiunea return mai apar în corpul funcției respective și alte instrucțiuni, acestea nu vor mai fi executate.
Dacă metoda nu întoarce o valoare (întoarce void), folosirea instrucțiunii return nu este absolut necesară, încheierea execuției făcându-se când se ajunge la acolada prin care se sfârsește blocul funcției. Totuși, dacă este necesar să se încheie în mod abrupt executarea corpului funcției, se poate folosi instrucțiunea return fără expresie.

Metode statice

La declararea metodelor statice, în fața tipului valorii întoarse se pune modificatorul static. Metodele care conțin în declarație acest modificator se numesc statice sau ale clasei, spre deosebire de metodele obișnuite care sunt ale instanței. În corpul metodelor statice se pot folosi numai câmpurile statice ale clasei respective și se pot invoca numai alte metode statice ale acestei clase.
 
Exemplu

În fișierul Cercuri.java se declară două clase pentru cercuri: clasa Cerc1, în care aria și circumferința se calculeaza prin metode ale instanței, și clasa Cerc2, care conține metode statice.
 
/* Declararea clasei Cerc1 cu metode ale instantei */

class Cerc1 {
  static final double PI=3.141592653589793;
  double r;

  double arie() {
    return PI*r*r;
  }

  double circumferinta() {
    return 2*PI*r;
  }
}

/* Declararea clasei Cerc2 cu metode ale clasei (statice) */

class Cerc2 {
  static final double PI=3.141592653589793;

  static double arie(double r) {
    return PI*r*r;
  }

  static double circumferinta(double r) {
    return 2*PI*r;
  }
}

Clasa Cerc1 conține câmpul static final PI și câmpul de instanță r (raza cercului). Aceasta întrucat numărul PI este o constantă valabilă pentru orice cerc, în timp ce raza cercului diferă de la o instanță la alta. Cele doua metode de instanță, arie() și circumferinta(), nu au argumente, dar folosesc ca date câmpurile statice și de instanță declarate în clasa respectivă. Invocarea acestor metode se face calificându-le cu numele instanței.

Clasa Cerc2 conține, de asemenea, câmpul static final PI, dar nu conține câmpul de instanță r. În schimb, metodele sale sunt statice și primesc raza cercului ca argument. Invocarea acestor metode se face calificându-le cu numele clasei.

În fișierul Cercuri.java există și clasa Cercuri, în care se folosesc clasele Cerc1 și Cerc2 declarate anterior. Iată această aplicație:
 
/* Aplicatia in care se utilizeaza cele doua clase de cercuri
   declarate mai sus
*/

class Cercuri {
  public static void main(String args[]) {
    double r1=1, r2=7.32;
    Cerc1 c1=new Cerc1(), c2=new Cerc1();
    c1.r=r1; c2.r=r2;
    System.out.println("Folosind metodele de instanta din clasa Cerc1:");
    System.out.println("Pentru cercul c1: aria="+c1.arie()+
      " circumferinta="+c1.circumferinta());
    System.out.println("Pentru cercul c2: aria="+c2.arie()+
      " circumferinta="+c2.circumferinta());
    System.out.println("Folosind metodele statice din clasa Cerc2:");
    System.out.println("Pentru raza r1: aria="+Cerc2.arie(r1)+
      " circumferinta="+Cerc2.circumferinta(r1));
    System.out.println("Pentru raza r2: aria="+Cerc2.arie(r2)+
      " circumferinta="+Cerc2.circumferinta(r2));
  }
}

Remarcăm că:
  - instanțierea clasei Cerc1 s-a făcut folosind constructorul implicit Cerc1(); vom explica aceasta la capitolul "declararea constructorilor";
  - atribuirea de valoare razei r a instanțelor din clasa Cerc1 s-a făcut calificând numele câmpului cu numele referinței la instanță, de exemplu în instrucțiunea de atribuire c1.r=r1;
  - invocarea metodelor de instanță s-a făcut calificând numele metodei cu referința la instanța respectivă: de exemplu c1.arie() calculează aria cercului cu referința c1 si, deci, va folosi implicit raza c1.r1;
  - invocarea metodelor statice ale clasei Cerc2 s-a făcut calificându-le cu numele clasei și transmițându-le valoarea razei cercului ca argument, de exemplu Cerc2.arie(r1);
  - la compilarea fișierului sursă Cercuri.java se obțin trei fișiere de bytecode: Cerc1.class, Cerc2.class si Cercuri.class, corespunzătoare celor trei clase declarate. 

Metode cu același nume. Signatura metodei

În aceeași clasă pot exista mai multe metode cu același nume, cu condiția ca ele să difere prin numărul și/sau tipul argumentelor. Pentru a deosebi între ele astfel de metode, s-a introdus conceptul de signatură.

Signatura metodei constă din numele acesteia, însoțit de lista de argumente. În consecință, două metode pot avea același nume, dacă diferă între ele prin signatură. Putem da exemple din clasele existente în pachetele deja studiate.
 
Să considerăm, de exemplu, următoarele metode ale clasei String:
 int indexOf(int ch) 
 int indexOf(int ch, int fromIndex) 
 int indexOf(String str) 
 int indexOf(String str, int fromIndex) 
Se observă imediat că prima și a doua diferă prin numărul argumentelor, prima și a treia diferă prin tipul unicului argument, iar a doua și a patra diferă prin tipul unuia din cele două argumente.



© Copyright 2000 - Severin BUMBARU, Universitatea "Dunărea de Jos" din Galați