edutecnica

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.