Java/Metodi

Wikibooks, manuali e libri di testo liberi.

In questo capitolo verranno spiegati i metodi, ovvero i mattoncini di una struttura software.

Indice

[modifica] Metodi

Possiamo pensare ai metodi come a dei sotto-programmi (subroutine) che raggruppano istruzioni ed espressioni per una elaborazione semplice dei dati al loro interno.
Essi, che in altri linguaggi di programmazione sono chiamati “funzioni”, sono in pratica come dei moduli intelaiati all'interno di un raccoglitore, la classe, che normalmente ne comprende numerosi concorrendo a costituire un programma organico. Concettualmente il metodo è anche paragonabile ad una azione che l'oggetto (una istanza della classe) può compiere.

I metodi concettualmente servono a fare una stessa serie di operazioni in più punti del programma senza riscriverle, quindi snelliscono il programma. Servono anche a suddividere un programma complesso in piccole parti migliorandone la gestione e la leggibilità.

Le classi API hanno molti metodi usabili e riusabili ma è soprattuto possibile creare i propri metodi personalizzati per integrarli e adattarli meglio agli scopi del nostro programma.

I metodi vanno implementati e codificati all'interno della classe e fuori da qualsiasi altro metodo, anche il "main()" che è un metodo speciale segue questa regola; un metodo non può essere codificato e costruito all'interno di altro metodo, invece è possibile richiamare (o usare) i metodi in maniera annidata, o addirittura chiamando loro stessi.

I metodi si scrivono, o si implementano, in un modo e si usano, o chiamano, in un altro.

I metodi possono essere istanziati o di classe.

La sintassi per la implementazione (scrittura di codice) di un metodo è la seguente:

modificatori tipo nomedelmetodo (parametri eventuali){
corpo del metodo;
}

Per richiamare un metodo usiamo la sintassi:

nomedelmetodo (parametri eventuali);

Cioè per eseguire ed usare le istruzioni di “nomedelmetodo” devo scrivere

nomedelmetodo (parametri eventuali);

Di seguito è mostrato ad esempio un esempio funzionante di implementazione di un metodo senza i parametri:

class  Frase{
 
    String soggetto= "egli ";
    String verbo= "fa ";
    String complemento= "qualcosa";
 
 // inizio del metodo
 
    public void faifrase(){
        System.out.println(soggetto + verbo + complemento);
    }
 
 // fine del metodo
 
 }

Proviamo ora ad usare il metodo richiamandolo da un'altra classe, definita nel modo seguente:

public class Provametodo{
 
  public static void main(String [] Args){
 
        Frase B= new Frase();
 
        B.faifrase();   
 
 }

In questo codice richiamo il metodo faifrase() dopo aver istanziato un oggetto di classe Frase (chiamandolo "B"). Ciò è necessario per essere usato nel “main()", un altro metodo ma particolare di cui si parlerà sotto, e da un'altra classe: “Provametodo”.

“Faifrase()” è un metodo istanziato appunto perché chiamato su istanza di classe.

Il codice sorgente finale diventa quindi questo:

class  Frase{ 
 
    String soggetto= "egli ";
    String verbo= "fa ";
    String complemento= "qualcosa";
 
    public void faifrase(){
        System.out.println(soggetto + verbo + complemento);
    }
 
}
public class Provametodo{
 
  public static void main(String [] Args){
 
        Frase B= new Frase();
         B.faifrase();  
    }
}

Salvare questo codice con nome Provametodo.java, compilare ed eseguire.

I parametri possono esserci oppure no.

I metodi possono restituire un valore particolare al chiamante oppure no. Quando si vuole restituire un valore il chiamante diverrà tale valore. La restituzione di un valore si ha con l'enunciato "return" ed il tipo del valore restituito indicato prima del nome del metodo. Se non si vuole restituire un valore o un dato particolare allora non occorre return e prima del nome del metodo c'è bisogno dell'enunciato "void". Quindi, prima del nome del metodo, ci deve essere o il "void" o il tipo del valore ( con all'interno del corpo la clausola "return").

Il metodo faifrase che abbiamo su non restituisce un valore particolare questo invece si:

public int dividinumeri(int dividendo, int divisore){
 
int prodotto= dividendo/divisore;
return prodotto;
 
}

