Słowo kluczowe static

W niektórych sytuacjach istnieje potrzeba zdefiniowania składowej klasy, której można używać niezależnie od obiektów tej klasy. Zwykle składowej klasy używamy za pośrednictwem obiektu tej klasy, ale możliwe jest również stworzenie samodzielnej składowej, której możemy używać bez odwoływania się do konkretnego obiektu. Składową taką tworzymy, poprzedzając jej deklarację słowem kluczowym static. Gdy zadeklarujesz składową jako static, możesz zacząć używać jej, zanim utworzysz pierwszy obiekt tej klasy, gdyż odwołanie się do tej składowej nie wymaga użycia referencji obiektu. Składowymi static mogą być zarówno zmienne, jak i metody. Najbardziej znanym przykładem składowej static jest metoda main(). Metodę main() zadeklarowano jako static, ponieważ musi zostać wywołana przez maszynę wirtualną Javy w momencie uruchomienia programu. Aby odwołać się do składowej static na zewnątrz klasy, poprzedzasz jej nazwę kropką i nazwą klasy. Nie musisz tworzyć żadnego obiektu. Na przykład jeśli chcesz przypisać wartość 10 zmiennej static o nazwie count należącej do klasy Timer, napiszesz następujący wiersz kodu:

Timer.count = 10;

Przypomina to odwołanie do zwykłej składowej obiektu, z tą różnicą, że zamiast nazwy obiektu użyta zostaje nazwa klasy. W ten sam sposób, poprzedzając kropką i nazwą klasy, możesz wywoływać  metody static. Zmienne zadeklarowane jako static są w zasadzie zmiennymi globalnymi. Utworzenie obiektu nie powoduje powstania kopii zmiennej static. Wszystkie obiekty klasy współdzielą tę samą zmienną. Na listingu 6.16 przedstawiłem program ilustrujący różnice pomiędzy zwykłymi składowymi klasy
a składowymi static.

Listing 6.16. SDemo.java

// Używa zmiennej static.
class StaticDemo {
  int x; // zwykła zmienna składowa
  static int y; // zmienna static Istnieje tylko jedna kopia składowej y, wspólna dla wszystkich obiektów.
  // Zwraca sumę składowej x
  // i zmiennej static y.
  int sum() {
    return x + y;
  }
}
class SDemo {
  public static void main(String args[]) {
    StaticDemo ob1 = new StaticDemo();
    StaticDemo ob2 = new StaticDemo();
    // Każdy obiekt ma własną kopię składowej x.
    ob1.x = 10;
    ob2.x = 20;
    System.out.println("Oczywiście, składowe ob1.x i ob2.x " + "są niezależne.");
    System.out.println("ob1.x: " + ob1.x + " ob2.x: " + ob2.x);
    System.out.println();
    // Każdy obiekt współdzieli z innymi jedną kopię zmiennej static.
    System.out.println("Zmienna y jest zadeklarowana jako static i tym samym współdzielona.");
    StaticDemo.y = 19;
    System.out.println("Nadaje StaticDemo.y wartość 19.");
    System.out.println("ob1.sum(): " + ob1.sum());
    System.out.println("ob2.sum(): " + ob2.sum());
    System.out.println();
    StaticDemo.y = 100;
    System.out.println("Zmienia wartość StaticDemo.y na 100");
    System.out.println("ob1.sum(): " + ob1.sum());
    System.out.println("ob2.sum(): " + ob2.sum());
    System.out.println(); }
}

Wykonanie powyższego programu spowoduje wyświetlenie następujących informacji:

Oczywiście, składowe ob1.x i ob2.x są niezależne.
ob1.x: 10
ob2.x: 20

Zmienna y jest zadeklarowana jako static i tym samym współdzielona.
Nadaje StaticDemo.y wartość 19.

ob1.sum(): 29
ob2.sum(): 39

Zmienia wartość StaticDemo.y na 100

ob1.sum(): 110
ob2.sum(): 120

