Liigu peamise sisu juurde

Staatilised meetodid ja muutujad

Õppevideo antud teemal:

Sissejuhatus

Siiani on iga väli ja meetod, mille oleme kirjutanud, kuulunud objektile — konkreetsele klassi eksemplarile. Nende kasutamiseks pidime esmalt looma objekti new märksõnaga ja seejärel pääsema nendele ligi selle objekti kaudu.

static märksõna muudab seda. Staatiline liige kuulub klassile endale, mitte ühelelegi konkreetsele objektile. See eksisteerib ühe eksemplarina sõltumata sellest, kui palju objekte luuakse — või kas üldse mõni objekt luuakse.

Tegelikult olete kasutanud staatilist meetodit juba algusest peale:

public static void main(String[] args) {
// ...
}

main meetod on static, sest JVM peab seda välja kutsuma enne, kui ükski objekt on olemas. Antud peatükk keskendub sellele, mis asi static on, mida see tähendab ja millal seda kasutada.

Staatilised väljad

Staatiline väli on jagatud kõigi klassi eksemplaride vahel. Selle asemel, et igal objektil oleks oma koopia (nagu isendiväljade puhul), on olemas ainult üks koopia, mis kuulub klassile.

Oletame, et meil on vaja järge hoida sellest, mitu Student objekti on loodud. Ainuüksi isendiväljadega pole see saavutatav, kuna iga objekt teab ainult infot enda kohta.

class Student {
private String name;

public Student(String name) {
this.name = name;
}
}

Võiksime proovida lisada näiteks int counter välja, kuid iga objekt saaks sellest oma eraldi koopia. Staatiline väli lahendaks selle probleemi. static märksõna tähistab, et antud väli luuakse korra klassi tasemel ning on kõikide objektide vahel jagatud. Näiteks:

class Student {
private String name;
private static int studentCount = 0;

public Student(String name) {
this.name = name;
studentCount++; // shared counter — incremented for every new Student
}

public static int getStudentCount() {
return studentCount;
}
}

public class Main {
public static void main(String[] args) {
Student alice = new Student("Alice");
Student bob = new Student("Bob");
Student charlie = new Student("Charlie");

System.out.println(Student.getStudentCount()); // 3
}
}

Eksisteerib ainult üks studentCount, mis kehtib klassile, mitte igale objektile eraldi. Antud näites iga kord kui uus Student objekt luuakse, suurendatakse ka studentCount suurust.

Staatiliste väljade kasutamine

Staatilisi välju ei kasutata mitte objekti, vaid klassi nime kaudu:

System.out.println(Student.getStudentCount());  // correct - accessed through the class

Java lubab staatilistele liikmetele ligi pääseda ka objekti viite kaudu, kuid seda peetakse halvaks tavaks, sest see on eksitav. See jätab mulje, nagu väärtus kuuluks sellele konkreetsele objektile, kuigi tegelikult see nii ei ole:

Student alice = new Student("Alice");
System.out.println(alice.getStudentCount()); // works, but misleading — avoid this

Staatilised meetodid

Staatiline meetod on meetod, mis kuulub klassile ning mida on võimalik kasutada ilma objekti loomata.

Meetod on staatiline, kui sellel on static märksõna enne tagastustüüpi, näiteks:

public static int square(int number) {
return number * number;
}

public static int max(int a, int b) {
if (a >= b) {
return a;
}
return b;
}

public void someMethod() { // not a static method, see the difference
// ...
}

Staatiliste meetodite kasutamine

Staatilisi meetodeid kutsutakse välja läbi klassi:

int result = MathHelper.square(5);      // 25
int bigger = MathHelper.max(10, 20); // 20

MathHelper.someMethod(); // Error, someMethod belongs to an object, not class

Staatiliste meetodite puhul ei ole vaja new märksõna kasutada. Meetodid ei sõltu ühegi objekti olekust. Need võtavad sisendi, annavad väljundi ja sellega asi piirdub.

Näiteid Javast endast

Järgnevad on paar näidet staatilistest meetoditest, mis Javas eksisteerivad. Mõnda neist olete tõenäoliselt juba kasutanud:

// Math class - static methods for mathematical operations
double root = Math.sqrt(16); // 4.0
double pi = Math.PI; // static field
int absolute = Math.abs(-5); // 5

// Integer class - static methods for parsing
int number = Integer.parseInt("42");

// Arrays class - static utility methods
int[] numbers = {3, 1, 4, 1, 5};
Arrays.sort(numbers);

Erinevused isendi ja staatiliste liikmete vahel

Peamine erinevus isendi ja staatiliste liikmete vahel on see, mille alla nad kuuluvad.

Isendi liigeStaatiline liige
KuulubKindlale objektileKlassile
Millal luuakseKui luuakse uus objekt new märksõnagaKui klass mällu laetakse
Kuidas ligi pääsetakse?Läbi objekti viite (object.method())Klassi nime kaudu (ClassName.method())

Staatiliste meetodite piirangud

Staatilistel meetoditel on üks kindel piirang. Kuna need kuuluvad klassile, siis nende kaudu ei ole võimalik ligi pääseda andmetele, mis kuuluvad individuaalsetele objektidele. Sisuliselt, staatiline meetod ei tea millist objekti täpselt silmas peetakse, seetõttu tekib ka kompileerimisviga:

class Student {
private String name;
private static int studentCount = 0;

public Student(String name) {
this.name = name;
studentCount++;
}

public static void printInfo() {
System.out.println(studentCount); // OK - static can access static
System.out.println(name); // Error: cannot access instance field from static context
System.out.println(this.name); // Error: 'this' does not exist in static context
}
}

Siit saame järeldada:

  • Staatilistel meetoditel on ligipääs ainult teistele staatilistele liikmetele (väljad, meetodid)
  • Tavalistel meetoditel on ligipääs olemas nii staatilistele kui ka isendi liikmetele.

Millal staatilisust kasutatakse?

static märksõna tasub kasutada siis, kui antud liige ei sõltu objekti olekust. Näiteks:

  • Utiilmeetodid, mis võtavad sisendiks mingid andmed ja tagastavad midagi muud, ilma, et need mõjutaks mingit olekut (nt: Math.sqrt(), Integer.parseInt()).
  • Jagatud olek või konfiguratsioon, mis peaks kõikidel juhtudel sama olema/sama tulemuse andma.
  • Konstandid ehk väärtused, mis kunagi ei muutu (static final muutujad, mille kohta saad lugeda siit)
  • Tehasemeetodid, mille eesmärk on luua uusi objekte (alternatiiv konstruktoritele).

Üldine reegel on, et kui pole kindel kas antud juhul peaks static kasutama või mitte, siis vaikimisi võiks eelistada mitte kasutamist. Praktikas püütakse vältida muudetavat globaalset olekut, sest see võib tekitada varjatud sõltuvusi ja ettenägematuid kõrvalmõjusid. Probleem ei ole static märksõnas endas, vaid jagatud ja muudetavas olekus, mis muudab programmi käitumise raskemini mõistetavaks ja testitavaks.