Zapis zmian

Kaa
  • Rejestracja:ponad 15 lat
  • Ostatnio:prawie 12 lat
0

Napisałem klasę której celem jest przechowywanie historii zmian w pewnym obiekcie. Chodziło o funkcje Undo i Redo. Moja klasa działa świetnie z prostą zmienną int niestety z obiektami klasy przechowującej dane już nie działa. Po debugowaniu okazało się że każdy zapisany obiekt jest jakby referencją do do obiektu który chciałem skopiować choć teoretycznie ze zmienną typu int czy String działało. Dlaczego z bardziej złożonymi obiektami nie chce działać ?
Poniżej podaje moje klasy.

Klasa odpowiedzialna za przechowywanie zmian

Kopiuj
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bibtexdescriptor;

/**
 *
 * @author Kaa
 */
public class ChangeManager<K> {
    int size = 0;
    Node<K> root;
    Node<K> current;
    int maxsize;

    public ChangeManager(K item) {
        size++;
        root = new Node<>(null, null, item);
        current = root;
    }
    public ChangeManager(K item, int maxsize) {
        size++;
        root = new Node<>(null, null, item);
        current = root;
        this.maxsize = maxsize+1;
    }
    
    public void addChange(K item){
        size++;
        Node<K> tep  = current;
        current = new Node<>(tep, null, item);
        tep.nastepny = current;
        if(maxsize>1 &&maxsize<size){
            root = root.nastepny;
            root.poprzedni = null;
            System.gc();
        }
    }

    public void setMaxsize(int maxsize) {
        this.maxsize = maxsize+1;
    }
    
    
    
    public boolean canUndo(){
        if(current.poprzedni!=null)return true;
        return false;
    }
    
        public boolean canRedo(){
        if(current.nastepny!=null)return true;
        return false;
    }
        
    public K undo(){
        if(canUndo()){
            size--;
            current = current.poprzedni;
            return current.obiekt;
        }else{
            throw new UnsupportedOperationException("Nothing to undo");
        }
    }
    public K redo(){
        if(canRedo()){
            size++;
            current = current.nastepny;
            return current.obiekt;
        }else{
            throw new UnsupportedOperationException("Nothing to redo");
        }
    }
    public int getSize(){
        return size;
    }
    
    public void trimToSize(int trim) {
        if (trim < size) {
            for (int i = 0; i < size - trim; i++) {
                root = root.nastepny;
                root.poprzedni = null;
                System.gc();
            }
        }
    }
    private class Node<K>{
        Node<K> poprzedni;
        Node<K> nastepny;
        K obiekt;

        public Node(Node<K> poprzedni, Node<K> nastepny, K obiekt) {
            this.poprzedni = poprzedni;
            this.nastepny = nastepny;
            this.obiekt = obiekt;
        }
    }
}

Klasa której obiekty chcę przechowywać

Kopiuj
class DataContainer implements Serializable{
    
    private PublicationType type;
    private HashMap<Enum, String> fields;
    private HashMap<Enum, String> oFields;
    private HashMap<String, String> userFields;
    private String name;

    public DataContainer(PublicationType type, HashMap<Enum, String> fields, HashMap<Enum, String> oFields, HashMap<String, String> userFields, String name) {
        this.type = type;
        this.fields = fields;
        this.oFields = oFields;
        this.userFields = userFields;
        this.name = name;
    }

    public PublicationType getType() {
        return type;
    }

    public HashMap<Enum, String> getFields() {
        return fields;
    }

    public HashMap<Enum, String> getoFields() {
        return oFields;
    }

    public HashMap<String, String> getUserFields() {
        return userFields;
    }

    public String getName() {
        return name;
    }
}
edytowany 1x, ostatnio: Kaa
M3
  • Rejestracja:około 14 lat
  • Ostatnio:około 3 lata
  • Postów:5
0

Już tłumaczę na czym polega problem: inty nie działają jak klasy.

Dla zobrazowania przykład.

Z intami:

Kopiuj
public class inty {
    public static void main(String[] args) {
    	int a = 1;
    	int b = 2;
    	a = b; // do zmiennej a przypisuję WARTOŚĆ zmiennej b
    	b = 3; // do zmiennej b przypisuję wartość 3    	
    	System.out.println(a); // 2 
    	System.out.println (b); // 3
    }
}

Z klasami:

Kopiuj
class klasa {
	int x;
	
	klasa(int x) {
		this.x = x;
	}
	
	int get() {
		return x;
	}
	
	void set(int x) {
		this.x = x;
	}
}

public class klasy {
    public static void main(String[] args) {
    	klasa a = new klasa(1);
    	klasa b = new klasa(2);
    	a = b; // do zmiennej a przypisuję REFERENCJĘ (a nie wartość) zmiennej b
    	b.set(3); // do zmiennej b przypisuję wartość 3    	
    	System.out.println(a.get()); // 3 a nie 2 
    	System.out.println (b.get()); // 3
    }
}

Niby jest to samo (tylko zamiast intów klasy), ale wynik inny. Dlaczego? Bo przypisała się referencja (tak jakby adres w pamięci, a nie kopia danych). Może to trochę dezorientujące, ale skąd kompilator ma wiedzieć jak skopiować dane z twojej własnej klasy (może to też ze względów bezpieczeństwa, żeby nie robić prosto kopii dużych danych - tak jak nie da się przekazać tablic do funkcji w C tylko przez wskaźniki)?

Typy prymitywne (np. int, double) kopiują. A klasy (np. twoja klasa, albo String - dlatego przy porównywaniu trzeba użyć metody equals zamiast ==, które porówna tylko referencję a nie zawartość Stringa) działają na referencjach.

Jest jednak rozwiązanie. Musisz sam zrobić metodę która skopiuje dane - czyli konstruktor kopiujący (lub przy porównywaniu - własna metoda porównywająca) - tzn. konstruktor z takim samym typem parametru jak klasa.
Tu rozwiązanie dla mojego przykładu:

Kopiuj
class klasa {
	int x;
	
	klasa(int x) {
		this.x = x;
	}
	
	klasa(klasa k) {
		this.x = k.x;
	}
	
	int get() {
		return x;
	}
	
	void set(int x) {
		this.x = x;
	}
}

public class klasy2 {
    public static void main(String[] args) {
    	klasa a = new klasa(1);
    	klasa b = new klasa(2);
    	a = new klasa(b); // do zmiennej a przypisuję kopię b (teraz jest jak w intach)
    	b.set(3); // do zmiennej b przypisuję wartość 3    	
    	System.out.println(a.get()); // 2 jak w intach
    	System.out.println (b.get()); // 3
    }
}
Q4
  • Rejestracja:około 12 lat
  • Ostatnio:ponad 11 lat
  • Postów:103
0

Poczytaj sobie o wzorcu projektowym memento.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.