Settery i Gettery
Choć może tytuł lekcji wygląda tajemniczo to jest on ściśle powiązany z poprzednią lekcją – z modyfikatorami dostępu. Settery i Gettery – a szczególnie gettery ułatwiają nam pewien sposób przysłania pól. W tej lekcji będziemy skupiać się właśnie na przysłaniu pól.
Przypominasz sobie z pewnością modyfikator dostępu private – przysłania on wszystko tak, że metody i pola widzimy tylko z poziomu tej samej klasy. Przypuśćmy, że chcemy, aby dostep do pola był możliwy, a jego modyfikacja nie – co wtedy? Przykład trochę może teraz abstrakcyjny – weźmy przykład bardziej realistyczny.
Przypuśćmy, że mamy klasę User – przechowuje ona jakieś id, login, hasło oraz e-mail. Chcemy pozwolić na wyświetlanie id, loginu, hasła oraz e-mail – jednak chcemy zabronić modyfikacji id – ponieważ nasze założenie mówi, że id usera ma być unikalne. I co wtedy?
Wtedy z pomocą przychodzą nam tzw. Settery i Gettery. Czym, więc one są?
Co to jest…
Settery i Gettery w rzeczywistości to nic innego jak metody klasy (publiczne), dzięki którym możemy ustawiać wartość pola lub odczytywać jego wartość. Czyli mogą być przydatne – choć nasze pole będzie prywatne, to i tak dzięki np. Getterowi się do niego dostaniemy i odczytamy jego wartość. 😉
Klaska
Oczywiście do części pokazowej będziemy potrzebować jakieś prostej klasy: np. User.
public class User { private Long id; private String login; private String password; private String email; public User(Long id, String login, String password, String email) { this.id = id; this.login = login; this.password = password; this.email = email; } }
Póki co wszystko powinno być zrozumiałe. 😉
Gettery
Zacznijmy od Getterów – tak jak wspomniałem są zwykłe metody w klasie.
Ich jedynym obowiązkiem jest zwracanie wartości konkretnego pola.
Dodatkowo wyróżnia ich przedrostek get – np. getLogin().
Pola w klasie User są private, sprawdźmy czy możemy odczytać ich wartość w main.:
public class Main { public static void main(String[] args) { User user = new User(1l, "admin", "admin", "admin@example.com"); System.out.println("User id: " + user.id + ", user login: " + user.login); } }
Jak widać, nie mamy dostepu do pól – co się zgadza, w końcu są one prywatne.
Jeżeli Twój kod się nie kompiluje zawsze zerknij w błędy jakie wypluwa kompilator – na ich podstawie spróbuj wywnioskować błąd lub poszukać o nim informacji w internecie.
Dodajmy, więc metody get dla wszystkich pól – tak jak wspomniałem będą one miały za zadanie zwracać wartość konkretnego pola klasy.
public class User { private Long id; private String login; private String password; private String email; public User(Long id, String login, String password, String email) { this.id = id; this.login = login; this.password = password; this.email = email; } public Long getId() { return id; } public String getLogin() { return login; } public String getPassword() { return password; } public String getEmail() { return email; } }
Jak widzisz typ każdej metody jest odpowiednio dopasowany do typu pola – wiadomo, że skoro pole jest typu String to metoda, również musi zwracać String. 😉
Spróbujmy teraz dostać się do pól z poziomu main:
public class Main { public static void main(String[] args) { User user = new User(1l, "admin", "admin", "admin@example.com"); System.out.println("User id: " + user.getId() + ", user login: " + user.getLogin()); } }
Kod się kompiluje, a wynik programu jest taki:
User id: 1, user login: admin
Jak widać wartości pól z obiektu user się zgadzają. Dotarliśmy do pól pomimo, że są prywatne – dzięki pośrednikowi, którym jest getter.
Settery
Skoro gettery zwracają nam wartość – to jeszcze potrzebujemy czegoś do ustawiania wartości – są to właśnie settery.
Dzięki setterom możemy zmieniać wartości pól – choćby były prywatne. Nic nie stoi na przeszkodzie. 😉
Zdefiniujmy sobie w klasie User settery dla wszystkich pól – oprócz ID, w końcu chcemy aby było unikalne dla każdego użytkownika!
public class User { private Long id; private String login; private String password; private String email; public User(Long id, String login, String password, String email) { this.id = id; this.login = login; this.password = password; this.email = email; } public Long getId() { return id; } public String getLogin() { return login; } public String getPassword() { return password; } public String getEmail() { return email; } public void setLogin(String login) { this.login = login; } public void setPassword(String password) { this.password = password; } public void setEmail(String email) { this.email = email; } }
Teraz zmieńmy wszystkie możliwe pola i wyświetlmy ich wartości.
public class Main { public static void main(String[] args) { User user = new User(1l, "admin", "admin", "admin@example.com"); System.out.println("User id: " + user.getId() + ", user login: " + user.getLogin() + ", user email: "+user.getEmail() + ", user password: "+user.getPassword()); user.setLogin("nowy-admin"); user.setPassword("admin-password"); user.setEmail("updated-email@email.com"); System.out.println("User id: " + user.getId() + ", user login: " + user.getLogin() + ", user email: "+user.getEmail() + ", user password: "+user.getPassword()); } }
I teraz po uruchomieniu programu:
User id: 1, user login: admin, user email: admin@example.com, user password: admin User id: 1, user login: nowy-admin, user email: updated-email@email.com, user password: admin-password
Jak widać faktycznie wartości pól się zmieniły. 😉
Wszystko z głową…
O ile zazwyczaj stworzenie getterów dla wszystkich pól nie jest jeszcze samobójstwem – to stworzenie wszystkich setterów może być.
Tworząc wszystkie settery i gettery robimy to bezmyślnie – otrzymuje w końcu taką samą sytuację jakby nasze pola były publiczne – a nie prywatne. 😉
Dlatego jeżeli nasze pola nie są publiczne to setterów i getterów trzeba używać z głową – i samemu decydować jakie pole może się zmieniać (np. ID), a które nie. 😉
Podsumowując – starajmy się jak najbardziej zaostrzać dostęp do konkretnych pól i metod – aby były jak najmniej widocznie. Kiedyś zobaczysz tego zalety podczas pisania większego projektu. 😉
toString
Mówiłem Ci, że każdy obiekt ma w sobie kilka metod, kóre pochodzą z klasy Object.
Są one małą częścią naszej klasy i możemy tak naprawdę coś z tą częścią zrobić.
Mamy do dyspozycji metodę String toString() – która wyświetla informację o danym obiekcie. Domyślnie wyświetla ona nazwę i adres obiektu – czyli nic czytelnego dla użytkownika, lecz to nic możemy ją nadpisać – czyli przysłonić własną implementacją.
Postaraj się zdefiniować tą metodę w zadaniach, które są poniżej – wystarczy, że zdefiniujesz ją w ten sposób w swojej klasie:
public String toString() { return "Opis obiektu: to moje imie: " + name; }
Zwróć uwagę, że zwraca ona String – więc, aby faktycznie wyświetlić informację o obiekcie w konsoli trzeba jeszcze użyć System.out.println – taka mała wskazówka. 😉
Podsumowanie
Temat lekcji raczej lekki i lekko rozszerzający poprzednią lekcję na temat modyfikatorów dostępu – czas na zadania, których zabrakło pod poprzednią lekcją. 😉
- Stwórz klasę Dog z prywatnymi polami: imię oraz rasa psa. Zastanów się, dla których stworzyć gettery i settery – myślę, że imię psa można jeszcze zmienić, lecz rasę… 😉 Dla klasy zdefiniuj także toString() – dzięki, której wyświetlisz informację o obiekcie w konsoli.
- Stwórz klasę Human z polami: imię, nazwisko oraz wiek, stwórz klasę SuperHero, która będzie dziedziczyć po Human z polem superPower. Wychodząc z założenia, że możemy zmienić tylko wiek człowieka i superbohatera napisz odpowiednie settery i gettery. Dla klas zdefiniuj także toString() – dzięki, której wyświetlisz informację o obiektach w konsoli.
Rozwiązania zadań możesz znaleźc tutaj.
Nie ma co cisnąć aż tak bardzo setterów i getterów bo chyba nie są, aż tak bardzo skomplikowanym zagadnieniem – lepiej będzie poświęcić czas na ostatnie zagadnienie drugiego tygodnia – czyli tworzenia aplikacji. 😉
“i samemu decydować jakie pole może się zmieniać (np. ID), a które może. 😉” 😉
No cóż, albo można zmieniać – albo… zmieniać. 😉
Dzięki za poinformowanie o błędzie, już poprawione.