W3docs

Classi e Oggetti in Java

Definisci una classe Java e crea oggetti (istanze) da essa — il fondamento del modello orientato agli oggetti di Java.

Una classe è una definizione; un oggetto è un'istanza di quella definizione che esiste a runtime. La classe descrive com'è fatto un cane e cosa sa fare; un oggetto è Rex, un cane specifico che vive in memoria mentre il programma è in esecuzione. Tutto quello che segue si basa su questa distinzione.

Definire una classe

La definizione di una classe risiede nel proprio file .java, il cui nome corrisponde a quello della classe. Il corpo contiene campi (i dati che ogni istanza porta con sé) e metodi (il comportamento che ogni istanza può eseguire).

public class Dog {
  String name;
  int    age;

  void describe() {
    System.out.println(name + ", age " + age);
  }
}

Questo dichiara un tipo. Non crea alcun cane — esattamente come scrivere int non crea un intero.

Creare un oggetto con new

La parola chiave new chiede alla JVM di allocare spazio per un'istanza e restituire un riferimento ad essa:

Dog d = new Dog();

Su quella riga accadono tre cose:

  1. Allocazione. La JVM trova spazio nell'heap sufficiente per un Dog.
  2. Inizializzazione predefinita. Ogni campo riceve un valore predefinito — null per gli oggetti, 0 per gli int, false per i boolean.
  3. Chiamata al costruttore. Le () invocano un costruttore. Non ne abbiamo scritto uno, quindi Java ne ha fornito uno predefinito senza argomenti che non fa nulla di extra. Il prossimo capitolo sui costruttori tratta la scrittura dei propri.

Dopo questa riga, d contiene un riferimento — un piccolo valore che punta all'oggetto nell'heap. L'oggetto stesso è la cosa più grande nell'heap.

Leggere e scrivere i campi

Si accede a un campo scrivendo <riferimento>.<campo>:

d.name = "Rex";
d.age  = 3;
System.out.println(d.name);   // Rex

L'accesso ai campi funziona anche per chiamare i metodi:

d.describe();    // Rex, age 3

Il punto è lo stesso in entrambi i casi; se il lato destro è un campo o un metodo dipende semplicemente da ciò che segue.

I riferimenti non sono l'oggetto

Questa è la frase più importante di questo capitolo: una variabile di tipo classe contiene un riferimento, non l'oggetto stesso.

Dog a = new Dog();
a.name = "Rex";

Dog b = a;           // copies the REFERENCE, not the dog
b.name = "Buddy";

System.out.println(a.name);   // Buddy

a e b puntano allo stesso oggetto nell'heap, quindi modificarlo attraverso uno è visibile attraverso l'altro. Confronta con i primitivi:

int x = 5;
int y = x;       // copies the value
y = 9;
System.out.println(x);    // still 5

x e y sono indipendenti — i primitivi vengono copiati per valore. Il capitolo sul passaggio per valore approfondisce ciò che questo significa per gli argomenti dei metodi.

null e NullPointerException

Una variabile di riferimento può essere null, cioè "non punta ad alcun oggetto":

Dog d = null;
d.describe();    // NullPointerException

null è ciò che si ottiene se non si è mai assegnato un oggetto, o se un campo di tipo oggetto non è stato mai inizializzato esplicitamente. Dereferenziare null (scrivere d.qualcosa quando d == null) lancia una NullPointerException a runtime. Scrivere codice che non esplode su null è metà della programmazione Java pratica.

Attenzione
NullPointerException è un errore a runtime, non un errore di compilazione — il codice compila correttamente e fallisce solo quando quella riga viene effettivamente eseguita. La soluzione è assicurarsi che la variabile punti a un oggetto reale (d = new Dog();) o proteggersi con un controllo (if (d != null) d.describe();) prima di dereferenziarla.

Confrontare oggetti: == vs equals

Per i riferimenti, == chiede "queste due variabili puntano allo stesso oggetto?":

Dog a = new Dog();
Dog b = new Dog();
Dog c = a;

System.out.println(a == b);   // false — different objects
System.out.println(a == c);   // true  — same object

Se si vuole confrontare il contenuto di due oggetti, si chiama invece un metodo equals — ogni classe ne eredita uno predefinito da Object, ma quello predefinito si comporta come l'uguaglianza per riferimento. Si sovrascrive equals per dargli il significato desiderato; vedi il capitolo su equals & hashCode più avanti in questa parte.

Un file, molti oggetti

Una singola definizione di classe supporta istanze illimitate. Condividono tutte il layout ma ognuna ha il proprio stato:

Dog rex   = new Dog();   rex.name   = "Rex";   rex.age   = 3;
Dog molly = new Dog();   molly.name = "Molly"; molly.age = 7;

rex.describe();     // Rex, age 3
molly.describe();   // Molly, age 7

Un metodo come describe legge da this — l'oggetto su cui è stato chiamato — quindi lo stesso codice stampa output diversi a seconda dell'istanza su cui lo si chiama.

Dove vivono le classi

Un file .java che dichiara public class Dog deve chiamarsi Dog.java. Puoi avere classi non pubbliche nello stesso file, ma solo una classe public per file, il cui nome deve corrispondere al nome del file. Per i piccoli programmi di questo capitolo spesso inseriremo classi ausiliarie nello stesso file di main usando classi annidate static, solo per mantenere l'esempio in un unico file.

Un esempio pratico

java— editable, runs on the server

Cosa c'è dopo

Sai dichiarare una classe e istanziarla, ma finora l'unico campo scritto era "qualsiasi valore va bene." Il prossimo capitolo sugli attributi delle classi tratta i campi in modo approfondito — dichiarazione, valori predefiniti, scope dell'istanza vs della classe e le convenzioni seguite dal codice Java.

Esercitazione

Pratica
Dato Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — cosa stampa System.out.println(a.name)?
Dato Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — cosa stampa System.out.println(a.name)?
Was this page helpful?