Detaljno objašnjenje uloge Java static ključne reči: statičke promenljive, statički metodi, statički blok, statička unutrašnja klasa
"Brate, da li ti je otok desni već popustio? U ponedeljak nisi objavio novo poglavlje 'Podučavam sestru Javu' (prethodnika Ergovog puta kroz Javu), prekinuo si!" Sanmej me je sa pažnjom pitala.
"Danas je četvrtak, tri dana uzimam lekove, bol je već prilično oslabio, a mama me je pozvala i rekla mi da kupim pilule za rashlađivanje." Rekao sam Sanmej sa osmehom. "Učenje ne sme da se prekine, danas da učimo o static ključnoj reči u Javi."
"static je jedna od ključnih reči u Javi koja je teže razumeti i jedna je od omiljenih tačaka koje ispituju intervjueri u velikim kompanijama." Popio sam gutljaj kafe i nastavio.
"Pošto je to važno za intervjue, onda zaista moram dobro da naučim." Sanmej je brzo rekla.
"Uloga static ključne reči se može opisati jednom rečenicom: 'omogućava pozivanje bez kreiranja objekta, uključujući promenljive i metode'. Drugim rečima, jednom kada se klasa učita, njoj se može pristupiti preko imena klase." Popravio sam teške naočare i nastavio. "static se može koristiti za modifikaciju članskih promenljivih klase, kao i članskih metoda. Hajde da ih jednog po jednog pregledamo."
01. Statička promenljiva
"Ako se pri deklaraciji promenljive koristi static ključna reč, onda se ta promenljiva zove statička promenljiva. Statička promenljiva dobija memorijski prostor samo jednom prilikom učitavanja klase, što čini statičke promenljive veoma štedljivim po pitanju memorije." Grejanje kod kuće bilo je malo prejako, pa sam otišao da malo otvorim prozor i nastavio.
"Razmotrimo sledeću Student klasu." Jedva što sam završio reč, već sam počeo da kucam po tastaturi.
public class Student {
String name;
int age;
String school = "Univerzitet Zhengzhou";
}Pošto sam otkucao ovaj kod, rekao sam Sanmej: "Pretpostavimo da je Univerzitet Zhengzhou primio deset hiljada novih studenata; pri kreiranju deset hiljada Student objekata, sva polja (name, age i school) dobijaju po jedan memorijski blok. Imena i godine studenata su različiti, ali svi pripadaju Univerzitetu Zhengzhou. Ako bi svaki put pri kreiranju objekta polje school zauzelo poseban memorijski blok, to bi bilo prilično rasipničko, zar ne, Sanmej?"
"Zbog toga je najbolje postaviti polje school kao static; na taj način zauzeće je samo jedan memorijski blok, a ne deset hiljada."
U tihoj kući ponovo su odjekivali zvuci kucanja po tastaturi.
public class Student {
String name;
int age;
static String school = "Univerzitet Zhengzhou";
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student s1 = new Student("Chenmo Wang Er", 18);
Student s2 = new Student("Chenmo Wang San", 16);
}
}"Gledaj, Sanmej. Dve referentne promenljive s1 i s2 se nalaze u stack zoni, objekti Chenmo Wang Er+18 i Chenmo Wang San+16 nalaze se u heap zoni, dok se statička promenljiva school nalazi u statičkoj zoni."
"Sačekaj, brate, stack, heap, statička zona?" Lice Sanmej bilo je puno zbunjenosti.
"Oh, ne brini, Sanmej, da nacrtam dijagram i sve će ti biti jasno." Rekavši to, otvorio sam sajt draw.io i pažljivo počeo da crtam.

"Zar sada nije odjednom jasno?" Gledajući taj lepi crtež, osetio sam malo zadovoljstva u srcu.
"O, brate, predivno!" Sanmej nije propustila da me pohvali, dala mi je veliki palac gore.
"Dobro, Sanmej, da pogledamo sledeći kod."
public class Counter {
int count = 0;
Counter() {
count++;
System.out.println(count);
}
public static void main(String args[]) {
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
}
}"Kreirali smo člansku promenljivu count i u konstruktoru je povećavamo. Pošto članska promenljiva dobija memoriju pri kreiranju objekta, svaki objekat ima svoju kopiju count, pa vrednost count se ne povećava sa brojem objekata."
Ja sam pričao u širokom luku, a Sanmej izgleda nije sve ukapirala.

