Metodi visti finora:
Il secondo tipo di metodo non era associato a un oggetto particolare: l'invocazione non richiede un oggetto di invocazione.
Per questo, non si può usare this in un metodo statico (non esiste l'oggetto di invocazione)
Sono metodi che:
Sono come i metodi di programma, solo che li metto nella classe.
Esempio: penso che il metodo di somma di due interi sia utile a tutti i programmi che usano la classe NewPoint
import java.awt.*; class NewPoint extends Point { static int somma(int a, int b) { return a+b; } }
Non ha un oggetto di invocazione!
È come per i metodi del programma, ma si mette prima il nome della classe:
class ProvaNewPoint { public static void main(String args[]) { int x; x=somma(12,43); // sbagliato!! x=NewPoint.somma(12,43); // ok System.out.println(x); } }
import java.awt.*; class NewPoint extends Point { int sommaCoordinate() { return this.x+this.y; } static int somma(int a, int b) { return a+b; } }
Differenza:
Quindi: i metodi normali li invoco su un oggetto, e quindi esiste this. I metodi statici non si invocano su un oggetto, e quindi this non esiste.
Definire la classe studente con le componenti: nome, eta e media di tipo String, int e double
Unico metodo statico: media, che calcola la media di due interi, e restituisce un reale.
Non ha relazioni con la componente media
Se i metodi del programma sono chiari:
Nel programma, si scriverebbe cosí:
class Semplif { static double media(int a, int b) { int somma; somma=a+b; return ((double) somma)/2; } public static void main(String args[]) { int x=12; int y=3; System.out.println(media(x, y)); } }
Copio il metodo, identico, nella classe.
class Studente { String nome; int eta; double media; static double media(int a, int b) { int somma; somma=a+b; return ((double) somma)/2; } }
Programma originario:
class Semplif { static double media(int a, int b) { int somma; somma=a+b; return ((double) somma)/2; } public static void main(String args[]) { int x=12; int y=3; System.out.println(media(x, y)); } }
Tolgo la definizione del metodo.
Aggiungo Studente. alle invocazioni:
class Semplif { public static void main(String args[]) { int x=12; int y=3; System.out.println(Studente.media(x, y)); } }
In pratica, scrivo direttamente il metodo nella classe.
Iniziamo a definire le componenti e la intestazione del metodo:
class Studente { String nome; int eta; double media; static double media(int a, int b) { ... } }
Devo calcolare la somma e poi fare la divisione per due.
Attenzione! La componente media non c'entra niente.
Il metodo statico non ha il this, quindi non può accedere a this.media oppure alle altre componenti.
class Studente { String nome; int eta; double media; static double media(int a, int b) { int somma; somma=a+b; return ((double) somma)/2; } }
I metodi statici si possono usare anche se non ci sono oggetti della classe.
class ProvaStudente { public static void main(String args[]) { double x; x=Studente.media(9, 34); System.out.println(x); } }
Questo prova solo il metodo statico: per provare le altre parti della classe, faccio un programma che usa oggetti.
Il metodo Studente.media può venire invocato per fare una media di due interi.
Si può invocare anche se i due interi non riguardano un oggetto Studente
Per esempio, si può usare per calcolare il punto mediano, ecc:
Point mediano; mediano=new Point(); mediano.x=(int) Studente.media(p.x, q.x); mediano.y=(int) Studente.media(p.y, q.y);
Si può fare, ma rende il programma meno chiaro.
In questi casi, meglio un metodo nel programma, oppure un metodo a parte nella classe Point
Potrei avere più metodi definiti in classi diverse (e fanno cose diverse).
Esempio: in NewPoint mi serve la approssimazione della media a intero:
class NewPoint extends Point { static int media(int x, int y) { return (x+y)/2; } }
In Studente mi serve la media come reale:
class Studente { ... static double media(int a, int b) { return ((double) a+b)/2; } }
Per distinguerli, so che uno si chiama NewPoint.media mentre l'altro si chiama Studente.media, e fanno due cose diverse.
I metodi dinamici si invocano come:
oggetto.nomeMetodo(argomenti);
In base all'oggetto, so il nome della classe.
Il metodo è quello della classe dell'oggetto.
class Studente { void dinamico() {...} } class NewPoint { void dinamico() {...} }
Se il programma è:
Studente s; NewPoint p; ... s.dinamico(); p.dinamico();
La prima invocazione è al metodo di Studente, la seconda al metodo di NewPoint
I metodi statici non hanno oggetti di invocazione.
Però posso passare quello che voglio come argomento.
Posso anche passare un oggetto della classe.
class NewPoint extends Point { static void stampaStatico(NewPoint p) { System.out.println(p.x); System.out.println(p.y); } void stampaPunto() { System.out.println(this.x); System.out.println(this.y); } }
static void stampaStatico(NewPoint) void stampaPunto()
Per le cose viste finora, l'unica differenza è che il primo si invoca come:
NewPoint.stampaPuntoStatico(p);
Mentre per il secondo:
p.stampaPunto();
Tutti e due hanno a disposizione un oggetto (p nel primo e in this nel secondo)
La variabile this non è modificabile:
this=null; // errore this.x=12; // ok: this non viene // modificato: e' this.x che cambia
Posso invece modificare il parametro formale p
p=null; // ok
Non ha comunque effetto nel programma che
invoca il metodo
(il programma invia un numero al metodo, e questo
numero viene inizialmente messo in p;
quello che poi succede a p non ha effetti
nel programma).
Altre differenze riguardano l'ereditarietà
Classe: Math
Metodo: static double sqrt(double)
Uso del metodo: d=Math.sqrt(12.2);
La classe Math non ha componenti, ma solo metodi statici.
È un contenitore di metodi che possono servire in più programmi.
Method Summary | |
static double |
abs(double a)
Returns the absolute value of a double value. |
static float |
abs(float a)
Returns the absolute value of a float value. |
static int |
abs(int a)
Returns the absolute value of an int value. |
static long |
abs(long a)
Returns the absolute value of a long value. |
static double |
acos(double a)
Returns the arc cosine of an angle, in the range of 0.0 through pi. |
static double |
asin(double a)
Returns the arc sine of an angle, in the range of -pi/2 through pi/2. |
Sono solo alcuni esempi.
Notare il sovraccarico di alcuni metodi.
Non hanno metodi statici.
Inserire nella classe Studente un metodo statico che converte un reale seguendo la regola:
nuovonumero=numero*110/30
Il numero dato è reale; quello generato deve essere intero.
Definire un metodo non statico che usa questo metodo per calcolare la media di uno studente espressa in centodecimi.
Prende come parametro un reale, e restituisce un intero:
class Studente { String nome; int eta; double media; static int converti(double n) { ... } }
Devo convertire in centodecimi il valore passato, e restituirlo come intero.
class Studente { String nome; int eta; double media; static int converti(double n) { return (int) n*110/30; } }
Deve restituire la media in centodecimi, dato l'oggetto di invocazione.
class Studente { String nome; int eta; double media; static int converti(double n) { return (int) n*110/30; } int media110() { return Studente.converti(this.media); } }
Regola generale: per invocare un metodo statico, prima metto il nome della classe.
Eccezione: se il metodo viene invocato da un altro metodo della stessa classe, il nome della classe si può omettere.
int media110() { return converti(this.media); }
Invocare converti:
class ProvaMedia { public static void main(String args[]) { Studente s; s=new Studente(); s.nome="Pippo"; s.eta=102; s.media=21.2; System.out.println(Studente.converti(29.2)); System.out.println(s.media110()); } }
Osservazioni:
Ogni metodo della classe può invocare un altro metodo della classe.
Però:
Un metodo statico può invocare un metodo non statico come al solito, ossia specificando un oggetto di invocazione.
class Studente { ... static void esempio(double x) { Studente s; s=new Studente(); s.media=x; System.out.println(s.media110()); } }
Notare che l'invocazione di un metodo non statico va fatta su un oggetto
Il metodo statico non ha this, quindi non si può fare this.media110()
Semplificazione: NomeClasse si può omettere se si invoca un metodo statico della stessa classe.
Estendere la classe Point a una nuova classe ExtPoint che contiene un metodo statico che crea un punto con dentro due valori casuali.
Per i valori casuali: usare il metodo double random() della classe Math che ritorna un reale casuale fra 0 e 1 (uno escluso).
Voglio interi casuali fra -100 e 100
Conversione?
Se a è un reale da 0 a 1, per ottenere un intero x da -100 a 100:
x=(int) (a*201)-100;
Non ha parametri.
Torna un ExtPoint
import java.awt.*; class ExtPoint extends Point { static ExtPoint puntoRandom() { ... } }
Crea un oggetto.
Ci mette dentro i valori random.
Il metodo è statico: non ha un oggetto di invocazione.
Se creo un oggetto, poi ci posso mettere dentro i valori casuali.
import java.awt.*; class ExtPoint extends Point { static ExtPoint puntoRandom() { ExtPoint p; p=new ExtPoint(); p.x=(int) (Math.random()*201-100); p.y=(int) (Math.random()*201-100); return p; } }
Cosa fa return p?
Ritorna l'indirizzo dell'oggetto creato.
Il passaggio di oggetti da programma a metodo e viceversa, è sempre un passaggio di valori (indirizzi)
Scrivere uin programma di prova che genera cento punti casuali e li stampa con println
Il metodo resituisce l'indirizzo di un ExtPoint
Lo metto in una variabile, e lo uso
class ProvaExtPoint { public static void main(String args[]) { ExtPoint p; int i; for(i=0; i<20; i++) { p=ExtPoint.puntoRandom(); System.out.println(p); } } }
Notare p= per memorizzare il punto generato.