Metodi di Classe Java
Aggiungi metodi di istanza a una classe Java per dare comportamento agli oggetti e operare sui loro campi.
I metodi di una classe sono ciò che conferisce comportamento ai suoi oggetti. I campi definiscono cosa un oggetto è; i metodi descrivono cosa può fare. Fino a ora i metodi che hai scritto erano static — utilità che appartengono alla classe stessa. Questo capitolo riguarda i metodi di istanza, che appartengono a ciascun oggetto e operano sui suoi campi.
Il termine "metodi di classe" in Java è un po' ambiguo. La maggior parte degli autori lo usa per indicare metodi definiti all'interno di una classe — il che include entrambi i tipi. Alcuni lo usano in senso stretto per indicare i metodi static (perché questi appartengono letteralmente alla classe). Tratteremo qui i metodi di istanza, mentre i metodi static hanno un capitolo dedicato in Java static.
Un metodo di istanza
Aggiungi un metodo al corpo della classe, senza static, e diventa parte di ogni istanza:
public class Circle {
double radius;
double area() {
return Math.PI * radius * radius;
}
}Ora ogni Circle che crei può rispondere ad area():
Circle c = new Circle();
c.radius = 5;
System.out.println(c.area()); // 78.539...Il corpo legge radius senza qualificarlo — Java risolve il nome semplice come this.radius, il campo dell'oggetto su cui è stato chiamato il metodo.
this — il ricevitore
Ogni metodo di istanza ha un parametro invisibile chiamato this, che fa riferimento all'oggetto su cui è stato chiamato il metodo:
Circle a = new Circle(); a.radius = 2;
Circle b = new Circle(); b.radius = 5;
a.area(); // inside area(), this == a, so this.radius == 2
b.area(); // inside area(), this == b, so this.radius == 5Lo stesso metodo compilato viene eseguito in entrambi i casi; ciò che cambia è a quale oggetto fa riferimento this. Il capitolo sulla parola chiave this spiega quando è necessario scrivere esplicitamente this. e quando può essere omesso.
Metodi che modificano lo stato
Un metodo può anche scrivere sui campi. Tali metodi sono spesso chiamati mutatori:
public class Counter {
int count;
void increment() {
count++; // mutates this.count
}
void reset() {
count = 0;
}
int get() {
return count;
}
}
Counter c = new Counter();
c.increment(); c.increment(); c.increment();
System.out.println(c.get()); // 3La mutazione tramite metodi è il modo in cui gli oggetti evolvono nel tempo senza che il codice esterno acceda direttamente ai loro campi. I metodi che si limitano a leggere un campo e restituirne il valore sono l'immagine speculare — vengono solitamente chiamati accessor o getter (int get() nell'esempio è uno di questi). Instradare letture e scritture attraverso i metodi, invece di esporre i campi, è l'idea centrale dell'incapsulamento: l'oggetto rimane responsabile dei propri dati.
Chiamare altri metodi dall'interno
I metodi di istanza possono chiamare altri metodi sullo stesso oggetto, semplicemente per nome:
public class Rectangle {
double width, height;
double area() { return width * height; }
double perimeter() { return 2 * (width + height); }
String describe() {
return "area=" + area() + ", perimeter=" + perimeter();
}
}Il compilatore trasforma area() e perimeter() all'interno di describe in this.area() e this.perimeter(). Chiamano i metodi sul rettangolo su cui è stato chiamato describe.
Static vs istanza — quale usare
La regola generale: il metodo dipende dallo stato per-oggetto?
- Se sì, è un metodo di istanza (senza
static). - Se no, è
static.
public class Math2 {
public static int squared(int n) { // pure calculation — static
return n * n;
}
}
public class Counter {
int count;
public void increment() { // reads/writes this.count — instance
count++;
}
}Un segnale comune è un metodo di istanza che ignora completamente this — quello è un metodo static travestito. Il capitolo su Java static approfondisce i compromessi.
Chiamare un metodo di istanza richiede un'istanza
Poiché i metodi di istanza leggono this, non puoi chiamarne uno senza un oggetto:
Counter.increment(); // ERROR — increment is not static
new Counter().increment(); // fine — increment is called on a fresh Counter (which is then thrown away)
Counter c = new Counter();
c.increment(); // fine — increment is called on cQuesto è l'errore di compilazione più comune che incontrano i principianti: un metodo non-static referenziato da un contesto static (tipicamente da main, che è esso stesso static).
Se il compilatore segnala non-static method increment() cannot be referenced from a static context, quasi certamente hai chiamato un metodo di istanza senza un oggetto — ad esempio Counter.increment() invece di c.increment(). Crea prima un'istanza, poi chiama il metodo su di essa.
Overloading e overriding
I metodi di istanza supportano entrambi:
- Overloading: più metodi con lo stesso nome ma elenchi di parametri diversi nella stessa classe (trattato in method overloading).
- Overriding: una sottoclasse che sostituisce la versione ereditata di un metodo (trattato in method overriding).
Hai già visto l'overloading nella Parte 5. L'overriding è uno dei grandi vantaggi dell'ereditarietà e verrà trattato a breve.
I corpi dei metodi sono blocchi
Il corpo di un metodo è semplicemente un blocco di codice ordinario — le variabili che dichiari sono locali alla chiamata, il flusso di controllo funziona come altrove, e puoi restituire il risultato in anticipo. Niente del fatto che "questo è in una classe" cambia come si legge il corpo stesso. L'unica capacità aggiuntiva è che gli identificatori semplici possono ora fare riferimento ai campi dell'oggetto e agli altri metodi.
Un esempio pratico
Questo esempio raccoglie accessor (area, perimeter), un mutatore (scale) e un metodo che chiama altri metodi (describe) in un'unica classe. Rectangle è dichiarata static class solo per far stare l'intera demo in un singolo file — quella parola chiave si applica alla classe annidata, non ai suoi metodi di istanza, che vengono comunque eseguiti su un rettangolo specifico. Nota che scalare r lascia s invariato: ogni oggetto mantiene il proprio stato.
Cosa viene dopo
Finora hai creato oggetti scrivendo new Dog(), poi compilando i campi riga per riga. Questo approccio è verboso e soggetto a errori — ed è facile dimenticarsi qualcosa. La soluzione è un costruttore, un metodo speciale che viene eseguito quando l'oggetto viene creato. Continua con il capitolo sui costruttori.