Twitter: @grzegg
Kategoria: java, Tagi: - - - - .

Java [23] – Klasy i obiekty cz. 1

Wszystkie pisane dotychczas na kursie programy mieściły się w jednej klasie. W przypadku prostych programów może to wystarczyć, ale w bardziej złożonych tworzenie nowych klas może być bardzo pomocne a nawet niezbędne. W naszych programach korzystaliśmy też, mniej lub bardziej świadomie, z innych klas dostępnych w bibliotekach Javy. W większości przypadków tworzyliśmy na ich podstawie obiekty, w innych wywoływaliśmy umieszczone w nich metody bezpośrednio.

Terminy „klasa” i „obiekt” były zatem już używane na kursie, ale nie do końca zostało wyjaśnione czym są i jakie są między nimi relacje. Teraz przyszedł na to czas. Potem zajmiemy się tworzeniem własnych klas i obiektów, co pozwoli pisać programy o znacznie wyższym stopniu złożoności niż dotąd.

Czym są klasy i obiekty

Java należy do obiektowych języków programowania co wskazuje na kluczową rolę jaką odgrywają w niej obiekty. Zrozumienie czym są obiekty i czym są klasy oraz jakie relacje wiążą jedne z drugimi jest kluczowe dla zrozumienia i efektywnego wykorzystania Javy. Zacznijmy od obiektów.

Obiekty w języku programowania mają wiele cech wspólnych z obiektami znanymi w realnym świecie. Jako przykład niech nam posłuży telefon komórkowy. Każde urządzenie tego typu posiada pewne cechy i przechowuje pewne informacje. Cechy to np. marka, model, kolor, rodzaj ekranu, informacje to numer telefonu (o ile posiada kartę SIM), kontakty, przechowywane zdjęcia itd. Przy opisie telefonu komórkowego zarówno cechy ja i przechowywane informacje można określić jako dane telefonu. Poza tym używając telefonu można wykonywać pewne czynności, na przykład wykonać połączenie, odebrać je, wysłać SMS, odebrać SMS, wyszukać kontakt, dodać kontakt itp.


Jeśli chcielibyśmy stworzyć w programie „wirtualny telefon”, musielibyśmy stworzyć coś, co z jednej strony przechowywałoby definiowane przez nas dane określonego typu, a z drugiej pozwalałoby na wykonanie pewnych czynności. To „coś” to właśnie obiekt. Obiekt jest więc pewną całością pozwalającą przechowywać dane i przeprowadzać operacje, także na przechowywanych przez siebie danych.

Przypomnij sobie na przykład w jaki sposób sprawdzaliśmy czy dwa ciągi znaków do siebie pasują:


String haslo = "przebiegle#HASLO!237";
String podajHaslo = "admin123"
if (haslo.equals(podajHaslo))
   System.out.println("Zapraszam do skarbca");
else
   System.out.println("Uwaga Intruz!");

W powyższym przykładzie najpierw zostały stworzone dwa obiekty typu String, każdy z nich przechowywał inny ciąg znaków. Później jeden z nich wykonał czynność sprawdzenia, czy przechowywany przez niego ciąg znaków jest taki sam jak ciąg znaków przechowywany przez drugi obiekt i w zależności od wyniku testu zwrócił wartość true lub false.

Wróćmy teraz do telefonów komórkowych. Projektując wirtualną „komórkę” należy umożliwić przechowywanie przez niej danych a także wykonywanie wymaganych operacji. Nietrudno się domyślić, że do pierwszego zadania przydadzą się zmienne oraz bardziej złożone struktury, jak np. tablice, a do drugiego będą służyć metody. Jedno i drugie należy umieścić w odpowiedniej klasie. Klasa jest czymś w rodzaju projektu na podstawie którego tworzony jest obiekt. Elementy klasy, które służą do przechowywania danych (zmienne, tablice itd.) nazywamy polami.


Mówimy, że tworzony obiekt jest więc „typu” klasy na podstawie której jest tworzony, na przykład jeśli napiszemy klasę Telefon i na podstawie jej stworzymy obiekt, to będzie on obiektem typu Telefon. Analogicznie, kiedy tworzyliśmy obiekt typu String, używaliśmy do tego klasy String dostępnych gdzieś w bibliotekach Javy.

