Mirki, uczę się #java i mam mały problem. Gdy wywołuję funkcję i jako argument użyję reference variable (jak to jest po polsku, zmienna referencyjna, czy po prostu referencja?), to obiekt do którego ona się odnosiła zostanie pozmieniany. Żeby tak nie było mogę albo pisząc fukncję stworzyć sobie nowy obiekt i skopiować do niego stary, albo utworzyć nowy obiekt i przesłać jego referencję jako argument. Załóżmy teraz, że mam jakąś klasę X, w której jedną ze zmiennych składowych jest referencja do obiektu klasy Y. Pisząc konstruktor do X, chcę, aby można było jako argument przesłać referencję do obiektu Y. Problem polega na tym, że jeśli po prostu skopiuję tę referencję, to potem w innych miejscach programu ten obiekt może się nieoczekiwanie pozmieniać. Z kolei jeśli skopiuję obiekt, to użytkownik tej klasy nie wie, że jest to zrobione w ten sposób (no chyba, że poszuka tego w kodzie) i może się okazać, że on też nie chce zmian w obiekcie, którego referencje będzie przesyłał jako argument, więc też stworzy sobie nowy, do którego przekopiuje stary i do niego prześle referencję. Przez to kilka razy niepotrzebnie tworzymy ten sam obiekt. I teraz pytanie: w jaki sposób powinienem to robić? a) kopiować w konstruktorze b) zostawić to użytkownikowi klasy, żeby sobie skopiował do nowego obiektu przed przekazaniem referencji c) wyjść z piwnicy d) zacząć uczyć się javy w wersji script Przepraszam, że takie to pogmatwane, nie potrafię tego za bardzo inaczej wytłumaczyć.
@Failar: po prostu referencja się nazywa. Jeżeli obiekt się nieoczekiwanie pozmienia to referencja ciągle będzie wskazywać na aktualny obiekt, a nie na stan obiektu z kiedy utworzyłeś referencję. Referencja to po prostu adres do pamięci gdzie zapisany jest obiekt. Coś jak link. Problem będzie tylko jeżeli usuniesz obiekt na który wskazuje referencja ale nie wiem jak działają referencje w Java bo nie znam tego języka i nie wiem co się stanie.
@Djuna: wiem jak działają referencje, nie do końca o to pytałem. Chodzi mi o to, którym sposobem zapobiegać zmianie stanu obiektu w nieoczekiwanych miejscach. Czy powienienem go przekopiować do nowego obiektu w funkcji, czy powinien robić to użytkownik, który tej funkcji chce użyć? Jeśli użyję rozwiązania pierwszego, to jak już pisałem, użytkownik nie wie czy ta funkcja zmienia obiekt, więc być może sam też będzie go kopiował przed przekazaniem argumentu i
@Failar: przekazuj go jako const ref? Albo w ogóle nie przekazuj samego obiektu tylko wrzuć go do private, a przekazuj tylko referencje (const ref lub kopie tam gdzie nie chcesz zmian i rw ref tam gdzie chcesz). W sumie to za bardzo nie umiem zrozumieć o co chodzi więc chyba zamilknę. :P
@Failar: Kolego kopiowanie obiektu wymagane jest zazwyczaj wtedy gdy korzystasz z wielowątkowości lub z jakichś względów potrzebujesz... kopii obiektu.
Problem polega na tym, że jeśli po prostu skopiuję tę referencję, to potem w innych miejscach programu ten obiekt może się nieoczekiwanie pozmieniać
Problem polega w Twoim błędnym rozumowaniu- jeżeli masz JEDEN wątek aplikacji- a zazwyczaj na początku pisze się jednowątkowe aplikacje i masz referencję do obiektu to działasz se po prostu
Ty kontrolujesz kiedy i co Ci się zmieni w obiekcie. Nic Ci magicznie nie zmieni obiektu O ILE sam o tym nie zadecydujesz.
Jeśli wyślę do funkji ten obiekt, to ona ma prawo go sobie dowolnie zmieniać, o czym ja nie będę świadomy (bo na przykład nie ja ją pisałem). Ale mi chodziło właściwie o drugą stronę. Może prościej na kodzie: http://pastebin.com/WPDAf1zE W ten
@Failar: przed zmianą referencji możesz zabezpieczyć obiekt jeżeli użyjesz słowa kluczowego final np. final dupa = new B(b); -> i tam Ci w środku choćby się zesrali to nie zmienią referencji. A zmianę właściwości/stanu obiektu zabezpieczysz stosując prywatne metody i pola (czyli słówko kluczowe private). Wywalasz "użytkownikowi" twojej klasy TYLKO to do czego ma mieć dostęp. Niestety, lub stety można zmodyfikować prywatne pola/metody przy użyciu użyciu mechanizmu refleksji- jednak jest to
@b0lec: C++, odrobinę, ale nie nazwałbym tego programowaniem. Rozpisałem bardziej o co mi chodzi: http://pastebin.com/BhDmeBAT W ten sposób zmienia się stan obiektu dupa w obiekcie a, mimo, że nic w obiekcie a go nie ruszało. Chodzi mi o to, że mogę temu zapobiec w kontruktorze tworząc nową kopię obiektu b, zamiast przepisywać referencję, tylko pytanie czy jest to dobre rozwiązanie?
@Failar: bez sensu kopiować obiekt gdy tego nie potrzebujesz. Przepisanie referencji jest jak najbardziej ok- czyli chodzi Ci o zapis dupa = b - jest to całkowicie ok. Sam często tak robię. Takie przypisanie w konstruktorze robi się po to aby metody mogły mieć dostęp do obiektu b. Jeżeli chcesz korzystać z danego obiektu tylko w danej klasie i czujesz że nie musisz go przekazywać- no to nie przekazuj bardzo dobrze-
@Failar: no coś w ten deseń, wyobraź sobie że w obiekcie który tworzysz ustawia Ci się znacznik czasu z bieżącą datą. Jednak gdy tworzysz nowy obiekt nie chcesz żeby Ci się ten znacznik ustawiał- w sensie z pewnych względów chcesz żeby znacznik był w drugim obiekcie taki sam- chcesz utrwalić stan obiektu. Wtedy przyda Ci się kopia. Przykład przyznam się szczerze raczej kiepski ale generalnie o to chodzi. I ogólnie takie
@Failar: i chyba łatwiej użyć konstruktora kopiującego niż bawić się z interfejsem Cloneable, pewnie oba podejścia mają swoje wady i zalety ale nie siedzę akurat w tym tak głęboko.
Załóżmy teraz, że mam jakąś klasę X, w której jedną ze zmiennych składowych jest referencja do obiektu klasy Y. Pisząc konstruktor do X, chcę, aby można było jako argument przesłać referencję do obiektu Y. Problem polega na tym, że jeśli po prostu skopiuję tę referencję, to potem w innych miejscach programu ten obiekt może się nieoczekiwanie pozmieniać. Z kolei jeśli skopiuję obiekt, to użytkownik tej klasy nie wie, że jest to zrobione w ten sposób (no chyba, że poszuka tego w kodzie) i może się okazać, że on też nie chce zmian w obiekcie, którego referencje będzie przesyłał jako argument, więc też stworzy sobie nowy, do którego przekopiuje stary i do niego prześle referencję. Przez to kilka razy niepotrzebnie tworzymy ten sam obiekt. I teraz pytanie: w jaki sposób powinienem to robić?
a) kopiować w konstruktorze
b) zostawić to użytkownikowi klasy, żeby sobie skopiował do nowego obiektu przed przekazaniem referencji
c) wyjść z piwnicy
d) zacząć uczyć się javy w wersji script
Przepraszam, że takie to pogmatwane, nie potrafię tego za bardzo inaczej wytłumaczyć.
Problem polega w Twoim błędnym rozumowaniu- jeżeli masz JEDEN wątek aplikacji- a zazwyczaj na początku pisze się jednowątkowe aplikacje i masz referencję do obiektu to działasz se po prostu
Jeśli wyślę do funkji ten obiekt, to ona ma prawo go sobie dowolnie zmieniać, o czym ja nie będę świadomy (bo na przykład nie ja ją pisałem). Ale mi chodziło właściwie o drugą stronę. Może prościej na kodzie:
http://pastebin.com/WPDAf1zE
W ten
final dupa = new B(b); -> i tam Ci w środku choćby się zesrali to nie zmienią referencji. A zmianę właściwości/stanu obiektu zabezpieczysz stosując prywatne metody i pola (czyli słówko kluczowe private). Wywalasz "użytkownikowi" twojej klasy TYLKO to do czego ma mieć dostęp.
Niestety, lub stety można zmodyfikować prywatne pola/metody przy użyciu użyciu mechanizmu refleksji- jednak jest to
Rozpisałem bardziej o co mi chodzi:
http://pastebin.com/BhDmeBAT
W ten sposób zmienia się stan obiektu dupa w obiekcie a, mimo, że nic w obiekcie a go nie ruszało. Chodzi mi o to, że mogę temu zapobiec w kontruktorze tworząc nową kopię obiektu b, zamiast przepisywać referencję, tylko pytanie czy jest to dobre rozwiązanie?
Takie przypisanie w konstruktorze robi się po to aby metody mogły mieć dostęp do obiektu b.
Jeżeli chcesz korzystać z danego obiektu tylko w danej klasie i czujesz że nie musisz go przekazywać- no to nie przekazuj bardzo dobrze-