Gettery i settery w Javie

2

@wioletta90 ech różne rzeczy "można" zrobić, ale raczej się nie zaleca. Tworzenie "pustego" obiektu a potem wypełnianie go danymi sprawia że:

  • obiekt jest mutowalny, bo jakoś trzeba było mu ustawić wartości, a mutowalność oznacza że ryzykujesz pracę z niespójnymi obiektami (np. przypadkiem gdzieś w kodzie dla któregoś obiektu nastąpi zmiana jakiegoś pola). Już nawet nie będę mówił jakie cuda się mogą dziać jak ktoś przypadkiem zmutuje sobie jakiś obiekt połączony z bazą danych (np. jakieś @Entity) i mu nagle wiersze z bazy zaczną znikać (tak tak, widziałem takie rzeczy w dużych systemach ;]).
  • masz obiekt który nie jest do końca zajnicjalizowany i ryzykujesz pracę z takim obiektem
  • łatwo przeoczyć jakiś setter kiedy jest ich dużo i dostajesz obiekt który nie jest poprawnie zainicjalizowany
2
Shalom napisał(a):

@wioletta90 ech różne rzeczy "można" zrobić, ale raczej się nie zaleca. Tworzenie "pustego" obiektu a potem wypełnianie go danymi sprawia że:

  • obiekt jest mutowalny, bo jakoś trzeba było mu ustawić wartości, a mutowalność oznacza że ryzykujesz pracę z niespójnymi obiektami (np. przypadkiem gdzieś w kodzie dla któregoś obiektu nastąpi zmiana jakiegoś pola). Już nawet nie będę mówił jakie cuda się mogą dziać jak ktoś przypadkiem zmutuje sobie jakiś obiekt połączony z bazą danych (np. jakieś @Entity) i mu nagle wiersze z bazy zaczną znikać (tak tak, widziałem takie rzeczy w dużych systemach ;]).
  • masz obiekt który nie jest do końca zajnicjalizowany i ryzykujesz pracę z takim obiektem
  • łatwo przeoczyć jakiś setter kiedy jest ich dużo i dostajesz obiekt który nie jest poprawnie zainicjalizowany

Ej jeszcze ja jedną rzecz mogę dodać !! jak masz mutowalny obiekt to brak gwarancji na visibility pomiędzy wątkami - final w immutable spowoduje wywołanie sfence pod spodem

0

W klasie Osoba brakuje Ci konstruktora, który przyjmie te dwa parametry.

Cały czas myślałam, że konstruktor służy tylko do tworzenia nowego obiektu, np.:

Osoba osobnik = new Osoba(imie, nazwisko);

bo za każdym razem gdy szukam informacji o konstruktorach to takie dostaję informacje zwrotne, długo nie wiedziałam o co chodzi... że brakuje mi konstruktora który coś przejmuje, dopiero po kilku godzinach szukania, przez przypadek na YT znalazłam jak ktoś pokazał że konstruktory można stworzyć a nie tylko wywołać.

Więc chyba muszę stworzyć coś takiego:

    public Osoba()
    {

    }

Wygląda banalnie, ale jak zrobić żeby to on coś przejmował ?

Z tego co przeczytałam, konstruktor się tworzy z jakimiś parametrami żeby później wywoływać go na rzecz tworzenia nowego obiektu, a z tego co mi tu wyszło w programie, wygląda na coś innego.

1

Tak jak w każdej innej metodzie. Różnica jest tylko w wywołaniu - jest wywoływany raz, automatycznie przy tworzeniu obiektu.

0
    public Osoba(imie, nazwisko)
    {

    }

to mi teraz imie podkreśla jako błąd

2

@wioletta90 jesteś bardzo blisko rozwiązania problemu. Przeanalizuj jeszcze raz kod, zobacz czy nie pomyliłaś się gdzieś (nawiasy, przecinki, średniki, etc).

Podsumowując masz:

  • Klasę Osoba która ma dwa pola (imię i nazwisko) oraz konstruktor, który ustawi te zmienne:
public Osoba(String imie, String nazwisko)
{
	this.imie=imie;
	this.nazwisko=nazwisko;
}
  • masz też klasę KlasaZMain z metodą main, w której tworzysz obiekt Osoba:
Scanner wczytywarka = new Scanner(System.in);
 