Na podstawie jednej klasy można stworzyć wiele obiektów, będą one mieć takie same pola i metody, ale każdy z nich będzie odrębną jednostką i może różnić się od pozostałych przechowywanymi danymi. Zauważ, że z podobną sytuacją mamy do czynienia w realnym świecie. Mówiąc „telefon jest użytecznym urządzeniem” mamy na myśli pewien abstrakcyjny obraz urządzenia, który posiada pewne cechy i można nim wykonywać określone czynności. Natomiast konkretny przedmiot, którego używamy do dzwonienia jest rzeczywistym „ucieleśnieniem” idei telefonu i posiada już konkretną markę, kolor, numer fabryczny itp.


Tworzymy wirtualne telefony

Mając już pewne pojęcie czym są klasy i obiekty stwórzmy kilka wirtualnych telefonów.

Jeśli w naszym programie będziemy używać wielu klas, muszą się one „widzieć”. Niektóre klasy Javy, które zainstalowaliśmy wraz z Java Development Kit, są widoczne w pisanych przez nas klasach automatycznie, inne należy dołączyć za pomocą instrukcji import (np. klasę Scanner). W przypadku klas umieszczonych w bibliotekach z poza dystrybucji Javy sprawa jest (nieco) bardziej skomplikowana i jeszcze do niej wrócimy. Na razie skupmy się na klasach, które sami będziemy pisać. Najprościej będzie jeśli zostaną one umieszczone w jednym pakiecie, wtedy będą mogły korzystać z siebie wzajemnie bez dodatkowych czynności.

Utwórz, jak zwykle, w NetBeans nowy projekt i pakiet, nazwij go telefony. W pakiecie powinny się znaleźć dwie klasy: zawierająca metodę main klasa Telefony oraz druga klasa o nazwie Telefon, której będziemy używać do tworzenia obiektów.
Nową klasę możemy dodać do pakietu klikając prawym klawiszem myszy w ikonę oznaczającą pakiet, następnie wybieramy New->Java Class i pokazuje się menu w którym uzupełniamy nazwę klasy i klikamy na „Finish”.

Najpierw zajmijmy się klasą Telefon:

Klasa jest bardzo prosta, zawiera trzy pola oraz cztery metody. Metody symulują wysyłanie i odbieranie SMS-ów oraz wykonywanie i odbieranie połączeń. Działanie dwóch pierwszych metod nie wymaga specjalnych wyjaśnień, do pozostałych wrócę za chwilę, kiedy poznamy sposób ich wykorzystania. Zauważ, że nie ma tu metody main.

Klasa Telefony wygląda następująco:

Początek to utworzenie dwóch obiektów typu „Telefon”: tel1 oraz tel2. Jak widać, wygląda to tak:


NazwaKlasy nazwaObiektu = new nazwaKlasy();

Następnie w obu zostają przypisane wartości polom wg. schematu:


nazwaObiektu.pole = wartość;

Pobranie wartości pola jest równie banalne:


nazwaObiektu.pole;

Zauważ, że każdy z obiektów ma inny zestaw wartości pól.

Dalsza część kodu to wywoływanie metod, które wygląda tak:


nazwaObiektu.metoda(argumenty);

Jeśli na danym obiekcie wywołujemy metodę, która korzysta z pól obiektu to oczywiście ich wartości odpowiadają tym przypisanym do tego konkretnego obiektu.

W wyniku uruchomienia kodu powinniśmy otrzymać taki rezultat:

Jestem produktem firmy LG mam kolor niebieski i numer 123456789

A ja jestem produktem firmy Apple mam kolor biały i numer 987654321

  • Wysyłam SMS na nr: 222333444
  • O treści: Pozdrowienia z kursu Javy

  • SMS: Witaj telefonie!

  • Ja, telefon marki LG o numerze 123456789

  • Dzwonię na nr: 987654321

Ja, telefon marki Apple o numerze 987654321

Odbieram połączenie od nr: 123456789

