L'obiettivo di questa esercitazione è l'approfondimento dei sottoprogrammi, o metodi (illustrati nel capitolo 5).
Raccomandazioni: Ove non altrimenti indicato, rispondete alle domande prima ragionando su carta e poi provando a editare, compilare ed eseguire. Come vedrete, per poter lavorare sui metodi è indispensabile conoscere le strutture di controllo della programmazione strutturata, e gli array, visti nelle lezioni ed esercitazioni precedenti. Gli esercizi etichettati con l'asterisco (*) sono più difficili: affrontateli dopo aver risolto gli altri.
Obiettivo: Comprendere i meccanismi di base del funzionamento dei metodi. Questi sono tutti esercizi molto semplici, che tutti dovete sapere svolgere.
Attività:
class Metodi1 { static void m1() { System.out.println(" Prima di chiamare m3"); m3(); System.out.println(" Dopo aver chiamato m3"); } static void m2() { System.out.println(" Prima di chiamare m1"); m1(); System.out.println(" Dopo aver chiamato m1"); } static void m3() { int y; System.out.println(" Prima di chiamare m4 con parametro 2"); y = m4(2); System.out.println(" Dopo aver chiamato m4. Risultato: " + y); } static int m4(int x) { return x + 1; } public static void main(String[] args){ System.out.println("Prima di chiamare m2"); m2(); System.out.println("Dopo aver chiamato m2"); } }
m1
(e poi m3
e m4
, quindi senza
m2
)? (bisogna modificare un'unica istruzione)m1
, poi
m2
, poi e m3
, e poi m4
,
modificando solo alcune istruzioni di chiamata (servono solo 3 minime
modifiche al programma originale)? m
invoca un altro
metodo n
, l'esecuzione di n
deve terminare
prima dell'esecuzione di m
. In altri termini: l'ultimo
invocato è il primo a terminare (LIFO, Last In First Out...).EasyIn.readInt()
è una procedura o una
funzione? E il metodo Math.sin()
?class Metodi2 { static void m(int x) { System.out.println("m invocato con parametro attuale: " + x); } public static void main(String[] args){ int y; int[] a = new int[2]; y = 5; a[1] = 8; m(y); m(y+1); m(a[1]); m(2*4+3); y = EasyIn.readInt(); m(y); } }Come potete vedere, come parametro attuale si può usare una qualsiasi espressione (purché sia del tipo corretto).
y =
EasyIn.readInt();
): cosa succede? Perché? Perché
invece nella riga precedente m(2*4+3)
si può
invocare m
con, come parametro attuale la stessa
espressione? Che differenza c'è? Chi è che valuta
quell'espressione nei due casi?class Metodi3 { static void m1(int x) { System.out.println("Metodo m1. Paramtro: " + x); } public static void main (String[] args) { int a; int b; boolean p; double x; a = 2; p = true; x = 2.0; m1(a); b = m1(a); m1(b); m1(p); m1(x); } }Studiate i messaggi di errore, cercando di capirli.
m1
con la seguente:
static int m1(int x) { System.out.println("Metodo m1. Parametro: " + x); return x; }(ora
m1()
è una funzione). Notate che il
compilatore vi consente di invocare una funzione (un metodo che
restituisce un valore) senza assegnare a nulla il valore restituito:
non vi è nessun errore, ad esempio, alla riga
m1(a);
. È comunque un esempio di cattiva
programmazione: evitatelo.
return
dal
metodo m1
? Come vedete, la distinzione fra procedure e
funzioni è piuttosto sfuocata...m1
così:
static int m1(double x) { System.out.println("Metodo m1. Parametro: " + x); return 23; }Come vedete vi è una promozione automatica del parametro attuale
int
al parametro formale double
.m1
così:
static double m1(double x) { System.out.println("Metodo m1. Parametro: " + x); return 23; }
m1
così:
static boolean m1(boolean x) { System.out.println("Metodo m1. Parametro: " + x); return 23; }
Riassumendo: la distinzione fra procedure e funzioni è un po' sfuocata (ma dove ci vuole una funzione non si può mettere una procedura!). Il controllo dei tipi è invece piuttosto rigido.
Obiettivo: Comprendere il passaggio parametri per valore.
Attività:
class Azzera { public static void main(String[] args) { int x; x = 1; System.out.println(x); azzera(x); System.out.println(x); } static void azzera(int x) { x = 0; } }(Come abbiamo visto a lezione, bisognerebbe definire il metodo
azzera()
come funzione... se non ve lo ricordate,
rivedetelo...)class Azzera { public static void main(String[] args) { int[] a = {0, 1, 2, 3, 4}; for (int i = 0; i < a.length; i++) System.out.println(a[i]); for (int i = 0; i < a.length; i++) azzera(a[i]); for (int i = 0; i < a.length; i++) System.out.println(a[i]); } static void azzera(int x) { x = 0; } }
class Azzera { public static void main(String[] args) { int[] a = {0, 1, 2, 3, 4}; for (int i = 0; i < a.length; i++) System.out.println(a[i]); azzera(a); for (int i = 0; i < a.length; i++) System.out.println(a[i]); } static void azzera(int x) { x = 0; } }
Obiettivo: Comprendere la visibilità delle variabili.
Attività: Riprendiamo l'esercizio precedente e vediamone alcune varianti.
x
in una variabile di classe?
(rispondete senza eseguire e poi verificate)
class Azzera { static int x; public static void main(String[] args) { x = 1; System.out.println(x); azzera(x); System.out.println(x); } static void azzera(int x) { x = 0; } }
azzera()
rimuovendone l'argomento? (rispondete
senza eseguire e poi verificate)
class Azzera { static int x; public static void main(String[] args) { x = 1; System.out.println(x); azzera(); System.out.println(x); } static void azzera() { x = 0; } }
Obiettivo: Saper usare le funzioni.
Attività:
class Calcola { public static void main(String[] args) { int x; x = somma(2,3); System.out.println(x); x = sottrai(x,1); System.out.println(x); } static int somma(int x, int y) { return x+y; } static int sottrai(int x, int y) { return x-y; } }Senza utilizzare una seconda variabile e senza utilizzare gli operatori aritmetici, ma solo le funzioni
somma
e
sottrai
, fate in modo che x
contenga il
risultato di 45-(32+9)
(ovviamente non dovete fare i
conti voi!). (insomma, dovete scrivere un'unica istruzione di
assegnamento, con le opportune invocazioni alle funzioni
somma
e sottrai
)x
contenga il risultato di
(12+6)-(22-9)
.somma
static void somma(int x, int y) { System.out.println((x+y)); }è ancora possibile ottenere gli stessi risultati? Perché?
Obiettivo: Uso dei metodi.
Attività:
class Radice { public static void main(String[] args) { int n; n = EasyIn.readInt(); for (int i = 0; i <= n; i++) { System.out.println(radice(i)); } } static int radice(int x) { // COMPLETARE QUI } }
a
(che è in una variabile di
classe, o "globale") è palindromo. Cosa c'è di sbagliato
in questo programma? (Nella prossima esercitazione lo riscriveremo in
forma corretta.)
class Palindromo { static int[] a; public static void main(String[] args) { int n; n = EasyIn.readInt(); a = new int[n]; for (int i = 0; i < a.length; i++) { System.out.print("a[" + i + "] = "); a[i] = EasyIn.readInt(); } if (palindromo()) System.out.println("Array palindromo"); else System.out.println("Array non palindromo"); } static boolean palindromo() { return true; } }