Aliasing in Java: riferimenti, memoria ed esempi svolti

L’aliasing in Java si verifica quando due o più variabili di riferimento indicano lo stesso oggetto. È uno degli argomenti più importanti della programmazione a oggetti: molti errori nascono dal credere che assegnare una variabile a un’altra produca una copia dell’oggetto.

Classe, oggetto e riferimento: il ripasso indispensabile

Una classe descrive la struttura e le operazioni di un tipo; un oggetto è un’istanza creata durante l’esecuzione; una variabile di riferimento consente di raggiungere quell’istanza. Quando scriviamo Scatola a = new Scatola();, new crea un oggetto e a ne contiene il riferimento, non l’oggetto completo.

Esempio completo: due variabili, un solo oggetto

class Scatola {
    int valore;
}

public class Main {
    public static void main(String[] args) {
        Scatola a = new Scatola();
        a.valore = 10;

        Scatola b = a;    // Copia del riferimento, NON dell'oggetto
        b.valore = 25;

        System.out.println(a.valore); // 25
        System.out.println(b.valore); // 25
        System.out.println(a == b);   // true
    }
}

Perché anche a.valore diventa 25? L’istruzione Scatola b = a copia il riferimento. a e b sono due variabili diverse, ma raggiungono un unico oggetto. La scrittura tramite b aggiorna lo stato osservato anche da a.

Traccia di esecuzione: cosa cambia in memoria

IstruzioneOggetti creatiab
new Scatola()1riferimento all’oggetto 1non dichiarata
a.valore = 101oggetto 1: valore 10non dichiarata
Scatola b = a1oggetto 1: valore 10oggetto 1: valore 10
b.valore = 251oggetto 1: valore 25oggetto 1: valore 25
L’assegnazione tra variabili di riferimento non aumenta il numero di oggetti.

Confronto: due oggetti distinti con lo stesso valore

Scatola a = new Scatola();
Scatola b = new Scatola();
a.valore = 25;
b.valore = 25;

System.out.println(a == b);             // false
System.out.println(a.valore == b.valore); // true

In questo secondo esempio ci sono due chiamate a new: perciò gli oggetti sono distinti, anche se hanno attributi uguali. L’operatore ==, quando applicato a due riferimenti di oggetti, confronta l’identità del riferimento. Per confrontare contenuti di oggetti, quando previsto dal tipo, si usa un metodo equals() appropriato.

Un secondo errore frequente: riassegnare il riferimento

Scatola a = new Scatola();
a.valore = 10;
Scatola b = a;

b = new Scatola();  // Ora b indica un secondo oggetto
b.valore = 99;

System.out.println(a.valore); // 10
System.out.println(b.valore); // 99
System.out.println(a == b);   // false

Riassegnare b non modifica automaticamente a. L’aliasing termina per quelle due variabili quando non puntano più allo stesso oggetto. L’oggetto precedente continua a esistere finché è raggiungibile: qui lo è tramite a.

Aliasing e passaggio dei parametri

Java passa sempre gli argomenti per valore. Se l’argomento è un riferimento, il metodo riceve una copia del riferimento: può modificare lo stato dell’oggetto, ma assegnare un nuovo oggetto al parametro non riassegna la variabile del chiamante.

class Scatola {
    int valore;
}

public class Main {
    static void cambia(Scatola x) {
        x.valore = 50;      // Modifica l'oggetto condiviso
        x = new Scatola();  // Riassegna solo il parametro locale
        x.valore = 100;
    }

    public static void main(String[] args) {
        Scatola s = new Scatola();
        s.valore = 5;
        cambia(s);
        System.out.println(s.valore); // 50, non 100
    }
}

Esercizi sull’aliasing in Java

  • Prevedi l’output: Contatore b = a; b.valore++;. Cosa mostra a.valore se inizialmente vale 3?
  • Individua gli oggetti: in Libro a = new Libro(); Libro b = a; Libro c = new Libro();, quante istanze sono state create?
  • Spiega: perché a == b può essere falso anche quando gli attributi hanno gli stessi valori?
  • Modifica il programma: crea un secondo oggetto e verifica che lo stato dei due oggetti cambi in modo indipendente.

Soluzioni ragionate

Nel primo esercizio il valore osservato tramite a diventa 4 perché a e b sono alias. Nel secondo esercizio gli oggetti creati sono 2: solo le istruzioni con new costruiscono nuove istanze. Nel terzo, == verifica se i riferimenti indicano lo stesso oggetto, non se i campi hanno valori uguali.

Nel percorso OOP: Torna all’indice delle lezioni Java · Ripassa classi e oggetti.