Classi in Java

Vediamo insieme come programmare ad oggetti in Java.

Classi

Un oggetto, in maniera analoga alla vita reale, ha diverse caratteristiche, chiamate attributi; Allo stesso modo può anche svolgere dei compiti, che vengono chiamati metodi.

Attributi e metodi di un oggetto sono definiti in una classe, contente tutte le caratteristiche dell'oggetto. All'interno di una classe dev'essere presente almeno un costruttore, che permette di istanziare un oggetto partendo dalla classe. Il costruttore si riconosce dai metodi perché ha lo stesso nome della classe e non ha valore di ritorno.

Vediamo un esempio di una classe Rettangolo in Java:

public class Rettangolo {

    //attributi
    private double base;
    private double altezza;

    //costruttore
    public Rettangolo(double base, double altezza){

        this.base = base;
        this.altezza = altezza;
    }

    //metodi
    public double area() {
        return base * altezza;
    }

    public double perimetro() {
        return (base + altezza) * 2;
    }
}

Nel costruttore usiamo la keyword this: la usiamo per distinguere tra i parametri del costruttore base e altezza e gli attributi della classe, che hanno lo stesso nome. this fa sempre riferimento a attributi e metodi della classe dove viene usato.

Qui la classe Rettangolo, il suo costruttore e i suoi metodi usano la parola chiave public, in modo da poter essere utilizzati da altri elementi esterni alla classe Rettangolo, come il main del nostro programma. base e altezza invece sono private, cioè non possono essere utilizzati al di fuori di rettangolo.

Proviamo adesso ad utilizzarla nel Main:

public class Main {

    public static void main(String[] args) {

        //istanzio r1
        Rettangolo r1 = new Rettangolo(10, 20);

        System.out.println("Rettangolo 1 -> Area: " + r1.area() + " Perimetro: "+ r1.perimetro());

        //istanzio r2
        Rettangolo r2 = new Rettangolo(5, 4);

        System.out.println("Rettangolo 2 -> Area: " + r2.area() + " Perimetro: "+ r2.perimetro());

    }
}
Rettangolo 1 -> Area: 200.0 Perimetro: 60.0
Rettangolo 2 -> Area: 20.0 Perimetro: 18.0

Istanze di oggetti

Siccome la classe Rettangolo è solamente un modello di oggetto non possiamo usarla direttamente, dobbiamo istanziare, cioè creare allocando in memoria, degli oggetti di tipo Rettangolo; per farlo usiamo la keyword new e il costruttore della classe Rettangolo.

r1 e r2 sono due oggetti di tipo Rettangolo. Appartengono alla stessa classe ma sono due istanze diverse, cioè hanno gli stessi attributi e metodi, ma contenenti valori diversi. Se gli attributi base e altezza fossero identici tra le due istanze, allora r1.area() e r2.area() ritornerebbero lo stesso valore.

Per dimostrare che r1 e r2 sono effettivamente indipendenti l'uno dall'altro e non che non sono collegati in nessun modo, aggiungiamo le seguenti righe per andare a modificare gli attributi di Rettangolo.

public double getBase() {
    return base;
}

public double getAltezza() {
    return altezza;
}


public void setBase(double Base) {
    this.base = base;
}

public void setAltezza(double altezza) {
    this.altezza = altezza;
}

Le prime due funzioni ci permettono di leggere il valore dei due attributi privati e vengono chiamate getter, le ultime due invece ci permettono di cambiarne il valore e vengono chiamate setter.

Modifichiamo il main e vediamo il risultato:

public class Main {

    public static void main(String[] args) {

        Rettangolo r1 = new Rettangolo(10, 20);
        Rettangolo r2 = new Rettangolo(5, 4);

        r1.setAltezza(200);

        r2.setBase(30);

        System.out.println("Rettangolo 1 -> Altezza: " + r1.getAltezza() + " Base: " + r1.getBase());
        System.out.println("Rettangolo 2 -> Altezza: " + r2.getAltezza() + " Base: " + r2.getBase());

    }
}
Rettangolo 1 -> Altezza: 200.0 Base: 10.0
Rettangolo 2 -> Altezza: 4.0 Base: 30.0

Possiamo vedere che solo l'altezza di r1 è cambiata e non quella di r2, come è cambiata solo la base di r2 e non quella di r1. Questo conferma che due istanze di un oggetto sono separate tra loro.

Attributi e Metodi Statici

Può darsi che la nostra classe abbia bisogno di un particolare metodo o attributo il cui valore debba essere lo stesso in tutte le istanze della classe. Nel nostro caso sarebbe utile aggiungere un attributo che indichi l'unità di misura utilizzata da Rettangolo, che sia però consistente tra tutti gli oggetti istanziati.

Usando la keyword static possiamo fare in modo che l'unità di misura sia istanziata una sola volta e tutti gli oggetti istanziati vi facciano riferimento, vediamo come:

public class Rettangolo {

    //attributi
    //...
    private static String unitaDiMisura = "cm";

    //metodi
    //...
    public static void setUnitaDiMisura(String unitaDiMisura){
        this.unitaDiMisura = unitaDiMisura;
    }

    public static String getUnitaDiMisura(){
        return unitaDiMisura;
    }
}
public class Main {

    public static void main(String[] args) {

        Rettangolo r1 = new Rettangolo(10, 20);
        Rettangolo r2 = new Rettangolo(5, 4);

        Rettangolo.setUnitaDiMisura("mm");

        System.out.println("Unità di misura: " + Rettangolo.getUnitaDiMisura());

    }
}

Metodi e attributi statici vengono chiamati facendo riferimento al nome della classe, non a quello dell'istanza.

UML

Il linguaggio UML viene utilizzato per rappresentare diversi aspetti di un software, tra cui la gerarchia delle classi.

La classe Rettangolo in UML verrebbe rappresentata nel seguente modo.

uml

Nella prima sezione abbiamo il nome della classe, Rettangolo.

Nella seconda sezione ci sono gli attributi, sono preceduti da un - perché privati.

Nelle ultime sezione vengono aggiunti i metodi e i costruttori, sono tutti preceduti da un + perché di visibilità pubblica.

Metodi e attributi statici vengono sottolineati.

© Nicola Bovolato 2020