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;
}
}