System.out.println("Podaj swoje imie: ");
String imie = pobierzDane(wczytywarka);
 
System.out.println("Podaj swoje nazwisko: ");
String nazwisko = pobierzDane(wczytywarka);
 
Osoba osobnik = new Osoba(imie, nazwisko);

Masz dwa oddzielne pliki Osoba.java i KlasaZMain.java?

0

Mam tylko Osoba.java

Mam taki błąd:

public static void main(String[] args)

a program proponuje usunąć static, dlaczego ?
Jeszcze nie widziałam metody main bez static.

1

Jest taka ogólna zasada w Javie - każdą klasę trzymamy w oddzielnym pliku. Oczywiście, są odstępstwa, ale póki co przyjmijmy, że tak jest. W jednym z ostatnich listingów wygląda, jakbyś pomyliła nawiasy {} i jakby KlasaZMain była zawarta w klasie Osoba. To powinny być dwie oddzielne klasy.

0

Faktycznie była zawarta w klasie Osoba. Zrobiłam jak mówisz, 2 oddzielnie pliki na klasy, błąd zniknął, został tylko podkreślony Scanner w dwóch miejscach, tam gdzie jest metoda pobierzDane

public class KlasaZMain {

	public static void main(String[] args) {
		Scanner wczytywarka = new Scanner(System.in);
		
		
		System.out.println("Podaj swoje imie: ");
		String imie = pobierzDane(Scanner);
		
		
		System.out.println("Podaj swoje nazwisko: ");
		String nazwisko = pobierzDane(Scanner);
		
		Osoba osobnik = new Osoba(imie, nazwisko);
	}

}

jak nie przekazywałam Scanneru jako parametr do metody pobierzDane, błędu nie było

1

A co tam przekazujesz? Scanner? A co to za obiekt wczytywarka?
pobierzDane(Scanner)

0

wcześniej moja metoda wyglądała tak:

  public static String pobierzDane() 
    {
        return wczytywarka.nextLine();
    }

i w taki sposób działała

String imie = pobierzDane();

a teraz mam

		public static String pobierzDane(Scanner wczytywarka) 
		{
		    return wczytywarka.nextLine();
		}

to powinno działać tak:

String imie = pobierzDane(Scanner wczytywarka) ; 

niestety nie działa, próbowałam też

pobierzDane(Scanner wczytywarka)
pobierzDane(wczytywarka)
pobierzDane()
3

@wioletta90 naucz sie skladni javy, bedzie to bardziej efektywne od probowania wlasnych wersji skladni ktore nawet sie nie kompiluja. w jezykach programowania nie jest tak jak w polskim czy angielskim ze rozmowca sie domysli o co chodzi.

0

O RLY? I jaki niby błąd pokazała wersja String imie = pobierzDane(wczytywarka);?

0

Chyba zapomniałaś zrobić:

import java.util.Scanner;
public static String pobierzDane(Scanner wczytywarka) 
        {
            return wczytywarka.nextLine();
        }
....
Scanner wczytywarka = new Scanner(System.in);
.....
String name = pobierzDane(wczytywarka);
0
Shalom napisał(a):

O RLY? I jaki niby błąd pokazała wersja String imie = pobierzDane(wczytywarka);?

podkresla mi pobierzDane a program proponuje stworzyć metode pobierzDane(Scanner), a taką już mam w klasie Osoba.java

3

o_O ale czemu masz ją w klasie Osoba? Przecież to w ogóle nie miałoby sensu.

PS: http://pl.indeed.com/Praca-Pomocnik-Piekarza zainteresuj się może :)

0

Przeniosłam metodę do main i nie ma już błędu.
Ogólnie chciałam rozbudować prosty program który pyta o imie, nazwisko aby były w nim gettery i settery, a tak się złożyło, że settery zostały usunięte, a gettery ? Chyba też nie są używane i można usunąć.

a więc o co chodzi ?

Finalna wersja:

Plik Osoba.java

package imie;

import java.util.Scanner;

public class Osoba {

	 private final String imie;
	    private final String nazwisko;
		
	    public Osoba(String imie, String nazwisko)
	    {
	        this.imie=imie;
	        this.nazwisko=nazwisko;
	    }
	    
	    public String getImie() {
	    	return imie;
	    }
	    
	    
	    public String getNazwisko() {
	    	return nazwisko;
	    }
	
	
	
}