Jak zauważyłeś, zmienna y jest współdzielona przez obiekty ob1 i ob2. Zmiana jej wartości dotyczy całej klasy, a nie pojedynczego obiektu. Różnica pomiędzy metodą static i zwykłą metodą sprowadza się do wywołania tej pierwszej jedynie przy użyciu nazwy klasy, bez konieczności tworzenia jakiegokolwiek obiektu tej klasy. Przykład takiej metody poznałeś już w poprzednich rozdziałach: metoda sqrt() jest metodą zadeklarowaną jako static w standardowej klasie Math. Przykład użycia metody static przedstawiłem w programie pokazanym na listingu 6.17.

Listing 6.17. SDemo2.java

// Używa metody static.
class StaticMeth {
  static int val = 1024; // zmienna static
  // metoda static
  static int valDiv2() {
    return val/2;
  }
}
class SDemo2 {
  public static void main(String args[]) {
    System.out.println("Wartość składowej val:" + StaticMeth.val);
    System.out.println("StaticMeth.valDiv2(): " + StaticMeth.valDiv2());
    StaticMeth.val = 4;
    System.out.println("Wartość składowej val:" + StaticMeth.val);
    System.out.println("StaticMeth.valDiv2(): " + StaticMeth.valDiv2());
  }
}

A oto wynik działania tego programu:

Wartość składowej val: 1024
StaticMeth.valDiv2(): 512
Wartość składowej val:4
StaticMeth.valDiv2(): 2

Z metodami static związanych jest kilka ograniczeń:

  • mogą bezpośrednio wywoływać tylko inne metody static;
  • mogą bezpośrednio używać tylko zmiennych składowych zadeklarowanych jako static;
  • nie dysponują referencją this.

Dlatego też definicja metody valDivDenom() przedstawionej na listingu 6.18 jest niepoprawna.

Listing 6.18. StaticError.java

class StaticError {
  int denom = 3; // zwykła zmienna składowa
  static int val = 1024; // zmienna static
  /* Błąd! Dostęp do zwykłej składowej
  nie jest możliwy z wnętrza metody static. */
  static int valDivDenom() {
  return val/denom; // nie zostanie skompilowana!
  }
}

W tym przypadku denom jest zwykłą zmienną składową i wobec tego nie jest dostępna dla metody zadeklarowanej jako static.

 

Bloki static

W niektórych sytuacjach klasa może wymagać pewnej inicjalizacji, zanim będzie gotowa do tworzenia obiektów. Na przykład może zaistnieć potrzeba nawiązania połączenia w sieci. Lub niektóre zmienne static wymagają inicjalizacji, zanim zostanie użyta jakakolwiek metoda static. Aby zaradzić takim problemom, Java umożliwia definiowanie bloków static. Blok taki zostaje wykonany w momencie załadowania klasy, a zatem zanim klasa może zostać użyta w jakimkolwiek innym celu. Przykład deklaracji bloku static pokazałem w programie przedstawionym na listingu 6.19. 

Listing 6.19. SDemo3.java

// Używa bloku static.
class StaticBlock {
  static double rootOf2;
  static double rootOf3;
  static { // Ten blok zostaje wykonany w podczas ładowania klasy.
    System.out.println("Wewnątrz bloku static.");
    rootOf2 = Math.sqrt(2.0);
    rootOf3 = Math.sqrt(3.0);
  }
  StaticBlock(String msg) {
    System.out.println(msg);
  }
}
class SDemo3 {
  public static void main(String args[]) {
    StaticBlock ob = new StaticBlock("Wewnątrz konstruktora.");
    System.out.println("Pierwiastek kwadratowy z 2 wynosi " + StaticBlock.rootOf2);
    System.out.println("Pierwiastek kwadratowy z 3 wynosi " + StaticBlock.rootOf3);
  }
}

Wynik działania programu jest następujący:

Wewnątrz bloku static.
Wewnątrz konstruktora.
Pierwiastek kwadratowy z 2 wynosi 1.4142135623730951
Pierwiastek kwadratowy z 3 wynosi 1.7320508075688772

Pokazuje on, że instrukcje bloku zadeklarowanego jako static zostają wykonane, zanim zostanie utworzony jakikolwiek obiekt danej klasy.

Java. Przewodnik dla początkujących. Wydanie VI, Autor: Herbert Schildt, Wydawnictwo: Helion

Podobne artykuły

Podziel się ze znajomymi tym artykułem - udostępnij na FB lub wyślij e-maila korzystając z poniższych opcji:

wszystkie oferty