I metodi statici

Metodi visti finora:

della classe
operazioni associate a un oggetto della classe, disponibili a tutti i programmi che usano la classe
del programma
operazioni che non sono associate a un oggetto, e che venivano usate solo dal programma

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)


Metodi statici della classe

Sono metodi che:


Come si dichiarano

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 si invocano i metodi statici

È 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);
  }
}

Metodi e metodi statici

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:

metodo non statico:
è una operazione che faccio con un oggetto (posso usare this)
metodo statico:
è un metodo che è associato alla classe (lo posso usare in tutti i programmi che usano la classe) però non è una operazione che faccio su un oggetto

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.


Esercizio

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


Modo semplificato

Se i metodi del programma sono chiari:


Modo semplificato

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));
  }
}

Spostamento nella classe

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;
  }
}

Modifica del programma

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));
  }
}

Metodo diretto

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) {
    ...
  }
}

Corpo del metodo

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;
  }
}

Programma di prova

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.


Osservazione

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


Perchè devo scrivere il nome della classe?

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.


Perchè non devo fare lo stesso con i metodi dinamici?

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


Argomenti/oggetto di invocazione

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);
  }
}

Oggetto di invocazione/oggetto passato

  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)


Differenze

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à


Esempio di metodo statico

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.


Altri metodi statici della classe Math

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.


Classi Point e Rectangle

Non hanno metodi statici.


Esercizio

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.


Il metodo statico

Prende come parametro un reale, e restituisce un intero:

class Studente {
  String nome;
  int eta;
  double media;

  static int converti(double n) {
    ...
  }
}

Corpo del metodo

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;
  }
}

Metodo non statico

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);
  }
}

Il nome della classe

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:

dentro la classe Studente:
basta fare converti(numero)
da un'altra classe o programma
devo mettere il nome della classe: Studente.converti(numero)

Un programma di prova

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:


Chi può invocare chi

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()


Regola facile

metodi non statici
invocazione oggetto.metodo(...)
l'indirizzo dell'oggetto viene copiato in this
metodi statici
invocazione NomeClasse.metodo(...)
non esiste il this, dato che non c'è l'oggetto di invocazione

Semplificazione: NomeClasse si può omettere se si invoca un metodo statico della stessa classe.


Esercizio

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?


Conversione

Se a è un reale da 0 a 1, per ottenere un intero x da -100 a 100:

  x=(int) (a*201)-100;

Il metodo

Non ha parametri.

Torna un ExtPoint

import java.awt.*;

class ExtPoint extends Point {
  static ExtPoint puntoRandom() {
    ...
  }
}

Cosa fa il metodo?

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.


Il corpo del metodo

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)


Programma di prova

Scrivere uin programma di prova che genera cento punti casuali e li stampa con println


Il programma

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.