Plik KlasaZMain.java

package imie;

import java.util.Scanner;

public class KlasaZMain {

	public static void main(String[] args) {

		Scanner wczytywarka = new Scanner(System.in);
		
		
		System.out.println("Podaj swoje imie: ");
		String imie = pobierzDane(wczytywarka) ; 
		
		
		System.out.println("Podaj swoje nazwisko: ");
		String nazwisko = pobierzDane(wczytywarka);
		
		Osoba osobnik = new Osoba(imie, nazwisko);
		
		
		
	}

	public static String pobierzDane(Scanner wczytywarka) 
	{
	    return wczytywarka.nextLine();
	}
	
	
}

0

Możesz teraz rozbudować program, żeby wyświetlał np. "Witaj, Imię Nazwisko", wtedy będziesz mogła użyć getterów ;)

0

Albo wczytaj w ten sposób 10 Osób do List<Osoba> a potem odfiltruj tych których imie zaczyna się na 'A' i juz się gettery przydadzą ;]

0

Możesz teraz rozbudować program, żeby wyświetlał np. "Witaj, Imię Nazwisko", wtedy będziesz mogła użyć getterów ;)

Zrobiłam tak bez getterów.

System.out.println(" Twoje imie: " + imie + " Twoje nazwisko: " + nazwisko );

Jak można zrobić to z getterami ?

Albo wczytaj w ten sposób 10 Osób do List<Osoba> a potem odfiltruj tych których imie zaczyna się na 'A' i juz się gettery przydadzą ;]

Chcę to zrobić, ale najpierw muszę o tym poczytać, bo aktualnie nic nie wiem na ten temat.
Znajdę to pod słowami kluczowymi tablicy,listy ? Coś takiego? Mam nadzieję że będzie tam przy okazji informacja jak odfiltrowywać.

0

@wioletta90 no brawo, ale ten kod który pokazałaś musiałby być w klasie Osoba, a nie da się tam wepchnąć wszystkich możliwych operacji jakie sobie wymyślisz. A zwykle w ogóle to inny obiekt coś chce robić z tymi twoimi Osobami.
Wyobraź sobie np. że piszesz grę w karty, w oczko na przykład. Masz klasę Karta która ma pole "wartość". W jaki sposób sprawdzisz czy ktoś wygrał/przegrał? Musisz zsumować wartość wszystkich jego kart. Jak to teraz zrobisz?

1

Jeżeli zaczynasz nie przejmuj się obiektami mutowalnymi, niemutowalnymi i skup się na getterach setterach

 
public class Osoba {
 
        private String imie;
        private String nazwisko;
 
       //dodaj te settery

        public String getImie() {
            return imie;
        }
 
 
        public String getNazwisko() {
            return nazwisko;
        }
}

Tera wyjaśnienie gettery i settery wzięły się z jakiś głupich praktyk, mówiono, że ukrywają implementację ale to głupota, tak się robi i już. Co nam tak dają na prawdę ?

  • atomowość operacji np:
 
public void setPoints(int x, int y){
 this.x = x;
 this.y = y;
}

|
W ten sposób wywołując

setPoints(5,2)

ustawimy współrzędne w jednej linijcie a za pomocą publicznych pól w dwóch linijkach.

  • możemy zabronić odczytu z pól i pozwolić zapisywać
    Jeżeli chcemy, żeby użytkownik tylko zapisywał do pól, ale nie mógł odczytywać generujemy setter i tyle. Zazwyczaj taki setter będzie świadczył o złej decyzji projektowej. Wszystkie inne kombinacje można ogarnąć słowami public private i final.

EDIT: chociaż ja jestem sceptycznie nastawiony do tego typu getterów/setterów są tacy co powiedzą, że są niezbędnę. Różnica poglądów, po prostu je generuj i tyle.

0

no brawo, ale ten kod który pokazałaś musiałby być w klasie Osoba

Dlaczego? Napisałam to w klasie KlasaZMain i działa.

W jaki sposób sprawdzisz czy ktoś wygrał/przegrał? Musisz zsumować wartość wszystkich jego kart. Jak to teraz zrobisz?

Każda karta miałaby przypisaną jakąś wartość i zmienną, więc wystarczyłoby dodać wszystkie zmienne ?

1

