Problem z klonowaniem obiektu.

Problem z klonowaniem obiektu.
0

Witam
Mam problem z klonowaniem obiektu w javie.

Fragment klasy ListaOsob:

Kopiuj
public class ListaOsob implements Cloneable{
    List<Osoba> lista;

    public ListaOsob(){
        lista = new Vector<Osoba>();
    }

    @Override
    public ListaOsob clone(){
        try{
            ListaOsob nowa = (ListaOsob)super.clone();
            return nowa;
        }catch(CloneNotSupportedException e) {return null;}
    }

Osoba jest osobna klasa.

Probuje sklonowac obiekt o nazwie lista:
listaKopia = lista.clone();

Niestety gdy zmieniam jakies pole w obiekcie lista, zmiana zachodzi rowniez w obiekcie listaKopia

Z gory dziekuje za pomoc. Pozdrawiam.

Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:12 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
0

Bo ta implementacja metody clone jest felerna :) Musisz wykonać głębokie klonowanie listy:

Kopiuj

class Osoba implements Cloneable {

	@Override
	public Object clone() throws CloneNotSupportedException {
// różne warianty. Polecam jednak głębokie klonowanie
        }

}

class ListaOsob implements Cloneable {

	List<Osoba> lista;

	public ListaOsob() {
		lista = new Vector<Osoba>();
	}

	@Override
	public ListaOsob clone() {
		ListaOsob nowa = new ListaOsob();
		try {
			for (Osoba o : lista) {
				nowa.lista.add((Osoba) o.clone());
			}
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return nowa;
	}
}

Wykonane zostaje "głębokie konowanie", które powinno zostać też wykonane dla pól z klasy Osoba. Dzięki temu dostajesz nową, niezanieczyszczoną wersję obiektu.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
KA
  • Rejestracja:ponad 17 lat
  • Ostatnio:około 13 lat
0

Ponieważ w metodzie clone nie stworzyłeś nowej listy osób i referencja w nowym obiekcie odnosi się do starego obiektu. Aby ta metoda poniżej działała klasa Osoba też musi implementować metodę clone ;-)

Kopiuj
@Override
public ListaOsob clone(){
	try{
		ListaOsob nowa = (ListaOsob)super.clone();
		nowa.lista = new Vector<Osoba>()
		for (Osoba osoba: lista) {
			nowa.lista.add((Osoba)osoba.clone());
		}
		return nowa;
	}catch(CloneNotSupportedException e) {
                throw new InternalError();
        }
}

EDIT: Koziołek mnie ubiegł ;-P


"Jam częścią tej siły, która wiecznie zła pragnąc, wiecznie czyni dobro"
J.W. von Goethe "Faust"
0

Wielkie dzieki!! Dziala:).

KA
  • Rejestracja:ponad 17 lat
  • Ostatnio:około 13 lat
0

A ja mam taką ciekawostkę, chciałem sobie zrobić generyczną listę która by umożliwiała głębokie kopiowanie:

Kopiuj
public class ClonList<V extends Cloneable> {
	private List<V> list;

	public ClonList() {
		list = new ArrayList<V>();
	}

	public void add(V v) {
		list.add(v);
	}

	@Override
	public Object clone() {
		try {
			ClonList<V> clon = new ClonList<V>();
			clon.list = new ArrayList<V>();
			for (V v : list) {
				clon.list.add((V) v.clone());
			}
			return clon;
		} catch (CloneNotSupportedException e) {
			throw new InternalError();
		}
	}
}

I co ciekawe nie da się bo ta linijka zwraca błąd:

Kopiuj
clon.list.add((V) v.clone());

Znalazłem taką odpowiedź:
http://forums.sun.com/thread.jspa?threadID=5373687
Czy dało by się jakoś to ominąć :>


"Jam częścią tej siły, która wiecznie zła pragnąc, wiecznie czyni dobro"
J.W. von Goethe "Faust"
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:12 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
0