In questo caso il metodo chiamante "dividinumeri(10,2)" diventa un intero (precisamente l'intero che è stato prodotto dalla divisione), e si potrebbe usare anche come tale, ovvero come un "5".

[modifica] La firma del metodo

Nel linguaggio Java la coppia costituita dal nome e dalla lista dei parametri è detta segnatura o firma del metodo. Non fa parte della firma invece il tipo di ritorno del metodo, diversamente da altri linguaggi. Questo significa, ad esempio, che è possibile avere nella stessa classe due metodi con uguale nome e diversa lista di parametri:

	public int somma(int op1, int op2){
		return op1 + op2;
	}
 
	public int somma(int op1, int op2, int op3){
		return op1 + op2 + op3;
	}


non è invece possibile avere nella stessa classe due metodi con uguale nome e lista parametri e diverso tipo di ritorno:

	public int somma(int op1, int op2){
		return op1 + op2;
	}
 
	public double somma(int op1, int op2){
		return new Double(op1 + op2);
	}


l'esempio qui sopra otterrebbe un errore di compilazione.

[modifica] Parametri

Nella scrittura di un metodo i parametri sono importanti e fanno parte della "firma del metodo o "signature", sia che ci siano e sia che non ci siano. Questi parametri sono consideratri dalla JVM secondo il tipo, la posizione ed il numero degli stessi. I parameteri si inseriscono all'interno delle parentesi tonde, dopo il nome del metodo, in maniera analoga alla dichiarazione dei tipi primitivi e/o astratti. In quest'esempio:

(int num, String nome, boolean on, Nomedellaclasse B)

ci sono quattro parametri di un metodo, il quale nel suo corpo ne farà uso istanziandoli con valori reali del chiamante. Nella implementazione di un metodo si usano parametri formali mentre nell'uso, nella chiamata di questo, si adoperano parametri attuali ( valori). All'atto della chiamata di un metodo i parametri sono inizializzati per valore, mentre prima erano usati solo riferimenti (dichiarazioni).

Un esempio semplice di scrittura o implementazione di un metodo e i suoi parametri:

public void faifrase(String soggetto, String verbo, String complemento){
 
System.out.println(soggetto + verbo + complemento);
 
}

il metodo codificato sopra lo useremo, lo chiameremo, in questo modo:

faifrase("lui ","fa "," qualcosa");

il metodo stamperà a video la frase ottenuta con le parole passate dal chimante: "lui fa qualcosa".

Altro esempio:

public int dividinumeri(int dividendo, int divisore){
 
int prodotto= dividendo/divisore;
return prodotto;
 
}

il chiamante sarà questo:

dividinumeri(10,2);

ed otterremo 5.

Il chiamante per fare affidamento esattamente sul suo codice descritto, e magari non un altro, deve avere la lista esatta dei parametri per tipo, posizione e numero, questo farà in modo di usare esattamente il suo metodo omonimo e non un altro.

Non è possibile chiamare il metodo dividinumeri così:

dividinumeri(10,2,3):

oppure

dividinumeri(1,2,3);

i parametri sono tre e il metodo scritto ne vuole solo due.

Oppure non è possibile

faifrase ('l', "fa", "qualcosa")

il metodo vuole tre stringhe non un char e due stringhe.

Il tipo, la posizione, ed il numero, dei parametri, tra il chiamante ed il metodo scritto, devono corrispondere, sempre.

[modifica] Il tipo di ritorno

Un metodo può restituire un valore ed il tipo di questo valore deve essere indicato prima del nome del metodo:

	public int somma(int op1, int op2){
		return op1 + op2;
	}


Il tipo del valore restituito deve corrispondere con il tipo dichiarato, altrimenti avremo un errore di compilazione:

	public double somma(int op1, int op2){
		return "La somma è: "+(op1 + op2);
	}


Nell'esempio sopra abbiamo dichiarato che il tipo di ritorno sarà double mentre il metodo cerca di restituire un valore di tipo String, per cui il compilatore risponderà con un errore. Nel caso che il metodo non debba restituire un valore, al posto del tipo di ritorno dovremo mettere void. Questo indica al compilatore che il metodo non deve restituire alcun valore:

	public void somma(int op1, int op2){
		System.out.println("La somma è: "+(op1 + op2));
	}

[modifica] Il metodo "main()"

Il metodo main, è un metodo speciale, è per default il metodo di partenza delle applicazioni java. Per eseguire una applicazione l'interprete ha bisogno del metodo “main” ossia del metodo “principale”, è concettualmente una sorta di inizio o di boot o di indice di una applicazione. Abbiamo bisogno del main quando dobbiamo far partire in esecuzione una applicazione. La JVM, di default, al comando di esecuzione della classe, chiamerà il metodo "main()" ed eseguirà il suo contenuto.

Il metodo "main()":

public static void main (string arg[]){
Istruzioni di inizio applicazione: chiamata a  oggetti  e metodi ...;
}

il metodo "main()" è un metodo di classe perché statico: non vi è bisogno di istanziare un oggetto per usarlo, appartiene alla classe. Tutti i metodi statici o di classe si usano con la sintassi

classe.nomemetodo();

I metodi statici si implementano scrivendo la parola chiave "static" prima del nome e del tipo restituito.

Finora abbiamo visto che normalmente i metodi si usano con un oggetto istanziato dalla classe con questa sintassi

nomeoggetto.nomemetodo();

I metodi sono statici, ovvero di classe, quando il loro uso è frequentissimo e/o non ha senso usare oggetti in quanto la loro azione è generalmente la stessa in tutte le circostanze.

Vediamo altre particolarità del "main()".

Il "main" ha il suffisso "void" dunque non restituisce un valore specifico.

IL "main" ha come parametro un array di stringhe. Questo array serve a condizionare l'esecuzione del programma in maniera opzionale, secondo le opzioni che diamo, potremmo fare in modo che il programma si comporti di conseguenza. Le opzioni in effetti vengono memorizzate nell'array di stringhe del "main". Le opzioni si danno dopo il nome della classe da eseguire con questa sintassi

java nomedellaclasse opzione1 opzione2 ...

in questo caso "opzione1" e "opzione2" saranno nell'array che se sviluppato nel corpo del "main" ci porterà a condizionare il programma.

[modifica] Costruttori

[modifica] Overloading e Overriding

L'overloading è la possibilità di creare più metodi con lo stesso nome e nella stessa classe con argomenti diversi per numero o tipo, mentre l'overriding è la possibilità di richiamare un certo metodo anche senza ricorrere a un'istanza della classe.

Vediamo un esempio con una classe che gestisce delle date:

 class Data{
  int giorno;
  int mese;
  int anno;
 
  public void Data(){
   this.giorno=1;
   this.mese=1;
   this.anno=2000;
  }
 
 
  public void Data(int giorno, int mese, int anno){
   this.giorno=giorno;
   this.mese=mese;
   this.anno=anno;
  }
 
 }

Esistono due costruttori Data, che in un linguaggio come il C genererebbero un errore, poiché il compilatore non saprebbe a cosa si fa riferimento quando si richiama il metodo. In Java l'ambiguità è risolta dal numero e dal tipo di argomenti richiesti dai metodi, quindi richiamando un metodo verrà di volta in volta scelto tra gli ononimi quello che richiede il numero e il tipo di argomenti richiesti. Dunque scrivendo

Data compleanno=new Data();

si creerà un oggetto Data inizializzato al capodanno 2000, poiché non si è fornito alcun valore al costruttore, mentre usando

Data compleanno=new Data(3,11,2005);

la JVM utilizzerà il secondo costruttore e inizializzerà l'oggetto al 5 novembre 2005.


L'overriding, invece, consente di ridefinire un metodo in una sottoclasse: il metodo originale e quello che lo ridefinisce hanno necessariamente la stessa firma, e solo a tempo di esecuzione si determina quale dei due deve essere eseguito. Ad esempio:

public class ClassePadre {
 
	public void print(){
		System.out.println("Classe padre");
	}
 
}
 
class ClasseFiglio extends ClassePadre{
 
    @Override
    public void print() {
    	System.out.println("Classe figlio");
    }
 
    public static void main(String[] args) {
	    ClassePadre padre = new ClassePadre();
	    ClassePadre figlio = new ClasseFiglio();
	    padre.print();
	    figlio.print();
    }
 
}

La classe Figlio ridefinisce il metodo print() della classe padre e ne cambia il comportamento.


[modifica] This e Super

Strumenti personali