@wioletta90 haha no dobra, ale wtedy ten kod wcale nie operuje na obiekcie osoba tylko na ostatnich wczytanych wartościach do tych lokalnych zmiennych :D A to ma tyle wspólnego co picie w szczawnicy ze szczaniem w piwnicy. Zrób w takim razie 2 obiekty osoba i jak już będziesz miała osoba1 i osoba2 to wypisz imiona i nazwiska. Albo wypisz najpierw same imiona a następnie same nazwiska ;]

Każda karta miałaby przypisaną jakąś wartość i zmienną, więc wystarczyłoby dodać wszystkie zmienne ?

Ale jak chcesz wyciągnąć wartości tych zmiennych skoro to są prywatne pola klasy Karta?

0

Chyba już wiem o co chodzi, czyli kod ma wyglądać mniej więcej tak:

System.out.println(" Twoje imie: " + Osoba.getImie() + " Twoje nazwisko: " + Osoba.getNazwisko() );

bo zmienne mamy private, dlatego własnie są tu potrzebne gettery ?
Tylko żeby wywołać zmienne za pomocą getterów muszę zmienić gettery na static, przeczytałam że dopisek static pozwala na korzystanie z tego w metodzie main(), więc w sumie się zgadza, ale wtedy w getterach mam podkreślone imie i nazwisko, przez co program chce tam też dopisać static przy final,a a wtedy podkreślone znowu są zmienne w konstruktorze, a tu program znowu mówi żeby usunąć te finaly z początku klasy. To co z tym final ?

1

Musisz pamietać, że operujesz na utworzonym obiekcie klasy, czyli np. obiekcie osobnik.
Gettery nie powinny być static w przypadku Twojej klasy Osoba.

Popraw i zobacz jaki będzie efekt.

0

Popraw i zobacz jaki będzie efekt.

Faktycznie działa.

Zrób w takim razie 2 obiekty osoba i jak już będziesz miała osoba1 i osoba2 to wypisz imiona i nazwiska. Albo wypisz najpierw same imiona a następnie same nazwiska ;]

Chyba mi wyszło:

package imie;

import java.util.Scanner;

public class KlasaZMain {

	public static void main(String[] args) {

		Scanner wczytywarka = new Scanner(System.in);
		
		
		System.out.println("Podaj swoje imie: ");
		String imie = pobierzDane(wczytywarka) ; 
		
		System.out.println("Podaj 2 imie: ");
		String imie1 = pobierzDane(wczytywarka) ; 
		
		System.out.println("Podaj swoje nazwisko: ");
		String nazwisko = pobierzDane(wczytywarka);
		
		System.out.println("Podaj swoje nazwisko: ");
		String nazwisko1 = pobierzDane(wczytywarka);		
		
		Osoba osobnik = new Osoba(imie, nazwisko);
		
		Osoba osobnik1 = new Osoba(imie1, nazwisko1);
		
		System.out.println(" Imie1 : " + osobnik.getImie() + " Imie 2 : " + osobnik1.getImie() );
		
			
		System.out.println(" Nazwisko 1: " + osobnik.getNazwisko()  + " Nazwisko 2: " + osobnik1.getNazwisko() );
		
		
	}

	public static String pobierzDane(Scanner wczytywarka) 
	{
	    return wczytywarka.nextLine();
	}
	
	
}
0

a jak mogę rozbudować ten program żeby nie dało się uniknąć setterów ?

1

Jeżeli twoje pola są finalne to nie wygenerujesz setterów, chyba że tak:

 
public class Osoba {
 
     private final String imie;
        private final String nazwisko;
 
        public Osoba(String imie, String nazwisko)
        {
            this.imie=imie;
            this.nazwisko=nazwisko;
        }
 
        public String getImie() {
            return imie;
        }
 
 
        public String getNazwisko() {
            return nazwisko;
        }

public Osoba setImie(String imie) {
   return new Osoba(imie, nazwisko);
}

public Osoba seNaziwsko(String nazwisko) {
   return new Osoba(imie, nazwisko);
}
 
 
 
 
}

Ale nie rób tak

1

@wioletta90 jeśli chcesz używać setterów, musiałabyś usunąć final z atrybutów klasy Osoba i utworzyć settery dla imienia i nazwiska.

1 użytkowników online, w tym zalogowanych: 0, gości: 1