Java e il passaggio di parametri

Robustezza a parte, una delle qualità di Java, che viene più esaltata è la semplicità. Java è un linguaggio per programmatori creato da programmatori. Gli inventori, hanno cercato, dunque, di venirci incontro, sollevandoci dalla responsabilità di dover gestire fasi di sviluppo in cui è possibile causare errori o peggio ancora bug. Come sappiamo una delle responsabilità più grandi che un programmatore assolve durante la programmazione è la gestione della memoria: allocazione, ridimensionamento (di un array dinamico ad esempio), deallocazione e altro. Un’operazione come la deallocazione (compromettente se gestita male in un qualsiasi linguaggio), in Java è superflua grazie all’introduzione del garbage collector. Il garbage collector, tra le semplificazioni, è solo quella più palese, un’altra delle tante, meno evidente ai più, riguarda il passaggio dei parametri.

Per passaggio di parametri si intende l’operazione tramite cui, durante la fase di definizione di una funzione/metodo associamo ad essa dei parametri formali. Al momento dell’esecuzione del metodo/funzione tali parametri non saranno più parametri formali ma parametri attuali. Il passaggio di parametri ad una funzione, in programmazione, può avvenire in due modi, per valore o per indirizzo. Supponiamo, in questo articolo, di voler realizzare una funzione che prenda in input due variabili e ne scambi il valore. Realizzeremo il tutto in C (dopo spiegherò anche perché C e non Java).

Passaggio di parametri per valore

L’esempio che vogliamo realizzare, è molto semplice, e anche se fossimo dei programmatori alle prime armi non ci porterebbe via molto tempo. Creeremo dunque il nostro programma e all’interno definiremo una funzione chiamata swap che prende come parametri formali due variabili e ne scambia i valori.

#include <stdio.h>

void swap(int, int);

int main()
{
    int x = 2;
    int y = 4;
    printf("output: x=%d, y=%d\n", x, y); // output: x=2, y=4
    swap(x, y); // x e y sono parametri attuali di swap
    printf("output: x=%d, y=%d\n", x, y); // output: x=2, y=4
    return 0;
}

void swap(int a, int b) // a e b sono parametri formali di swap
{
   int tmp;
   tmp = a;
   a = b;
   b = tmp;
}

Come tutti potrete vedere in questo caso le due chiamate alla funzione printf producono lo stesso output anche se tra le due abbiamo chiamato swap. Come è possibile? Un programmatore meno esperto potrebbe pensare che la causa del problema sia che in realtà la funzione swap è scritta male, ma non è questo il punto. I meno fiduciosi possono copiare il corpo della funzione swap ed incollarla tra le due chiamate a printf. Compilando e rieseguendo il programma la seconda printf dimostrerà che lo scambio c’è stato e che quindi la funzione swap era corretta. Cosa c’era allora che non andava? La risposta è intrinseca al meccanismo che i linguaggi di programmazione come il C usano nel passaggio dei parametri. In C, salvo nostre “manipolazioni”, i parametri vengono passati per valore, questo significa che al momento dell’esecuzione della funzione swap i parametri attuali vengono copiati e durante il ciclo di vita di swap saranno sempre e solo le copie ad essere modificate. Al termine di vita della funzione cesseranno di esistere anche le copie dei parametri attuali. La seconda printf confermerà che nulla è cambiato nelle nostre variabili.

Passaggio di parametri per indirizzo (o per riferimento)

Un modo per evitare il problema precedente esiste e fa ricorso all’uso dei puntatori. Grazie ad essi possiamo puntare all’area di memoria (indirizzo) dove sono contenuti i valori delle variabili che vogliamo modificare. A questo punto quando inizierà il ciclo di vita della funzione swap non verranno modificate delle copie dei parametri attuali come avveniva prima, ma il valore contenuto in un indirizzo di memoria. Ecco perché questo passaggio di parametri vien detto “passaggio per indirizzo”. Il nostro programma dovrà essere quindi modificato per assecondare tale logica:

#include <stdio.h>

void swap(int *, int *);

int main()
{
    int x = 2;
    int y = 4;
    printf("output: x=%d, y=%d\n", x, y); // output: x=2, y=4
    swap(&x, &y); // x e y sono parametri attuali di swap e sono gli indirizzi di x e y
    printf("output: x=%d, y=%d\n", x, y); // output: x=4, y=2
    return 0;
}

void swap(int *a, int *b) // a e b sono parametri formali di swap di tipo puntatore a intero
{
   int tmp;
   tmp = *a;
   *a = *b;
   *b = tmp;
}

E per quel che riguarda Java?

Per quel che riguarda Java come al solito c’è qualche mito da sfatare. Il più famoso è quello che sostiene che i tipi primitivi siano passati per valore e gli oggetti per indirizzo. Niente di più errato! E’ corretto dire invece che in Java tutto è passato per valore. Infatti, per rendere il tutto quanto più semplice possibile non esiste il passaggio per riferimento (ecco perchè l’esempio è in C), così come confermato dallo stesso James Gosling, uno degli inventori di Java:

Some people will say incorrectly that objects are passed “by reference.” In programming language design, the term pass by reference properly means that when an argument is passed to a function, the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter, the value in the calling code will be changed because the argument and parameter use the same slot in memory…. The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing mode — pass by value — and that helps keep things simple.

James Gosling – The Java Programming Language, 4th Edition

Facendo 2+2, ne viene che l’unico modo che abbiamo per effettuare uno scambio di variabile in Java è quello di farlo senza usare metodi.

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

Comments

Non c’è ancora nessun commento.

Lascia un commento

(obbligatorio)

(obbligatorio)


*
To prove that you're not a bot, enter this code
Anti-Spam Image