Warto szczególnie przyjrzeć się wywołaniu metody zadzwon. Przyjmuje ona jako argument obiekt typu Telefon. Okazuje się więc, że poszczególne obiekty w naszym programie mogą się komunikować i wykorzystywać się wzajemnie. W zasadzie nie powinno to być niczym zaskakującym, przecież robiliśmy to już wcześniej, na przykład porównując dwa łańcuchy znaków. Teraz jednak możemy przyjrzeć się dokładniej jak ten proces przebiega. Metoda zadzwoń zostaje wywołana na pewnym konkretnym obiekcie, ma ona więc dostęp do pól tego obiektu, ale ponieważ zostaje jej przekazany inny obiekt, ma również dostęp do jego pól oraz jego metod. Dzięki temu metoda zadzwon w obiekcie tel1 może uzyskać dostęp do danych w przekazanym jej obiekcie oraz wywołać na nim metody.

Przekazywanie obiektów jako argumentów

Uwaga! Jeśli przekazujesz obiekt jako argument, to pamiętaj o tym, że mamy to do czynienia z typem odnośnikowym. Co to w praktyce oznacza? Przypomnij sobie pierwszą lekcję poświęconą zmiennym. Napisałem tam, że na przykład int, double, boolean czy char są typami zmiennych (danych) typu podstawowego (prymitywnego), natomiast w przypadku tablic i innych obiektów mówimy o typach odnośnikowych (referencyjnych). To rozróżnienie okazało się istotne kiedy chcieliśmy w jednej z lekcji poświęconej tablicom, skopiować tablicę. Kiedy zastosowaliśmy sposób tablica2 = tablica1 otrzymaliśmy dwa odnośniki wskazujące na tą samą tablicę, wszelkie modyfikacje w tablicy1 wpływały na tablicę2 i odwrotnie. Podobny efekt uzyskamy przekazując obiekt jako argument do metody. Metoda nie będzie operowała na kopii obiektu ale na odnośniku obiektu, który przekazaliśmy jako argument. Jeśli więc dokonamy na nim jakichkolwiek modyfikacji, będą one widoczne także w kodzie metody z której przekazaliśmy obiekt. Najlepiej pokazać to na przykładzie.

Zmodyfikuj nieco klasę Telefon:

  • w miejscu gdzie znajdują się definicje pól dodaj linijkę: int liczbaPolaczen = 0;. W ten sposób zostało dodane nowe pole, które będzie zliczać liczbę odebranych połączeń. Na początku zmienna ma wartość 0.
  • na końcu metody odbierzPolaczenie dodaj komendę: liczbaPolaczen++;. Przy odebranym połączeniu wartość pola będzie się zwiększała o 1.

Teraz zmień końcówkę metody main w klasie Telefony na taką:


System.out.println("\n liczba połączeń: "+ tel2.liczbaPolaczen);
tel1.zadzwon(tel2);
System.out.println("\n liczba połączeń: "+ tel2.liczbaPolaczen);

Po uruchomieniu programy, końcowa część komunikatów będzie wyglądała następująco:


...
liczba połączeń: 0

  • Ja, telefon marki LG o numerze 123456789
  • Dzwonię na nr: 987654321

Ja, telefon marki Apple o numerze 987654321

Odbieram połączenie od nr: 123456789

liczba połączeń: 1

Co się stało?
Obiekt tel2, a właściwie odnośnik do niego, został przekazany do metody zadzwon w obiekcie tel1. Tam z kolei została na przekazanym obiekcie wywołana metoda odbierzPolaczenie, która m. in. zmieniła wartość pola liczbaPolaczen. Ponieważ cały czas operacje były wykonywane z wykorzystaniem odnośnika do obiektu tel1 a nie na jego kopii, rezultat jest widoczny także w metodzie main klasy Telefony.

Zadanie

Stwórz program w którym będzie utworzonych kilka obiektów typu Gatunek
Klasa Gatunek powinna zawierać:

  • pola przechowujące:
    • nazwę rodzaju
    • nazwę gatunkową
    • liczbę chromosomów 2n
    • podstawową liczbę chromosomów x
    • opis
  • metody:
    • podającą pełną nazwę (Rodzaj + gatunek)
    • podającą haploidalną liczbę chromosomów n
    • wypisującą wszystkie dane
    • klonującą obiekt – metoda powinna zwracać odnośnik do nowego obiektu typu Gatunek o wartościach pól takich samych jak w obiekcie, w którym została wywołana.

W programie powinny być użyte wszystkie metody.



4 komentarze Java [23] – Klasy i obiekty cz. 1

Leave a Reply