public class Demo {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Tomáš Pitner, Radek Ošlejšek, Marek Šabo
Se statickou metodou jsme se setkali už u úplně prvního programu - Hello, world!
public class Demo {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
public
reprezentuje viditelnost — metoda je veřejná
void
reprezentuje návratový typ — nic nevrací
Co reprezentuje static
?
Metoda static v Javě (jinde může být chápáno jinak) říká, že metoda nepotřebuje pro své fungování žádný konkrétní existující objekt, s nímž by pracovala
To přesně potřebujeme u main
, neboť žádný objekt dosud nemáme
Dosud jsme zmiňovali atributy (proměnné) a metody objektu.
Jméno (atribut String name
) patří přímo jedné osobě
Metoda toString
vrátí Person jméno této osoby
public class Person {
private String name; // name of this person
...
public String toString() {
return "Person " + name; // returns name of this person
}
}
Lze deklarovat také metody a proměnné patřící celé třídě, tj. všem objektům třídy.
Taková proměnná (nebo metoda) existuje pro jednu třídu jen jednou.
Označujeme ji static
.
Chceme metodu max
, která vrací maximální hodnotu dvou čísel
K tomu žádné objekty nepotřebujeme
Uděláme ji jako statickou
public class Calculate {
public static int max(int a, int b) {
if (a > b) return a;
return b;
}
}
Ano, takto. Vynecháme static
.
public class Calculate {
public int max(int a, int b) {
if (a > b) return a;
return b;
}
}
Na spuštění max
budu nyní potřebovat objekt třídy Calculate
Calculate c = new Calculate();
int max = c.max(1, 2); // method needs an object `c`
Ovšem ten objekt c
je tam úplně k ničemu,
s žádnými jeho atributy se nepracuje a ani žádné nemá
Uděláme metodu statickou.
Pak metoda patří celé třídě a zavoláme ji názvem třídy bez konkrétního objektu
public class Calculate {
public static int max(int a, int b) {
if (a > b) return a;
return b;
}
}
...
int m = Calculate.max(1, 2);
Někdy v kódu často používáme statické metody určité třídy, např. naše Calculator.max
Pro kratší zápis lze pak využít deklaraci import static
dané metody
nebo všech metod přes *
, např.
import static cz.muni.fi.pb162.Calculator.*;
...
int m = max(1, 2);
Velmi často se používají v obdobných situacích, jako výše uvedené max
Tzn. jednoduše pro implementaci funkce, která nevyužívá žádné atributy (data objektu), pouze dostane vstupy a něco vrátí
Pak ani logicky žádný objekt nepotřebuje
Příklady: metody třídy java.util.Arrays
Doposud jsem měli pouze proměnné (atributy) patřící konkrétnímu objektu
Např. ve třídě Person
, která reprezentuje člověka, má každý člověk své (obvykle i odlišné) jméno
Někdy je ale situace, kdy pro celou třídu stačí určitý údaj jenom jednou
Příklad: chceme jsi pamatovat, kolik lidí se nám během chodu programu vytvořilo
Jak to udělat?
Vytvoříme statickou proměnnou peopleCount a každý člověk ji při svém vzniku zvýší o jedna.
public class Person {
private String name;
private static int peopleCount = 0;
public Person(String name) {
this.name = name;
peopleCount++;
}
public static int howManyPeople() {
return peopleCount;
}
}
Logicky na vrácení počtu lidí stačí statická metoda howManyPeople()
Použití bude vypadat následovně
Person.howManyPeople(); // 0
Person jan = new Person("Jan");
Person.howManyPeople(); // 1
Person anna = new Person("Anna");
Person.howManyPeople(); // 2
Více informací: Java tutorial — Class variables |
Můžeme volat statickou metodu nad konkrétním objektem (instancí) dané třídy?
Person anna = new Person("Anna");
anna.howManyPeople();
Ano, není to problém.
Přes třídu Person
je to však správnější.
Můžeme volat nestatickou metodu jako statickou?
Person.getName();
Logicky ne!
Co by mohlo volání Person.getName()
vrátit? Nedává to smysl.
Jde nám přece o jméno konkrétního člověka, tj. atribut v konkrétním objektu Person
Atribut name
se nastaví až při zavolání konstruktoru
Obdobně platí pro atributy, tj. NELZE toto:
public class NonStaticTest {
private int count = 0;
public static void main(String args[]) {
count++; // compiler error
}
}
Java ohlásí při překladu chybu: non-static variable count cannot be referenced from a static context.
Metoda main
je statická — může používat pouze statické metody a proměnné.
Jedině po vytvoření konkrétní instance:
public class NonStaticTest {
private int count = 0;
public static void main(String args[]) {
NonStaticTest test = new NonStaticTest();
test.count++;
}
}
Všimněte si, že ve třídě mohu vytvořit objekt té stejné třídy. |
Dalším řešením by bylo udělat count
statický.
Ano, použití static
není tak prosté, jak jsme dosud prezentovali :-)
Statické metody většinou problém nejsou
Jednoduše slouží k realizaci nějaké činnosti, které stačí předané vstupy (parametry) a která nepotřebuje žádný "svůj" objekt s atributy
Důkazem je řada použití statických metod v Java Core API, kde jsou třídy, které mají jen statické metody
Takovým třídám se říká utility classes (jakési "účelové" třídy)
U statických proměnných je to složitější
Jejich použití musí být hodně dobře zdůvodněné
Opravdu potřebujeme danou hodnotu pro danou třídu právě jednou???
Nestane se dobudoucna, že jich budeme potřebovat více???
Často je lepší aplikovat návrhový vzor singleton (jedináček)
Jedná se běžnou třídu, např. PersonCounter
, která má své běžné nestatické atributy a metody zajišťující potřebnou funkcionalitu
Např. metody void increaseNumPeople()
a atribut int peopleCount
zajišťující počítání vytvořených lidí.
public class PersonCounter {
private int peopleCount = 0;
public void increaseNumPeople() {
peopleCount++;
}
public int howManyPeople() {
return peopleCount;
}
}
Singleton ale navíc zajišťuje vytvoření jediné sdílené instance (např. jediného počítadla lidí pro celý systém):
Zakáže se volání konstruktoru (např. tak se vytvoří jediný bezparametrický privátní konstruktor)
Místo volání konstruktoru se nabídne veřejná metoda getInstance()
, která zjistí, jestli (jediná) instance již existuje. Pokud ne, vytvoří jí (voláním privátního konstruktoru) a uloží do statického atributu třídy. Pokud již existuje, rovnou se instance vrátí.
A dále zajišťuje jednoduchý přístup k jediné instanci odkudkoliv:
Metoda getInstance()
je statická, tj. kdokoliv odkudkoliv může zavolat PersonCounter.getInstance().increaseNumPersons()
.
Pokud chceme automaticky počítat vytvoření instance třídy Person
z předchozího příkladu, lze toto volání jednoduše přidat konstruktorů třídy Person
public class PersonCounter {
// here will be the singleton instance (object)
private static PersonCounter counter = null;
private int peopleCount = 0;
// "private" prevents creation of instance via new PersonCounter()
private PersonCounter() {}
// creates the singleton unless it exists
public static PersonCounter getInstance() {
if(counter == null) {
counter = new PersonCounter();
}
return counter;
}
public void increaseNumPeople() {
peopleCount++;
}
public int howManyPeople() {
return peopleCount;
}
}
Už jsme ukázali výše, že statické třídy i metody můžeme importovat:
import static java.lang.System.out;
public class HelloWorld {
public static void main(String[] args) {
out.println("Hello World!");
}
}
relevantní pouze pro statické metody a proměnné
vhodně použitelné pro některé věci z Java Core API, např. Math
Více informací: Wikipedia:Static import |
import static java.lang.System.out;
// developer is reading the code
out.println("Hello World!"); // what is out?
// few lines above:
PrintStream out;
// ahh ok, I thought it was System.out
Takže někdy pak nevíme, jestli jde o statický import a nebo jen o lokální proměnnou/metodu.
A jakmile něco nevíme na první pohled, JE TO ŠPATNĚ! :-)
==