Sono metodi associati al programma, invece che a una classe.
Si fanno metodi di questo tipo quando il metodo è utile solo in un programma.
Consideriamo questo problema: stampare una serie di espressioni, separate da una linea di asterischi.
class Linea {
public static void main(String args[]) {
int x=12;
int y=42;
System.out.println("**********************************");
System.out.println(x+2);
System.out.println("**********************************");
System.out.println(2*x+1);
System.out.println("**********************************");
System.out.println(y/2);
System.out.println("**********************************");
System.out.println(x+y/2);
System.out.println("**********************************");
}
}
Questa istruzione si ripete sempre uguale.
Potrei definire un metodo che fa la stampa, e poi invocare il metodo quando serve.
Però il metodo va messo in una classe.
Devo creare una classe solo per metterci dentro il metodo:
class Inutile {
void stampaLinea() {
System.out.println("**********************************");
}
}
Devo creare un oggetto solo per poter invocare il metodo:
class ProcInutile {
public static void main(String args[]) {
int x=12;
int y=42;
Inutile i;
i=new Inutile();
i.stampaLinea();
System.out.println(x+2);
i.stampaLinea();
System.out.println(2*x+1);
i.stampaLinea();
System.out.println(y/2);
i.stampaLinea();
System.out.println(x+y/2);
i.stampaLinea();
}
}
Soluzione alternativa: definire il metodo dentro il programma.
Posso scrivere metodi che sono associati al programma e non a una classe.
class Proc {
static void stampaLinea() {
System.out.println("**********************************");
}
public static void main(String args[]) {
int x=12;
int y=42;
stampaLinea();
System.out.println(x+2);
stampaLinea();
System.out.println(2*x+1);
stampaLinea();
System.out.println(y/2);
stampaLinea();
System.out.println(x+y/2);
stampaLinea();
}
}
Ci sono delle somiglianze con i metodi delle classi, e delle differenze.
La dichiarazione è quasi uguale, ma si mette static davanti.
static TipoValoreRitorno nomeMetodo(argomenti) {
istruzioni
}
Per invocare il metodo nel programma (=far eseguire le istruzioni), si mette il nome del metodo con gli argomenti fra parentesi.
stampaLinea();
System.out.println(x+y/2);
stampaLinea();
Non c'è un oggetto di invocazione.
Quindi:
Sono tutte e due conseguenze del fatto che questi metodi non hanno un oggetto di invocazione.
Realizzare un metodo che stampa la stringa "Positivo" oppure "Negativo" oppure "Zero" a seconda del segno di un numero passato come argomento.
Realizzare anche un programma di prova.
Il metodo ha:
L'intestazione del metodo è di conseguenza:
static void stampaSegno(int n)
Devo stampare una stringa diversa a seconda se il numero è positivo, negativo, oppure zero.
Un modo possibile (ce ne sono altri):
static void stampaSegno(int n) {
if(n==0)
System.out.println("Zero");
else if(n>0)
System.out.println("Positivo");
else
System.out.println("Negativo");
}
Questo è un possibile programma che usa il metodo:
class Segno {
static void stampaSegno(int n) {
if(n==0)
System.out.println("Zero");
else if(n>0)
System.out.println("Positivo");
else
System.out.println("Negativo");
}
public static void main(String args[]) {
int a=2;
stampaSegno(a);
stampaSegno(-9);
stampaSegno(2*a-4);
}
}
Posso invocare il metodo passando il risultato di una qualsiasi espressione, per esempio:
Stampare questa figura:
* ** *** **** ***** ****** ******* ******** ********* **********
Definire un metodo che stampa una linea di
n
(per stampare un singolo asterisco,
fare System.out.print("*");)
Il metodo ha:
Per l'intestazione, è come un metodo di una classe:
static void asterischi(int n) {
...
}
L'unica differenza, nell'intestazione, è la parola static
In n viene messo il numero di asterischi da stampare.
Dopo aver stampato, vado a capo.
static void asterischi(int n) {
int a;
for(a=0; a<n; a++)
System.out.print("*");
System.out.println();
}
Se invoco il metodo come asterischi(x), viene stampata una linea di n asterischi.
Questo va fatto per x=1, 2, 3, ..., 10
class Aster {
static void asterischi(int n) {
int a;
for(a=0; a<n; a++)
System.out.print("*");
System.out.println();
}
public static void main(String args[]) {
int x;
for(x=1; x<=10; x++)
asterischi(x);
}
}
Quando si invoca un metodo void:
Nel corpo del metodo le variabili del programma non si possono usare.
I parametri attuali sono valori, che possono anche risultare dalla valutazione di espressioni:
asterischi(12); asterischi(a*2-b); asterischi(2+(int) p.distance(q));
Le variabili del metodo e del programma possono anche avere lo stesso nome.
Sono comunque due variabili diverse.
class Stesso {
static void asterischi(int n) {
int x;
for(x=0; x<n; x++)
System.out.print("*");
System.out.println();
}
public static void main(String args[]) {
int x;
for(x=1; x<=10; x++)
asterischi(x);
}
}
Prima di invocare il metodo:
Le variabili del metodo non esistono
Ogni volta che viene invocato un metodo, si crea una zona di memoria per tutte le sue variabili (variabili locali e parametri formali).
Prima di eseguire le istruzioni, c'è la copiatura dei parametri attuali in quelli formali.
Quando si eseguono le istruzioni, nei parametri attuali sono stati messi i valori dei parametri attuali.
Il valore di x va in n: questo dipende dell'invocazione!
Quindi, il valore di x viene copiato dentro n
È come se venisse fatto n=x;
Ogni metodo può accedere solo alle sue variabili:
La zona di memoria di asterischi viene rimossa, e si torna allo stato originario.
Attenzione! Quando si invoca nuovamente il metodo, le sue variabili vengono create di nuovo.
Da una invocazione all'altra, i valori delle variabili locali vengono persi.
Cosa stampa questo programma?
class Trab1 {
static void prova(int x) {
x=0;
}
public static void main(String args[]) {
int x;
x=12;
prova(x);
System.out.println(x);
}
}
Si deve fare la figura.
Durante l'esecuzione del programma, esiste solo la zona di memoria del programma:
Viene creata la zona di memoria del metodo:
Il valore di x del main viene copiato nella x di prova
Solo ora si esegue il corpo del metodo.
Se x=0 compare nel metodo prova, viene messo 0 nella x di prova
Notare: la x di main non può venire modificata: è inaccessibile dal metodo prova
Viene cancellata la zona di prova
Viene quindi stampato 12
Cosa stampa questo programma?
class Ordine {
static void prova(int x, int y) {
System.out.println(x);
}
public static void main(String args[]) {
int x=10;
int y=20;
prova(y,x);
}
}
I nomi delle variabili sono irrilevanti.
Se invece del nome x uso il nome abcd il programma fa lo stesso.
Il passaggio avviene sulla base della posizione:
Nella x di prova viene messo il valore della y di main
Viene stampato 20
Se non è chiaro:
usate nomi di variabili diverse, se possibile, per evitare confusione
Se invece il meccanismo è chiaro, potete anche usare gli stessi nomi.
Altro suggerimento:
non modificate i parametri formali, per evitare confusione
Il programma trasmette dei valori al metodo (es. 3, 12, -2, ecc.)
Il metodo li riceve: per poterli usare, vengono messi in alcune variabili
int a=12, b=-2; nomemetodo(12*2, a-b/2, a+b);
Vengono valutate le tre espressioni.
I valori calcolati sono 24, 13, 10
L'invocazione del metodo equivale a:
nomemetodo(24, 13, 10);
Per lo stesso motivo:
int x=12; prova(x);
È equivalente a:
int x=12; prova(12);
Perchè il valore di x dovrebbe cambiare.
I parametri attuali sono valori.
Quando si invoca il metodo, le espressioni fra parentesi vengono valutate.
Il fatto che il valore 12 derivi dal fatto che in x c'era questo valore viene dimenticato:
prova(x) diventa come prova(12), che non ha nessuna relazione con x
i parametri attuali sono valori: il programma "trasmette" dei valori ai metodi; la provenienza dei valori (costanti, valori di variabili, valori di espressioni) è irrilevante
Quando faccio prova(x) è il valore contenuto in x che viene inviato. Il fatto che provenga da x non ha importanza.
La sequenza effettiva è:
I passi vengono fatti in questa sequenza.
Cosa stampa questo programma?
class Ritorno {
static int prova(int x) {
x=x+10;
return x+2;
}
public static void main(String args[]) {
int x=12;
x=prova(x);
System.out.println(x);
}
}
Viene stampato 24
Perchè?
Inizio del metodo:
Viene ritornato il valore di x+2
Per x si intende la x di prova, che è 22
Dato che il metodo era stato invocato con x=prova(x), e il valore di ritorno è 24, questo equivale a x=24
Il valore di ritorno viene messo in x
Se non fate modifiche ai parametri formali, non avrete questi problemi:
// programma piu' chiaro
class Chiaro {
static int prova(int x) {
int altronome;
altronome=x+10;
return altronome+2;
}
public static void main(String args[]) {
int x=12;
x=prova(x);
System.out.println(x);
}
}
x=prova(x);
Se non vi risulta chiaro, usate una variabile in più:
int y; y=prova(x); x=y;
Da questo si capisce la sequenza: prima invocazione, poi assegnamento.
Date due variabili intere a e b, stampare i valori delle espressioni a-b, a-b*b, -a/b, a/b
Stampare solo i valori di queste espressioni che risultano positivi (maggiori o uguali a zero).
Valuto ogni espressione e vedo se è positiva:
class SenzaMetodo {
public static void main(String args[]) {
int a=12, b=32;
if(a-b >= 0)
System.out.println(a-b);
else
System.out.println("Espressione negativa");
if(a-b*b >= 0)
System.out.println(a-b*b);
else
System.out.println("Espressione negativa");
if(-a/b >= 0)
System.out.println(-a/b);
else
System.out.println("Espressione negativa");
if(a/b >= 0)
System.out.println(a/b);
else
System.out.println("Espressione negativa");
}
}
Farlo usando un metodo.
Quale è l'operazione che si ripete?
Stampare un valore se positivo.
``calcolare l'espressione'' non è l'operazione che si ripete, dato che ogni volta si tratta di una operazione diversa.
Si può riscrivere il programma:
class Ripetizione {
public static void main(String args[]) {
int a=12, b=32;
int f;
f=a-b;
if(f >= 0)
System.out.println(f);
else
System.out.println("Espressione negativa");
f=a-b*b;
if(f >= 0)
System.out.println(f);
else
System.out.println("Espressione negativa");
f=-a/b;
if(f >= 0)
System.out.println(f);
else
System.out.println("Espressione negativa");
f=a/b;
if(f >= 0)
System.out.println(f);
else
System.out.println("Espressione negativa");
}
}
È chiaro che la valutazione di una espressione va fatta nel programma, dato che sono quattro espressioni diverse.
Però la verifica se positivo e la stampa si ripetono sempre uguali.
Il metodo prende un valore intero, e non restituisce nulla.
class ConMetodo {
static void stampaSePositivo(int val) {
if(val>=0)
System.out.println(val);
else
System.out.println("Espressione negativa");
}
public static void main(String args[]) {
int a=12, b=32;
stampaSePositivo(a-b);
stampaSePositivo(a-b*b);
stampaSePositivo(-a/b);
stampaSePositivo(a/b);
}
}
Cosa succede quando si invoca stampaSePositivo(a-b*b)?
Equivale a fare: val=a-b*b e poi eseguire il corpo del metodo.
Si intende che dove val è la variabile del metodo mentre a e b sono variabili del programma.
Scrivere un metodo che calcola il fattoriale di un numero intero.
Scrivere poi il programma che stampa i fattoriali dei valori da 1 a 4, il fattoriale di 6 e poi verifica se il fattoriale di 5 è maggiore di 50 oppure no.
Ha valore di ritorno intero.
Ha come argomento un intero.
static int fattoriale(int n)
Calcolo il fattoriale del numero che sta in n,
e ritorno il valore calcolato.
static int fattoriale(int n) {
int a;
int f;
f=1;
for(a=1; a<=n; a++)
f=f*a;
return f;
}
Basta a questo punto invocare il metodo tutte le volte che serve.
public static void main(String args[]) {
int i;
for(i=1; i<=4; i++)
System.out.println(fattoriale(i));
System.out.println(fattoriale(6));
if(fattoriale(5)>50)
System.out.println("Il fattoriale di 5 e' maggiore di 50");
else
System.out.println("Il fattoriale di 5 e' minore di 50");
}
Provare senza metodo: andava ripetuto lo stesso codice almeno tre volte.
Anche in questo modo funziona:
static int fattoriale(int n) {
int f=1;
for(; n>=1; n--)
f=f*n;
return f;
}
Molto meno chiaro.
Scrivere un metodo che calcola il valore assoluto di un numero intero.
Scrivere un programma che legge da tastiera un intero, e stampa la radice del valore assoluto.
Ha come parametro un intero, e ritorna un intero.
static int valoreAssoluto(int)
Se il numero è positivo, ritorno il suo valore.
Se è negativo, ritorno l'opposto del suo valore.
static int valoreAssoluto(int n) {
if(n>=0)
return n;
else
return -n;
}
Nel programma di prova, è bene fare più invocazioni, per verificare se il metodo funziona.
Nel programma vero potrebbe anche esserci solo una invocazione.
class ValAssoluto {
static int valoreAssoluto(int n) {
if(n>=0)
return n;
else
return -n;
}
public static void main(String args[]) {
int x;
for(x=-10; x<=10; x++) {
System.out.println(valoreAssoluto(x));
}
}
}
Il programma che voglio fare è quello che legge un intero da tastiera, fa la radice del valore assoluto, e stampa.
import javax.swing.*;
class Radice {
static int valoreAssoluto(int n) {
if(n>=0)
return n;
else
return -n;
}
public static void main(String args[]) {
int x;
String s;
s=JOptionPane.showInputDialog("Dammi un intero");
x=Integer.parseInt(s);
System.out.println(Math.sqrt(valoreAssoluto(x)));
System.exit(0);
}
}
Scrivere un metodo che riceve due interi e restituisce la somma dei loro fattoriali.
Usare il metodo fattoriale.
Si può invocare un metodo anche all'interno di un altro metodo.
static int fattoriale(int n) {
int a;
int f;
f=1;
for(a=1; a<=n; a++)
f=f*a;
return f;
}
Prende due interi e torna un intero.
static int sommaFatt(int, int)
Devo calcolare i fattoriali, e sommarli.
static int sommaFatt(int x, int y) {
int f1, f2;
f1=fattoriale(x);
f2=fattoriale(y);
return f1+f2;
}
class SommaFatt {
static int fattoriale(int n) {
int a;
int f;
f=1;
for(a=1; a<=n; a++)
f=f*a;
return f;
}
static int sommaFatt(int x, int y) {
int f1, f2;
f1=fattoriale(x);
f2=fattoriale(y);
return f1+f2;
}
public static void main(String args[]) {
int i;
System.out.println(sommaFatt(1,4)/2);
}
}