"Nije problem, Sanmej, probaj prvo da pogodiš — koji je izlaz ovog koda?"
"Prema tvojoj logici, trebalo bi da ispiše tri 1? Je li tako?" Sanmej je trepnula, pomalo nesigurno odgovorivši.
"Hej, dobro je."
Kliknuo sam na dugme za pokretanje u IDEA-i, program je krenuo.
1
1
1"Svaki put kada se kreira Counter objekat, vrednost count se poveća sa 0 na 1. Sanmej, razmisli — šta ako bi count bio statički?"
"Ne znam."
"Hajde da pogledamo sledeći kod."
public class StaticCounter {
static int count = 0;
StaticCounter() {
count++;
System.out.println(count);
}
public static void main(String args[]) {
StaticCounter c1 = new StaticCounter();
StaticCounter c2 = new StaticCounter();
StaticCounter c3 = new StaticCounter();
}
}"Da pogledamo izlaz."
1
2
3"Da objasnim ukratko — pošto statička promenljiva dobija memorijski prostor samo jednom, svaka izmena koju bilo koji objekat napravi biće sačuvana, pa pri kreiranju svakog objekta vrednost count se poveća za 1, pa je konačni rezultat 3. Razumeš li, Sanmej? To je razlika između statičkih promenljivih i članskih promenljivih."
"Pored toga, važno je napomenuti da pošto statičke promenljive pripadaju klasi, ne treba im pristupati preko referenci objekata, već bi trebalo direktno preko imena klase, inače će kompajler dati upozorenje."

02. Statički metod
"Kada smo završili sa statičkim promenljivama, hajde da progovorimo o statičkim metodima." Rekavši to, spremao sam da zapalim jednu cigaretu, ali me je Sanmej zaustavila; pokazala je na natpis 'Pušenje šteti zdravlju' na kutiji, pa sam se nasmejao.
"Dobro." mogao sam samo da popijem gutljaj kafe i nastavim. "Ako ispred metoda stoji static ključna reč, onda je to statički metod."
"Statički metodi imaju sledeće karakteristike."
- Statički metod pripada toj klasi, a ne objektima te klase;
- Pri pozivu statičkog metoda ne treba kreirati objekat te klase;
- Statički metod može pristupati statičkim promenljivama.
"Hajde, nastavimo sa kodom."
public class StaticMethodStudent {
String name;
int age;
static String school = "Univerzitet Zhengzhou";
public StaticMethodStudent(String name, int age) {
this.name = name;
this.age = age;
}
static void change() {
school = "Univerzitet Henan";
}
void out() {
System.out.println(name + " " + age + " " + school);
}
public static void main(String[] args) {
StaticMethodStudent.change();
StaticMethodStudent s1 = new StaticMethodStudent("Chenmo Wang Er", 18);
StaticMethodStudent s2 = new StaticMethodStudent("Chenmo Wang San", 16);
s1.out();
s2.out();
}
}"Pažljivo slušaj, Sanmej. Metod change() je statički metod, pa može direktno pristupiti statičkoj promenljivoj school i promeniti joj vrednost u Univerzitet Henan; pored toga, može se pozvati direktno preko imena klase, kao StaticMethodStudent.change()."
"Da pogledamo izlaz."
Chenmo Wang Er 18 Univerzitet Henan
Chenmo Wang San 16 Univerzitet Henan"Važno je napomenuti da statički metodi ne mogu pristupati ne-statičkim promenljivama niti pozivati ne-statičke metode. Gledaj, Sanmej, samo malo da izmenim kod i kompajler će prijaviti grešku."
"Prvo, u statičkom metodu pokušaj pristupa ne-statičkoj promenljivoj — kompajler ne dozvoljava."

"Zatim, u statičkom metodu pokušaj poziva ne-statičkog metoda — kompajler takođe ne dozvoljava."

"O upotrebi statičkih metoda, sada je jasno, zar ne, Sanmej?"
Gledajući kako Sanmej klima glavom, nasmejao sam se sa zadovoljstvom.
"Brate, setila sam se jednog pitanja — zašto je main metod statički?" Nisam očekivao, ali Sanmej je lepo povezivala različite tačke znanja.
"Da main metod nije statički, to bi značilo da Java virtuelna mašina pri izvršavanju mora prvo da kreira objekat da bi pozvala main metod; a s obzirom na to da je main metod ulaz u program, kreiranje dodatnog objekta je prilično suvišno." Moj odgovor bez razmišljanja naveo je Sanmej da me gleda sa divljenjem.
"Skoro svi metodi klase java.lang.Math su statički, pa ih je moguće pozvati direktno preko imena klase, bez kreiranja objekta klase."

