Metodi
Un meccanismo indispensabile per gestire problemi complessi è la scomposizione in sottoproblemi. Questa politica applicata alla programmazione dei calcolatori consiste nella suddivisione di un programma in sottoprogrammi.
Un sottoprogramma è un insieme finito di istruzioni che svolgono una determinata azione e possono essere richiamati più volte per operare su dati diversi.
Un metodo, è l'unico costrutto in Java che permette di codificare una parte dell'elaborazione andando a costituire di fatto un sottoprogramma.
Un metodo si comporta esattamente come una funzione, nelle stesse modalità già viste per il linguaggio C/C++.
Una funzione riceve un insieme di dati in ingresso, calcola un risultato
e lo restituisce in uscita al programma chiamante. Il tipo di dato restituito
deve precedere il nome della funzione. I dati di input sono chiamati parametri
formali , sono compresi tra parentesi tonde, specificati per tipo
e separati da una virgola. Il corpo della funzione è racchiuso in una coppia
di parentesi graffe, al suo interno il dato da restituire al programma chiamante
deve essere preceduto dall'istruzione return.
Qui un esempio per il calcolo dell'area di un rettangolo:
class rett{
public static void main (String[] args) {
int base=3, alt=2, area;
area=sup(base,alt);
System.out.println("area :"+area);
}//fine main
static int sup(int b, int h){
int a=b*h;
return a;
}//fine sup
}//fine classe
Nell'intestazione del metodo si riconosce il nome (identificatore del metodo),
il tipo di dato restituito e i parametri formali (segnatura
o firma del metodo).
Il modificatore static può essere presente
o meno a secondo che si tratti di un metodo statico (metodo di classe) o
un metodo di istanza.
Nel corpo del programma notiamo che una variabile dello stesso tipo del
metodo si occupa di ricevere il risultato elaborato dal metodo che viene
contestualmente invocato.
Alla fine del metodo si vede l'istruzione return
che restituisce il dato richiesto al programma chiamante.
Il modificatore static viene usato per definire
la visibilità di un metodo (altri modificatori come public, private
protected hanno lo stesso scopo). Per impostare una programmazione procedurale
(o funzionale come in C, Pascal o JavaScript) è sufficiente utilizzare metodi
statici collocati prima della chiusura della stessa classe che li sta usando.
class rett{
public static void main (String[] args) {
int base=3, alt=2, area, perimetro;
area=sup(base,alt);
perimetro=peri(base,alt);
System.out.println( "area :"+area);
System.out.println( "perimetro :"+perimetro);
}//fine main
//__>
seguono i metodi statici
static int sup(int b, int h){
int a=b*h;
return a;
}//fine sup
static int peri(int b, int h){
int p=2*b+2*h;
return p;
}//fine sup }//fine
classe
I metodi statici possono essere direttamente
richiamati nella classe in cui sono dichiarati (senza creare nuovi oggetti
di quella classe). A differenza dei metodi statici, i metodi non-statici,
per essere richiamati, hanno bisogno che venga istanziato un oggetto della
classe cui appartengono. come dimostra i seguente listato:
class staticoNonStatico{
public static void main (String[] args) {
A.suonoStatico();//OK
A.suonoNonStatico();//errore per contesto
statico
A a=new A();//istanziazione dell'oggetto
a.suonoNonStatico();//OK
}//fine main
}//fine classe
class A {
void suonoNonStatico(){
System.out.println("HONK! non statico");
}//fine metodo non statico
static void suonoStatico(){
System.out.println("HONK! statico");
}//fine metodo statico
}//fine classe A
Oltre ai metodi statici esistono anche attributi statici denominati anche variabili di classe, in contrapposizione agli attributi non statici denominati anche variabili d'istanza.
Una variabile static viene inizializzata solo la prima volta che si esegue la funzione in cui è presente e alla fine di tale funzione non viene "cancellata": il suo valore rimane in memoria, quindi la seconda volta che chiami la funzione essa avrà il valore che le era stato dato in precedenza come notiamo nel seguente programma:
class suoni{
public static void main (String[] args) {
T a=new T("auto");//istanziazione degli oggetti
T c=new T("camion");
a.suona();
c.suona();
a.suona();
System.out.println("num.suoni :"+T.cnt);
}//fine main
}//fine classe
class T {
static int cnt;//contatore attributo statico
String veicolo;//attributo non statico
T(String v){veicolo=v;}
void suona(){
cnt++;
System.out.println("HONK! "+veicolo);
}//fine metodo non statico
static {//inizializzatore statico
cnt=0;
System.out.println("contatore azzerato");
}
}//fine classe A
Metodi void
Un metodo che non restituisce alcun risultato deve essere dichiarato di tipo void il suo significato è dunque in stretta analogia con le funzioni void del C/C++ o delle procedure VB o Pascal.
class staticoVoid{
public static void main (String[] args) {
suonoStatico();//invocazione del metodo
}//fine main
static void suonoStatico(){
System.out.println("HONK! statico");
}//fine metodo statico
}//fine classe
come si vede dallo scritto, nel punto della chiamata al metodo non è indispensabile
predisporre alcuna variabile in ricezione ad un eventuale risultato restituito
dal metodo stesso;
suonoStatico();//invocazione del metodo
inoltre, nel corpo del metodo, l'istruzione return è opzionale e anche qualora
la si usasse ad essa non dovrebbe seguire alcuna variabile (perché non c'è
niente da restituire).
Il passaggio dei parametri avviene sempre per valore nel caso dei tipi di dati primitivi (int, char, double…) mentre avviene sempre per indirizzo (per referenza) nel caso degli oggetti; quindi anche nel caso dei vettori e delle stringhe, dato che in Java i vettori (array) e stringhe sono oggetti.
Vettori
Un vettore è una struttura di dati omogenei (dello stesso tipo) memorizzati in locazioni contigue di memoria. Ognuno dei valori è memorizzato in una locazione del vettore . Per accedere a ogni locazione si usa un indice (un valore numerico): la prima locazione ha indice 0, la seconda 1 e così via . Ad es.
int A[];//dichiarazione
A = new int[5];//allocazione
Definisce un vettore di 5 numeri interi.
Spesso dichiarazione e allocazione vengono effettuate insieme:
int A[] = new int[5];
È inoltre possibile assegnare, all 'atto della dichiarazione-allocazione,
i valori iniziali del vettore (inizializzazione):
int A[]={2, 9, 4, 7, 3};
La lunghezza di un vettore (il numero di elementi) è ottenibile posponendo
al nome del vettore un punto e la parola length.
System.out.println(A. length);
restituisce 5 in output. È ovvio che l'indicizzazione del vettore avviene
tra 0 e A.length-1 . In ragione
di ciò è possibile eseguire la scansione del vettore, tramite il ciclo for,
evitando la dichiarazione di una costante globale che contenga il numero
di elementi del vettore.
for (int i=0; i < A.length - 1; i++) System.out.println(A[i]);
Come esempio riportiamo il caricamento da programma
di un vettore
class caricamentoDaProgramma {
public static void main (String[] args) {
int i; int A[]={2,9,4,7,3};
//stampa
for(i=0;i < A.length;i++) System.out.print(" "+A[i]);
}//fine main
}//fine class
In questo listato, il caricamento random
con interi da 1 a 9 compresi:
class caricamentoRandom{
public static void main (String[] args) {
int i; int A[] = new int[5]; //caricamento
for(i=0;i < A.length;i++)
A[i]=(1+(int)(Math.random()* 9));
//stampa
for(i=0;i < A.length;i++)System.out.print(" "+A[i]);
}//fine main
}//fine class
In questo listato, il caricamento da tastiera:
import java.util.Scanner;
class caricamentoTastiera {
public static void main (String[] args){
Scanner in=new Scanner(System.in);
int i; int A[] = new int[5];
//caricamento
for(i=0;i < A.length;i++){
System.out.print("ins "+(i+1)+"°:");
A[i]=in.nextInt();
}//fine for
in.close();
//stampa
for(i=0;i < A.length;i++)System.out.print(" "+A[i]);
}//fine main
}//fine class
La scansione di un vettore avviene obbligatoriamente con un ciclo for
tradizionale con una variable di controllo i che
parte da 0 e si incrementa rispettando i confini dell'array (i<T[i].length).
Alternativamente si può usare un ciclo for each,
come si vede nel seguente programma:
class foreach {
public static void main(String[] args) {
int T[]={2, 9, 4, 7, 3};
//ciclo for tradizionale
for(int i=0;i<T.length;i++)System.out.print(T[i]+" ");
System.out.println("");
//ciclo for-each (per tipi tipi primitivi)
for(int i:T)System.out.print(i+" ");
}//fine__main
}//fine class
Come si vede il ciclo for each rispetta la sintassi
for (tipo var : nomeArray) {
...//corpo del ciclo
}
Il ciclo for each può essere facilmente scritto
anche se il vettore non contiene tipi di dati primitivi (ad es. interi come
nel caso precedente). Esso funziona anche nel caso si abbia un array di
oggetti (in questo caso un oggetto frazione F).
class fraz_a {
public static void main(String[] args) {
//creo un vettore di 3 elementi di classe F
F T[] = new F[3];
T[0] = new F(1, 3);// 1/3
T[1] = new F(5, 2);// 5/2
T[2] = new F(3, 4);// 3/4
//ciclo for tradizionale
for(int i=0;i<T.length;i++)System.out.print(T[i]+" ");
System.out.println();
//ciclo for-each per gli oggetti
for(F i:T)System.out.print(i+" ");
}//fine__main
}//fine classe
class F {
private int n,d;//attributi privati
F(int x, int y) {
n=Math.abs(x);
d=Math.abs(y);
}//costruttore
public String toString(){
String st = n+"/"+d;
return st;
}//fine toString
}//fine classe F
Matrici
Una matrice è un vettore a due dimensioni costituito da un cero numero
di righe e di colonne.
Noi indicizziamo le righe con la variabile i e le
colonne con la j.
Per dichiarare la una matrice a 4 righe e 3 colonne usiamo:
int A[][] = new int[4][3];
Bisogna ricordarsi che la scansione della matrice avviene tecnicamente, usando due cicli for annidati come emerge dal seguente listato che illustra il caricamento da tastiera di una matrice 3x3.
import java.util.Scanner;
class matriceTastiera {
public static void main (String args []){
Scanner in=new Scanner(System.in);
int i,j;
int A[][]= new int[3][3]; //caricamento
for(i=0;i < A.length;i++)
for(j=0;j < A.length;j++){
System.out.print("riga:"+(i+1)+" colonna "+(j+1)+":");
A[i][j]=in.nextInt();
}//fine for j
in.close();
//stampa
for(i=0;i < A.length;i++){
for(j=0;j < A.length;j++)System.out.print(A[i][j]+" ");
System.out.println();
}//fine for i
}//fine main
}// fine classe
Qui il caricamento random di una matrice 4x3.
class matriceRandom{
public static void main (String[] args) {
int i,j; int A[][]= new int[4][3];
//caricamento
for(i=0;i < A.length;i++)
for(j=0;j < A[0].length;j++)A[i][j]=(1+(int)(Math.random()*
9));
//stampa
for(i=0;i < A.length;i++){
for(j=0;j < A[0].length;j++)System.out.print(A[i][j]+"
");
System.out.println();
}//fine for i
}//fine main
}//fine class
Notare come la l'altezza della matrice sia stata dedotta con l'istruzione A[0].length.