1. Budowa pamięci
Każdy komputer ma pamięć operacyjną. Czym ona jest, jakie ma właściwości i, co najważniejsze, jaką mamy z niej korzyść?
Każdy program (w tym programy napisane w Java) przed wykonaniem jest ładowany do pamięci operacyjnej. W pamięci operacyjnej znajdują się kod programu (który wykonuje procesor) oraz dane programu (które do pamięci umieszcza sam program).
Czym właściwie jest pamięć operacyjna i do czego można ją porównać?
Wyobraź sobie Excela 😎 Arkusz w Excelu składa się z komórek, a każda komórka ma swój unikalny numer (A1, A2, ... B1, B2). Znając numer komórki, zawsze można wpisać do niej jakąś wartość albo odczytać wartość, która jest w niej przechowywana. Pamięć komputera jest zbudowana w podobny sposób.

Program i jego dane podczas działania są przechowywane w pamięci. Cała pamięć komputera jest przedstawiona jako małe komórki – bajty. Każda komórka ma swój unikalny numer – 0, 1, 2, 3, ... (numeracja zaczyna się od zera). Znając numer komórki, możemy zapisać do niej jakieś dane lub je z niej pobrać. W jednych komórkach przechowywany jest kod programu – zestaw instrukcji dla procesora, w innych – dane tego programu. Numer komórki nazywa się także adresem komórki.
Procesor potrafi wykonywać instrukcje z programu załadowanego do pamięci. Prawie wszystkie instrukcje procesora to coś w rodzaju: pobierz dane z pewnych komórek → zrób z nimi coś → wynik umieść w innych komórkach.
Łącząc setki prostych instrukcji, otrzymujemy złożone i użyteczne działania.
Gdy w kodzie programu deklaruje się zmienną, zostaje dla niej przydzielony fragment nieużywanej jeszcze pamięci. Zwykle to kilka bajtów. Przy deklarowaniu zmiennej koniecznie trzeba wskazać typ informacji, którą program będzie w niej przechowywał: liczby, tekst lub inne dane. Bez znajomości typu nie wiadomo bowiem, jak duży blok pamięci należy przydzielić dla zmiennej.
U zarania informatyki programy operowały po prostu numerami komórek pamięci, ale później dla wygody programistów komórkom zaczęto nadawać nazwy. Unikalna nazwa zmiennej jest przede wszystkim dla wygody programistów: program w trakcie działania poradziłby sobie i z samymi numerami.
2. Zmienne w pamięci
W Java są 4 podstawowe typy danych do przechowywania liczb całkowitych. To byte, short, int i long.
| Typ | Rozmiar, bajtów | Pochodzenie nazwy |
|---|---|---|
|
|
Byte, ponieważ zajmuje jeden bajt pamięci |
|
|
Skrót od Short Integer |
|
|
Skrót od Integer |
|
|
Skrót od Long Integer |
W Java są także 2 typy zmiennoprzecinkowe — float i double:
| Typ | Rozmiar, bajtów | Pochodzenie nazwy |
|---|---|---|
|
|
Skrót od Floating Point Number |
|
|
Skrót od Double Float |
Za każdym razem, gdy wykonanie programu dochodzi do instrukcji tworzenia zmiennej, przydzielany jest dla niej niewielki obszar pamięci (rozmiar zależy od typu zmiennej).
Za adres zmiennej uznaje się adres pierwszej komórki przydzielonego dla niej bloku pamięci.
Programom w Java nie wolno bezpośrednio odwoływać się do pamięci. Cała praca z pamięcią odbywa się wyłącznie za pośrednictwem maszyny wirtualnej Java.
3. Typ String w pamięci
Typ String może przechowywać duże ilości danych, dlatego nie jest to po prostu typ danych, lecz pełnoprawny obiekt.
Same dane typu String (tekst) umieszcza się w specjalnym obiekcie, dla którego przydziela się pamięć, a adres tego obiektu umieszcza się w zmiennej, dla której również przydziela się pamięć.

- Zmienna a typu int zajmuje 4 bajty i przechowuje wartość 1.
- Zmienna b typu int zajmuje 4 bajty i przechowuje wartość 10,555. Przecinek – to nie część ułamkowa liczby, lecz separator rzędów. Część ułamkową oddziela się kropką.
- Zmienna d typu double zajmuje 8 bajtów i przechowuje wartość 13.001.
- Zmienna str typu String przechowuje wartość D12 – adres pierwszej komórki obiektu zawierającego tekst.
Obiekt typu String (zawierający tekst) jest przechowywany jako osobny blok pamięci. Adres jego pierwszej komórki jest przechowywany w zmiennej str.
4. Co się dzieje podczas przypisania
Jeszcze jedna ważna rzecz – jak działa przypisanie. Na przykład:
int a = 10;
int b = a;
b = 20;
System.out.println(a); // 10
W tym przykładzie w pamięci tworzone są dwie komórki: jedna dla a, druga dla b. Gdy piszemy b = a;, kopiowana jest wartość (10), a nie sam „pudełko”. Zmiany w b w żaden sposób nie wpływają na a.
Teraz analogicznie, ale z łańcuchami:
String s1 = "Hello";
String s2 = s1;
s2 = s2 + " World";
System.out.println(s1); // "Hello"
System.out.println(s2); // "Hello World"
Tutaj obie zmienne s1 i s2 wskazują na ten sam łańcuch "Hello" do momentu modyfikacji. Jednak gdy wykonujemy s2 = s2 + " World";, dla s2 tworzony jest nowy łańcuch "Hello World", a s1 wciąż wskazuje na stary łańcuch "Hello".
5. Dlaczego w programowaniu liczy się od zera
Ludzie bardzo często się dziwią, dlaczego w programowaniu prawie wszędzie przyjęto liczenie od zera. Chodzi o to, że jest bardzo wiele sytuacji, gdy liczenie od zera jest wygodniejsze (choć są i takie, w których wygodniej jest liczyć od 1).
Spróbuję podać analogię. Stoisz w długiej kolejce w sklepie. I nagle kasjer mówi, że wszyscy klienci, zaczynając od 20., niech przejdą do drugiej kasy. Jakie będą ich numery? 20, 21, 22, 23, ... Logiczne. A względem dwudziestego? 0, 1, 2, 3, ...
Gdy definiujemy grupę jako „numer pierwszego elementu” + „liczebność”, to wewnątrz grupy numery względne wychodzą +0, +1, +2, ...
W programowaniu jest tak samo. Jeśli twojej zmiennej przydzielono 100 bajtów pamięci i masz adres X – adres pierwszego bajtu, to jakie będą adresy wszystkich bajtów? X+0, X+1, X+2, ..., X+99. Oto otrzymaliśmy grupę bajtów z indeksami 0, 1, 2, 99.
Gdy myślimy o adresie względnym wewnątrz jakiegoś bloku danych, zawsze otrzymujemy numerację od zera. To jest pierwszy i najczęstszy powód liczenia od zera.
GO TO FULL VERSION