Ha... nadziałeś się na najbardziej buraczany błąd w API jaki jest, czyli protected dla metody clone(). Niestety nie można tego ominąć w prosty sposób. Jeżeli programujesz w czystej Javie bez takich fajerwerków jak GWT/DWR, czyli masz dostęp do refleksji to wystarczy, że wywołasz tą metodę za pomocą mechanizmu refleksji. Moja propozycja to ściągnięcie:
http://code.google.com/p/private-member-testing/ i zapoznanie się z metodą:
http://pmt.koziolekweb.pl/apidocs/pl/koziolekweb/pmt/PrivateMemberTester.html#runMethod%28java.lang.String,%20java.lang.Object,%20java.lang.Object[],%20java.lang.Class,%20java.lang.Class...%29

Jest to tylko jedna klasa, ale zrobiłem ją właśnie po to by uruchamiać metody na podstawie nazwy bez konieczności bezpośredniego grzebania w nich za pomocą refleksji.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
KA
  • Rejestracja:ponad 17 lat
  • Ostatnio:około 13 lat
0

Ciekawe rozwiązanie ;-) A czy czasami kiedyś metoda clone nie była publiczna ?


"Jam częścią tej siły, która wiecznie zła pragnąc, wiecznie czyni dobro"
J.W. von Goethe "Faust"
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:12 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
0

@kaziuuu, niestety z tego co pamiętam to nie (aż ściągnąłem api 1.1, by to sprawdzić). Zazwyczaj gdy ja nadpisujesz to zmieniasz na publiczną i dlatego jak już jej się używa to jako publicznej.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
RI
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 11 lat
0

A jest mozliwe sklonowanie zwyklej listy obiektow, ktore nie sa "obudowane" o klase? Tak jakby lista osob nie byla klasa tylko zwykla ArrayLista przechowujaca osoby?


Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:12 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
0

@riker, chodzi ci o coś w stylu:

Kopiuj
ArrayList<T> newList =list.clone();

Czyli mamy na wyjściu nową listę, którą można swobodnie zmieniać nie zmieniając oryginalnej?
Hm...
Własna metoda przepisująca obiekty:

Kopiuj
public List<?> rewrite(List<?> oryginalna){
   List<?> nowa = oryginalna.getClass().newInstance(); // taki sam typ listy
   for(Object o: oryginalna){
      nowa.add(o);
   }
   return nowa;
}

Coś w ten deseń.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
RI
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 11 lat
0
Koziołek napisał(a)

@riker, chodzi ci o coś w stylu:

Kopiuj
ArrayList<T> newList =list.clone();

Czyli mamy na wyjściu nową listę, którą można swobodnie zmieniać nie zmieniając oryginalnej?
Hm...
Własna metoda przepisująca obiekty:

Kopiuj
public List<?> rewrite(List<?> oryginalna){
   List<?> nowa = oryginalna.getClass().newInstance(); // taki sam typ listy
   for(Object o: oryginalna){
      nowa.add(o);
   }
   return nowa;
}

Coś w ten deseń.

Sprytnie ;] Dzieki


DM
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 14 lat
0

Nie wiem, czy wiecie, ale jest darmowa biblioteka do prostego, głębokiego klonowania: http://robust-it.co.uk/clone/. Odkąd ją odkryłem wątpię, żeby jeszcze kiedykolwiek potrzebował/chciał bawić się w zawiłości ręcznego klonowania, bo faktycznie fatalnie rozwiązali tą sprawę w Javie. Oto przykład jej użycia:

Kopiuj
import com.rits.cloning.Cloner;
...
private void pushState(){
	Cloner cloner = new Cloner();
	GameState stateClone = cloner.deepClone(currentState);
	stateStack.push(stateClone);
}

W ten sposób wykonujemy klon dowolnego obiektu, niezależnie od jego wewnętrznej konstrukcji. Są w tym api również inne metody, dające pełniejszą kontrolę nad przebiegiem klonowania. Ale szczerze mówiąc, nie miałem dotąd potrzeby się z nimi zapoznawać, bo najpowszechniejszy przypadek to właśnie głębokie klonowanie całego obiektu i od początku powinno to być w Javie tak proste jak z tą biblioteką ;).

KA
  • Rejestracja:ponad 17 lat
  • Ostatnio:około 13 lat
0

No prościej niż w tej bibliotece się chyba już nie da [green]


"Jam częścią tej siły, która wiecznie zła pragnąc, wiecznie czyni dobro"
J.W. von Goethe "Faust"
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)