03. Statički blok
"Sanmej, ustani da se malo protegneš, i meni je vrat malo ukočio."
Zajedno smo prišli prozoru; pred očima nam se pojavio sneg koji je padao sa neba. I Sanmej i ja smo bili oduševljeni, jedva čekali smo da otvorimo prozor i ispružimo ruke da osetimo temperaturu pahuljica — onaj prolazni hladan osećaj bio je zaista prijatan.
"Severni predeli, hiljadu milja zaleđeno, deset hiljada milja snežno... Zidovi Kine sa obe strane, samo beskrajna ravnica; gore i dole reke, izgubile su svoj tok. Planine plesu kao srebrne zmije, visoravni jure kao voštani slonovi, želeći da se takmiče sa nebom... Neka bude sunčan dan, i sve je u crvenom i belom, izvanredno lepo..." Sanmej je čak i nehotice počela da deklamuje 'Ćenjuanćun - Sneg'.
Zaista je radost, ovo je prvi sneg u Luojangu 2020. godine, zaista raduje.
Trenutak kasnije.
"Pored statičkih promenljivih i statičkih metoda, static ključna reč ima još jednu važnu ulogu." Rekao sam veselo Sanmej. "Jedna static ključna reč, uz velike zagrade koje obuhvataju deo koda, zove se statički blok."
"Kao u sledećem kodu."
public class StaticBlock {
static {
System.out.println("statički blok");
}
public static void main(String[] args) {
System.out.println("main metod");
}
}"Statički blok se obično koristi za inicijalizaciju nekih statičkih promenljivih; izvršava se pre main() metoda."
"Da pogledamo izlaz."
statički blok
main metod"Erge, pošto se statički blok izvršava pre main() metoda, da li Java klasa bez main() metoda može uspešno da se izvrši?" Način razmišljanja Sanmej me sve više zadivljuje.
"U Javi 1.6 može, ali od Jave 7 nadalje to više nije moguće." odgovorio sam pun samopouzdanja.
public class StaticBlockNoMain {
static {
System.out.println("statički blok, bez main");
}
}"Kada se u komandnoj liniji izvrši java StaticBlockNoMain, biće bačena greška NoClassDefFoundError."

"Sanmej, pogledaj sledeći primer."
public class StaticBlockDemo {
public static List<String> writes = new ArrayList<>();
static {
writes.add("Chenmo Wang Er");
writes.add("Chenmo Wang San");
writes.add("Chenmo Wang Si");
System.out.println("prvi blok");
}
static {
writes.add("Chenmo Wang Wu");
writes.add("Chenmo Wang Liu");
System.out.println("drugi blok");
}
}"writes je statički ArrayList, pa nije baš moguće završiti inicijalizaciju pri deklaraciji, zbog čega treba uraditi inicijalizaciju u statičkom bloku."
"Statički blok je zaista veoma koristan pri inicijalizaciji kolekcija. U realnom razvoju projekata obično se koristi statički blok da se konfiguracioni fajlovi učitaju u memoriju."
04. Statička unutrašnja klasa
"Sanmej, pored svega gore navedenog, static ima još jednu manje korišćenu funkciju — statička unutrašnja klasa."
"Java nam dozvoljava deklarisanje unutrašnje klase unutar jedne klase; to pruža ubedljiv način da dozvolimo upotrebu nekih promenljivih samo na jednom mestu, čineći kod organizovanijim i čitljivijim."
"Postoje četiri uobičajene vrste unutrašnjih klasa: članska unutrašnja klasa, lokalna unutrašnja klasa, anonimna unutrašnja klasa i statička unutrašnja klasa. Zbog ograničenja prostora, prve tri neće biti tema našeg razmatranja ovog puta — o njima će biti reči kasnije."
"Pogledaj sledeći primer." Sanmej je malo odlutala, kucnuo sam je po glavi i nastavio.
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}"Sanmej, saberi se, skoro je gotovo."
"O, ovaj kod izgleda prilično elegantno, brate."
"Da, Sanmej, ovaj kod će se ponovo videti kasnije kada budeš kreirala singleton."
"Pri prvom učitavanju klase Singleton, instance se ne inicijalizuje; tek kada se prvi put pozove getInstance() metod, Java virtuelna mašina počinje da učitava SingletonHolder i inicijalizuje instance — na taj način se ne samo osigurava bezbednost niti, već i jedinstvenost klase Singleton. Međutim, elegantniji način kreiranja singletona je korišćenje enumeracije, o čemu ćemo govoriti drugi put."
"Važno je napomenuti. Prvo, statička unutrašnja klasa ne može pristupati svim članskim promenljivima spoljašnje klase; drugo, statička unutrašnja klasa može pristupati svim statičkim promenljivima spoljašnje klase, uključujući privatne statičke promenljive. Treće, spoljašnja klasa ne može biti deklarisana kao static."
"Gledaj, Sanmej, kada se na klasu Singleton doda static, kompajler prijavljuje grešku."

Sanmej je klimnula glavom, zamišljena.
