Programmazione Orientata agli Oggetti
La Programmazione Orientata agli Oggetti (OOP) è un paradigma che modella il software come una collezione di oggetti che interagiscono tra loro. Ogni oggetto rappresenta un'entità del mondo reale con stato (attributi) e comportamento (metodi).
Cosa Imparerai
- Cos'è una classe e cos'è un oggetto
- Stato e comportamento
- Costruttori e inizializzazione
- Incapsulamento e modificatori di accesso
- La parola chiave this
- Membri statici vs di istanza
Classi e Oggetti
Definizioni Chiave
- Classe: Un modello (blueprint) che definisce attributi e metodi
- Oggetto: Un'istanza di una classe, un'entità concreta in memoria
- Attributi: Variabili che rappresentano lo stato dell'oggetto
- Metodi: Funzioni che definiscono il comportamento dell'oggetto
// Definizione della classe
public class Studente {
// Attributi (stato)
String nome;
String cognome;
int matricola;
int annoCorso;
double mediaVoti;
// Metodi (comportamento)
void presentati() {
System.out.println("Ciao, sono " + nome + " " + cognome);
System.out.println("Matricola: " + matricola);
}
void studiaMateria(String materia) {
System.out.println(nome + " sta studiando " + materia);
}
boolean isFuoriCorso() {
return annoCorso > 3;
}
}
public class Main {
public static void main(String[] args) {
// Creazione oggetto con new
Studente mario = new Studente();
// Assegnazione attributi
mario.nome = "Mario";
mario.cognome = "Rossi";
mario.matricola = 123456;
mario.annoCorso = 2;
mario.mediaVoti = 27.5;
// Chiamata metodi
mario.presentati();
mario.studiaMateria("Programmazione");
// Creare più oggetti dalla stessa classe
Studente luigi = new Studente();
luigi.nome = "Luigi";
luigi.cognome = "Verdi";
luigi.matricola = 789012;
// Ogni oggetto ha il proprio stato
System.out.println(mario.nome); // Mario
System.out.println(luigi.nome); // Luigi
}
}
Costruttori
Un costruttore e un metodo speciale chiamato quando si crea
un oggetto con new. Permette di inizializzare l'oggetto.
public class Studente {
String nome;
String cognome;
int matricola;
int annoCorso;
// Costruttore di default (senza parametri)
public Studente() {
this.annoCorso = 1; // valore predefinito
}
// Costruttore con parametri
public Studente(String nome, String cognome, int matricola) {
this.nome = nome;
this.cognome = cognome;
this.matricola = matricola;
this.annoCorso = 1;
}
// Costruttore completo
public Studente(String nome, String cognome, int matricola, int annoCorso) {
this.nome = nome;
this.cognome = cognome;
this.matricola = matricola;
this.annoCorso = annoCorso;
}
}
// Utilizzo dei costruttori
Studente s1 = new Studente(); // costruttore di default
Studente s2 = new Studente("Mario", "Rossi", 123456); // costruttore con 3 parametri
Studente s3 = new Studente("Luigi", "Verdi", 789012, 2); // costruttore completo
Regole sui Costruttori
- Il nome del costruttore deve essere identico al nome della classe
- Non ha tipo di ritorno (nemmeno void)
- Se non definisci nessun costruttore, Java crea un costruttore di default vuoto
- Se definisci un costruttore con parametri, il costruttore di default non viene più creato automaticamente
Incapsulamento
L'incapsulamento protegge i dati di un oggetto nascondendoli dall'esterno e fornendo metodi controllati per accedervi (getter/setter).
public class ContoBancario {
// private: accessibile solo dentro la classe
private double saldo;
private String intestatario;
// public: accessibile da ovunque
public ContoBancario(String intestatario, double saldoIniziale) {
this.intestatario = intestatario;
this.saldo = saldoIniziale;
}
// Getter: permette di LEGGERE il valore
public double getSaldo() {
return saldo;
}
public String getIntestatario() {
return intestatario;
}
// Setter con validazione
public void deposita(double importo) {
if (importo > 0) {
saldo += importo;
System.out.println("Depositati €" + importo);
} else {
System.out.println("Importo non valido");
}
}
public boolean preleva(double importo) {
if (importo > 0 && importo <= saldo) {
saldo -= importo;
System.out.println("Prelevati €" + importo);
return true;
}
System.out.println("Prelievo non autorizzato");
return false;
}
}
Modificatori di Accesso
| Modificatore | Classe | Package | Sottoclasse | Ovunque |
|---|---|---|---|---|
| private | ✅ | ❌ | ❌ | ❌ |
| (default) | ✅ | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
La Parola Chiave this
public class Corso {
private String nome;
private int crediti;
private Docente docente;
// this per distinguere parametri da attributi
public Corso(String nome, int crediti) {
this.nome = nome; // this.nome = attributo
this.crediti = crediti; // nome = parametro
}
// this per chiamare un altro costruttore
public Corso(String nome) {
this(nome, 6); // chiama il costruttore con 2 parametri
}
// this per passare l'oggetto corrente
public void assegnaDocente(Docente docente) {
this.docente = docente;
docente.aggiungiCorso(this); // passa questo corso al docente
}
// this per catene di metodi (fluent interface)
public Corso conCrediti(int crediti) {
this.crediti = crediti;
return this;
}
public Corso conDocente(Docente docente) {
this.docente = docente;
return this;
}
}
// Uso fluent interface
Corso corso = new Corso("Programmazione")
.conCrediti(9)
.conDocente(profRossi);
Membri Statici vs Istanza
public class Studente {
// Attributo STATICO: condiviso da tutte le istanze
private static int contatore = 0;
private static final String UNIVERSITA = "Universita di Bologna";
// Attributi di ISTANZA: uno per ogni oggetto
private int matricola;
private String nome;
public Studente(String nome) {
this.nome = nome;
contatore++; // incrementa per ogni nuovo studente
this.matricola = 2024000 + contatore;
}
// Metodo STATICO: appartiene alla classe, non all'istanza
public static int getNumeroStudenti() {
return contatore;
}
public static String getUniversita() {
return UNIVERSITA;
}
// Metodo di ISTANZA: opera su un oggetto specifico
public void presentati() {
System.out.println("Sono " + nome + " di " + UNIVERSITA);
}
}
// Utilizzo
System.out.println(Studente.getUniversita()); // Chiamata statica
Studente s1 = new Studente("Mario");
Studente s2 = new Studente("Luigi");
System.out.println(Studente.getNumeroStudenti()); // 2
s1.presentati(); // Chiamata su istanza
Quando usare static
- Costanti:
static finalper valori immutabili condivisi - Contatori: Per tenere traccia del numero di istanze
- Utility: Metodi che non dipendono dallo stato dell'oggetto (es. Math.sqrt())
- Factory: Metodi che creano istanze della classe
Esempio Completo: Sistema Gestione Corsi
package it.universita.gestione;
public class Studente {
// Attributi statici
private static int contatore = 0;
// Attributi di istanza
private final int matricola;
private String nome;
private String cognome;
private int annoIscrizione;
private double mediaVoti;
private int esamiSostenuti;
// Costruttore
public Studente(String nome, String cognome, int annoIscrizione) {
this.matricola = generaMatricola();
this.nome = nome;
this.cognome = cognome;
this.annoIscrizione = annoIscrizione;
this.mediaVoti = 0;
this.esamiSostenuti = 0;
}
// Metodo statico privato
private static int generaMatricola() {
contatore++;
return 2024000 + contatore;
}
// Getter
public int getMatricola() {
return matricola;
}
public String getNomeCompleto() {
return nome + " " + cognome;
}
public double getMediaVoti() {
return mediaVoti;
}
// Metodo per registrare un esame
public void registraEsame(int voto) {
if (voto >= 18 && voto <= 30) {
double totale = mediaVoti * esamiSostenuti;
esamiSostenuti++;
mediaVoti = (totale + voto) / esamiSostenuti;
System.out.printf("%s ha superato l'esame con %d%n", getNomeCompleto(), voto);
} else {
System.out.println("Voto non valido");
}
}
// Metodo per calcolare l'anno di corso
public int getAnnoCorso() {
int annoCorrente = java.time.Year.now().getValue();
return annoCorrente - annoIscrizione + 1;
}
public boolean isFuoriCorso() {
return getAnnoCorso() > 3;
}
// toString per rappresentazione stringa
@Override
public String toString() {
return String.format("Studente[matricola=%d, nome=%s, media=%.2f, anno=%d]",
matricola, getNomeCompleto(), mediaVoti, getAnnoCorso());
}
// Metodo statico di utilita
public static int getTotaleStudenti() {
return contatore;
}
}
package it.universita.gestione;
public class Esame {
private String nomeCorso;
private int crediti;
private Studente studente;
private int voto;
private boolean lode;
private String data;
public Esame(String nomeCorso, int crediti, Studente studente) {
this.nomeCorso = nomeCorso;
this.crediti = crediti;
this.studente = studente;
}
public void registraVoto(int voto, boolean lode) {
if (voto >= 18 && voto <= 30) {
this.voto = voto;
this.lode = (voto == 30 && lode);
this.data = java.time.LocalDate.now().toString();
studente.registraEsame(voto);
}
}
public String getVotoFormattato() {
if (voto == 0) return "Non sostenuto";
return lode ? "30 e Lode" : String.valueOf(voto);
}
@Override
public String toString() {
return String.format("%s - %s: %s (%d CFU)",
studente.getNomeCompleto(), nomeCorso, getVotoFormattato(), crediti);
}
}
package it.universita.gestione;
public class TestGestione {
public static void main(String[] args) {
// Creazione studenti
Studente mario = new Studente("Mario", "Rossi", 2023);
Studente luigi = new Studente("Luigi", "Verdi", 2022);
// Registrazione esami
Esame esameProgrammazione = new Esame("Programmazione", 9, mario);
esameProgrammazione.registraVoto(28, false);
Esame esameAnalisi = new Esame("Analisi I", 12, mario);
esameAnalisi.registraVoto(30, true);
Esame esameReti = new Esame("Reti", 6, luigi);
esameReti.registraVoto(25, false);
// Stampa situazione
System.out.println("\n=== Situazione Studenti ===");
System.out.println(mario);
System.out.println(luigi);
System.out.println("\n=== Esami Registrati ===");
System.out.println(esameProgrammazione);
System.out.println(esameAnalisi);
System.out.println(esameReti);
System.out.println("\n=== Statistiche ===");
System.out.println("Totale studenti: " + Studente.getTotaleStudenti());
}
}
Conclusione
In questo articolo abbiamo introdotto i concetti fondamentali della OOP: classi, oggetti, costruttori, incapsulamento e membri statici.
Nel prossimo articolo approfondiremo ereditarieta, polimorfismo e interfacce: i pilastri avanzati della programmazione a oggetti.
Punti Chiave da Ricordare
- Classe: Blueprint che definisce attributi e metodi
- Oggetto: Istanza concreta di una classe
- Costruttore: Metodo speciale per inizializzare oggetti
- Incapsulamento: Nascondi i dati, esponi metodi controllati
- this: Riferimento all'oggetto corrente
- static: Appartiene alla classe, non alle istanze







