Cześć, Amigo! Chciałbym opowiedzieć Ci o wewnętrznej strukturze zmiennych. Jak już wiesz, każda zmienna jest powiązana z obszarem pamięci, w którym przechowywana jest jej wartość.

– Tak. Opowiedziałeś mi o tym ostatnim razem.

– Świetnie. Dobrze, że pamiętasz. Wobec tego – przejdźmy dalej.

– Wszystkie typy złożone (obiektowe) składają się z prostszych. Te z kolei składają się z jeszcze prostszych. Aż wreszcie dochodzimy do typów prostych (prymitywów), których nie można dalej uprościć. Te właśnie typy nazywamy typami prostymi lub prymitywami. Na przykład int jest typem prostym, ale String jest typem złożonym, który przechowuje dane w tablicy znaków (w której każdy znak jest typem prostym char).

– Bardzo ciekawe. Kontynuuj.

– Typy złożone są tworzone przez grupowanie typów prostych. Takie typy nazywamy klasami. Kiedy w programie definiujemy nową klasę, deklarujemy nowy złożony typ danych. Jego danymi będą inne typy złożone lub typy proste.

Kod Java Opis
public class Osoba
{
   String imie;
   int wiek;
}
Deklarowany jest nowy typ złożony – Osoba.
Jego dane są przechowywane w zmiennej typu String (typ złożony) imie oraz w zmiennej typu int (typ prosty) wiek
public class Prostokat
{
   int x, y, szerokosc, wysokosc;
}
Deklarowany jest nowy typ złożony – Prostokat.
Składa się z czterech zmiennych int (typ prosty).
public class Kot
{
   Osoba wlasciciel;
   Prostokat terytorium;
   int wiek;
   String imie;
}
Deklarowany jest nowy typ złożony – Kot. Ma następujące zmienne:
wlasciciel, typ złożony Osoba
terytorium, typ złożony Prostokat
wiek, typ prosty int
imie, typ złożony String

– Na razie wszystko jest jasne, choć jest też dość dziwne.

– Duże (złożone) typy zawierają wiele małych (prostych) typów. Dlatego obiekty tych typów zajmują dużo pamięci - więcej niż zmienne typów prostych. Czasami nawet o wiele więcej. Wykonanie operacji przypisania dla takich zmiennych zajmowało wiele czasu i wymagało kopiowania dużych bloków pamięci. Dlatego zmienne typów złożonych nie przechowują samego obiektu, a tylko referencję do niego, tzn. jego czterobajtowy adres. To wystarczy, aby obsłużyć dane w takich obiektach. Maszyna Java obsługuje wszystkie wynikające z tego zależności.

– Nic z tego nie zrozumiałem.

– Wcześniej powiedzieliśmy, że zmienna jest jak pudełko. Jeżeli chcesz przechowywać w nim liczbę 13, możesz napisać 13 na kartce papieru i włożyć ją do pudełka.

– Ale wyobraź sobie, że musisz przechować w pudełku (zmiennej) coś większego. Na przykład psa, samochód lub sąsiada. Zamiast próbować wepchnąć do pudełka coś, czego nie można tam zmieścić, możesz zrobić coś łatwiejszego: użyć zdjęcia psa zamiast prawdziwego psa, tablicy rejestracyjnej zamiast prawdziwego samochodu lub numeru telefonu sąsiada zamiast samego sąsiada.

– Bierzemy kawałek papieru i zapisujemy na nim numer telefonu sąsiada. To jak referencja do obiektu. Jeśli zrobimy kopie kawałka papieru z numerem telefonu sąsiada i umieścimy je w kilku pudełkach, będziemy mieć kilka referencji do sąsiada. Ale, jak wcześniej, nadal mamy tylko jednego sąsiada. To ma sens, prawda?

– Ważną cechą tego sposobu przechowywania danych jest to, że możesz mieć wiele referencji do jednego obiektu.

– Ciekawe! Chyba rozumiem. Proszę, powiedz mi jeszcze – co się stanie, jeśli przypiszę zmienną typu złożonego do innej zmiennej tego samego typu złożonego?

– Wtedy dwie zmienne będą przechowywać ten sam adres. Oznacza to, że jeżeli zmienisz dane obiektu, do którego odwołuje się jedna zmienna, zmienisz dane, do których odwołuje się też druga zmienna. Obie zmienne odwołują się (są referencją) do tego samego obiektu. Oczywiście mogą też istnieć inne zmienne, które również przechowują referencje do tego obiektu.

– Co robią zmienne typów złożonych (referencje/klasy), jeśli nie przechowują referencji do obiektu? Czy to w ogóle możliwe?

– Tak, Amigo. Wyprzedzasz mnie swoim pytaniem. To jest możliwe. Jeśli zmienna typu referencyjnego (złożonego) nie przechowuje referencji do obiektu, przechowuje tak zwaną „referencję nieustaloną” lub „referencję o wartości null”. Zasadniczo – oznacza to, że odwołuje się ona do obiektu o adresie 0. Jednak maszyna Java nigdy nie tworzy obiektów z tym adresem, więc zawsze wie, że jeśli zmienna referencyjna zawiera 0, to nie wskazuje żadnego obiektu.

Kod Java Opis
String s;
String s = null;
Wyrażenia równoważne.
Osoba osoba;
osoba = new Osoba();
osoba = null;
Tworzymy zmienną osoba, której wartością jest null.
Przypisujemy do niej adres nowo utworzonego obiektu Osoba.
Przypisujemy do zmiennej wartość null.
Kot kot = new Kot();
kot.wlasciciel = new Osoba();
kot.wlasciciel.imie = "Bóg";
Tworzymy obiekt Kot i umieszczamy jego adres w zmiennej kot; kot.wlasciciel równa się null.
Ustawiamy wartość kot.wlasciciel na adres nowo utworzonego obiektu Osoba.
kot.wlasciciel.imie nadal ma wartość null.
Ustawiamy wartość kot.wlasciciel.imie na "Bóg".

– Czy dobrze Cię zrozumiałem? Zmienne dzielą się na dwa typy: proste i referencyjne. Typy proste przechowują wartości bezpośrednio, podczas gdy typy referencyjne przechowują referencje do obiektu. Typy proste obejmują int, char, boolean i wiele innych. Typy referencyjne obejmują wszystko inne. Do ich tworzenia używamy klas.

– Masz absolutną rację, mój chłopcze.

– Można powiedzieć, że wszystko już zrozumiałeś. Oto kilka zadań, które pomogą Ci utrwalić wiedzę.