22 marca 2008

SCJP - Deklaracja zmiennych i stałych

Deklaracja zmiennych i stałych, czyli streszczenie sekcji "Variable Declarations" – kontynuacja działań zapowiedzianych w artykule "Przygotowania do SCJP czas zacząć".

Java definiuje dwa rodzaje zmiennych: zmienne typu prostego (ang. primitives) i zmienne będące referencjami (ang. reference variables). Jest 8 typów prostych, są to: char, boolean, byte, short, int, long, double oraz float. Referencje są de facto wskaźnikami na obiekty, ale nie na wszystkie obiekty a tylko na te zgodne z typem referencji. Jeśli więc zadeklarujemy referencję na obiekty klasy A, to może ona wskazywać tylko na obiekty klasy A oraz na obiekty klas pochodnych. W języku Java – w przeciwieństwie do np. C++ – wszystkie klasy uczestniczą jednak we wspólnej hierarchii dziedziczenia z klasą Object w korzeniu, tak więc możemy zadeklarować referencję do obiektów klasy Object, która będzie mogła wskazywać na obiekt dowolnego typu.

Zmienna typu boolean może przyjmować jedną z dwu wartości: ‘true’ albo ‘false’. Już to pisałem, ale przypomnę, że Java jest językiem tzw. case-sensitive, a więc ‘true’ to co innego niż ‘TRUE’ i co innego niż ‘True’ a wartością zmiennej typu boolean może być tylko ‘true’ albo ‘false’. Typ znakowy char reprezentowany jest na dwu bajtach i odpowiada jednemu znakowi UTF-16. Zmienne typów numerycznych zakodowane są bitowo w tak zwanej notacji uzupełniającej do dwu z najbardziej znaczącym bitem oznaczającym znak liczby (0 to plus a 1 to minus). Poniższa tabelka pokazuje liczbę bajtów użytą do reprezentacji poszczególnych typów.

byte

short

int

long

float

double

1

2

4

8

4

8


Zmienne można deklarować w czterech różnych kontekstach. Zmienne (nie statyczne) zadeklarowane w klasie to zmienne instancyjne. Jeśli do zmiennej zadeklarowanej w klasie dodamy modyfikator static to staje się ona zmienną klasową. W ciele metody możemy zadeklarować zmienną lokalną. Ostatnim sposobem na deklarowanie zmiennych są parametry metod. W zależności od tego, z którą z powyższych deklaracji mamy do czynienia możliwe jest zastosowanie innego zestawu modyfikatorów. Przypomnę jeszcze, że możemy zadeklarować (i zainicjalizować) kilka zmiennych w jednej deklaracji, poprawne są więc deklaracje tej postaci:


int a = 0, b, c = 2;

Integer i = 5, j;


Przyjrzyjmy się teraz bliżej zmiennym instancyjnym. Są to te zmienne, które zostały zadeklarowane bezpośrednio w klasie i nie zostały oznaczone jako static. Zmienne instancyjne są inicjalizowane na domyślne wartości w chwili tworzenia instancji (a zmienne klasowe w momencie wczytywania klasy), tak więc nie muszą być inicjalizowane explicite. Zmienne te mogą mieć każdy z czterech zakresów widoczności, a więc dozwolony jest każdy z modyfikatorów: public, protected i private. Modyfikator widoczności może być również pominięty i wtedy obowiązywał będzie zakres domyślny. Zakresy widoczności działają analogicznie jak dla metod, co opisałem w artykule "SCJP - Modyfikatory widoczności w deklaracji metod i zmiennych". Ze zmiennej takiej możemy zrobić stałą dodając modyfikator final. Możemy też użyć słówka kluczowego transient oraz volatile, o których za chwilkę. Legalne jest także użycie względem zmiennej zadeklarowanej w klasie słówka kluczowego static, ale oznacza ono właśnie tyle, że nie jest to zmienna instancyjna tylko klasowa. Zmienne klasowe mogą być oznaczone tymi samymi modyfikatorami, co zmienne instancyjne.

Modyfikator transient jest znaczący w kontekście serializacji. Zmienne instancyjne oznaczone jako transient są ignorowane, tj. nie są serializowane i ich stan nie jest odtwarzany przy deserializacji. Modyfikator volatile jest istotny w kontekście programów współbieżnych a jego znaczenie wymaga dobrego zrozumienia zagadnień współbieżności - zadanie to odkładamy na później. Póki co zapamiętajmy tylko, że modyfikator volatile nie może być użyty w parze z modyfikatorem final, innymi słowy - stała nie może być volatile.

Zmienne lokalne, to zmienne zadeklarowane w ciele metod. W przeciwieństwie do zmiennych instancyjnych nie są one inicjalizowane na domyślne wartości, tak więc to programista ma obowiązek przypisać jakąś wartość zanim zmienna zostanie użyta. Zmienne lokalne mogą być oznaczone jedynie modyfikatorem final, co ma ten skutek, że wartość takiej zmiennej nie będzie mogła być zmieniona – będzie to stała. Zmienne będące parametrami metody również mogą być oznaczone tylko jako final. Ze zmiennymi lokalnymi wiąże się jeszcze jedno zagadnienie - przysłanianie zmiennych. Jeśli parametr metody, albo zmienna lokalna ma tą samą nazwę (typ nie ma znaczenia), co zmienna zadeklarowana w klasie, to zmienna zadeklarowana w klasie jest przysłonięta, tj. nazwa odnosi się do zmiennej lokalnej lub parametru metody, a odwołanie się do zmiennej zadeklarowanej w klasie wymaga użycia operatora ‘this’. Poniżej przykład ilustrujący to zagadnienie – efektem uruchomienia metody jest wypisanie cyfry 5 a następnie napisu "Ola ma kota".

public class TestClass {
String var = "Ola ma kota";

void test() {
int var = 5;

System.out.println(var);
System.out.println(this.var);
}
}

Pewnym szczególnym przypadkiem zmiennych są zmienne typu tablicowego (ang. array). Tablice mogą być zarówno jedno jak i wielo wymiarowe. Deklarując tablicę, która będzie zawierała elementy danego typu dodajemy po nazwie typu albo po nazwie zmiennej nawiasy kwadratowe ‘[]’, przy czym zdecydowanie zaleca się umieszczać je po nazwie typu. Poniżej kilka przykładów poprawnych deklaracji tablic, przy czym pierwsze dwie deklaracje są zgodne z zaleceniami a kolejne, mimo że poprawne stanowią przykład deklaracji nie eleganckich.

String[] names;

boolean[] [] allowances;

int codes[];

String[] names[];

Dla tych, którzy zanim zaczęli swą przygodę z Javą, programowali w takich językach jak C czy C++ powiem jeszcze wprost, że w Javie nie jest poprawnym określenie rozmiaru tablicy w deklaracji, nie jest np. poprawną deklaracja ‘int[2] codes’. Deklaracja jest tylko deklaracją - pamięć na tablicę jest alokowana dopiero wówczas, gdy tworzony jest obiekt tablicy i to wówczas istotny jest jej rozmiar.

Brak komentarzy: