Generizität

Status
Nicht offen für weitere Antworten.

max5432

Aktives Mitglied
Hallo allerseits

Ich möchte von einer Collection eine deep copy (Klon-Objekt) machen und nutze dazu eine Methode namens getDeepCopy, die wiederum die Serialisierung einsetzt, um eine exakte Kopie des übergebenen Objekts (Collection mit gesamten Inhalt) zu erzeugen. Nun, das Problem ist folgendes:

Die überbegene Collection kann eine List-Instanz oder auch eine TreeSet-Instanz sein, wobei die in der Collection enthaltene Objekte vom Typ A oder vom Typ B sind. Dabei ist die Klasse B eine Subklasse der Klasse A (es gibt auch noch weitere Subklassen, aber hier nicht weiter relevant). Meine jetzige Lösung sieht wie folgt aus:

Java:
public static <T> ArrayList<T> getDeepCopy(ArrayList<T> param) throws Exception
    {
        ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
        new ObjectOutputStream(byteArrayOut).writeObject(param);
        ByteArrayInputStream byteArrayIn = new ByteArrayInputStream(byteArrayOut.toByteArray());

        return (ArrayList<T>) new ObjectInputStream(byteArrayIn).readObject();
    }

Wenn ich jetzt ein TreeSet übergeben möchte, muss ich in der Aufrufer-Methode zuerst den Inhalt aus dem TreeSet in eine ArrayList kopieren, diese zum klonen übergeben und anschliesesnd den in der zurückgegebenen ArrayList enthaltenen Inhalt wieder in ein TreeSet kopieren. Kann man machen, aber ich finde es nicht so elegant. Sicher könnte ich noch eine zweite Methode implementieren, die anstatt mit ArrayList halt mit TreeSet arbeitet. Ich frage mich, ob meine Methode getDeepCopy nicht so definiert werden könnte, dass sie mir den gleichen Collection-Typ zurückgibt, den sie auch erhalten hat. Sollte etwa so aussehen:

Java:
public static CollectionTyp<InhaltTyp> getDeepCopy(CollectionMitInhalt)
{
    // ... 
}

Kann man so was elegant lösen, ohne dass man mit getClass usw. hantieren muss und dass der Rückgabewert-Typ Collection wird, da etwas "zu allgemein". Das Ziel wäre eben, dass der Rückgabewert-Typ dem übergebenen Collection-Typ entspricht: ArrayList bzw. TreeSet. Und falls ja, wie sehe dies syntaxmässig aus?

Danke.
 
S

SlaterB

Gast
Java:
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        List<String> x = createList();
        x = getDeepCopy(x);
        Map<List<Map<Integer, String>>, JFrame> y = createMap();
        y = getDeepCopy(y);
    }

    @SuppressWarnings("unchecked")
    public static <T>T getDeepCopy(T o)
    {
        return (T)getDeepCopyO(o);
    }

    public static Object getDeepCopyO(Object o)
    {
        return o;
    }

    @SuppressWarnings("unchecked")
    public static <T>T createMap()
    {
        return (T)new HashMap();
    }

    @SuppressWarnings("unchecked")
    public static <T>T createList()
    {
        return (T)new ArrayList();
    }
}

die Methoden createList/Map sind nur eine zusätzliche Spielerei, habe mit deinem Problem nicht direkt zu tun

programmiere deepCopy mit Stream usw. nur einmal mit Object, alle anderen Methoden können das nutzen
 

0x7F800000

Top Contributor
Hab's jetzt nur kurz überflogen, die Idee mit der Serialisierung finde ich ehrlich gesagt ziemlich abgefahren: man will ja schließlich nur zeugs hin und herkopieren, das will man evtl sogar schnell, da kann man sich doch nicht zwischendurch den Spaß erlauben, das ganze zu serealisieren und wieder zu deserialisieren... Ich versteh eigentlich überhaupt nicht wie das gehen soll, wo wird denn garantiert dass die enthaltenen Objekte serialisierbar sind?

Ich hätte da folgenden Vorschlag:
Java:
import java.util.*;

public class _ {
	
	public static interface Copier<X>{
		X copy(X x);
	}
	
	public static <T> void deepCopy(Collection<T> source, Collection<T> destination, Copier<T> copier){
		for(T t:source){
			destination.add(copier.copy(t));
		}
	}
	
	//beispiele
	//klasse mit clone
	private static class A{
		private int a;
		public A(int _a){
			a=_a;
		}
		@Override
		public String toString(){
			return "A["+a+"]";
		}
		@Override
		public A clone(){
			return new A(this.a);
		}
	}
	
	//klasse mit einem copykonstruktor
	private static class B{
		private int b;
		public B(int _b){
			b=_b;
		}
		public B(B b){
			this(b.b);
		}
		@Override
		public String toString(){
			return "B["+b+"]";
		}
	}
	
	public static void main(String..._){
		
		//A kopieren
		Collection<A> aSrc=new HashSet<A>();
		aSrc.add(new A(33));
		aSrc.add(new A(77));
		Collection<A> aDest=new LinkedList<A>();
		deepCopy(aSrc,aDest,new Copier<A>(){public A copy(A a){ return a.clone();}});
		System.out.println(aSrc+"\n"+aDest);
		
		//B kopieren
		Collection<B> bSrc=new LinkedList<B>();
		bSrc.add(new B(532));
		bSrc.add(new B(234));
		Collection<B> bDest=new ArrayList<B>();
		deepCopy(bSrc,bDest,new Copier<B>(){public B copy(B b){ return new B(b);}});
		System.out.println(bSrc+"\n"+bDest);
	}
}
Wenn man sowohl Quell- als auch Ziel-struktur übergibt, hat man da automatisch jede Freiheit die man will: man kann von beliebigen Strukturen in beliebige Strukturen umkopieren. Wie man kopiert, muss man im Kopierer genau spezifizieren: im Allg. ist es ja unklar, ob man die objekte klonen kann, ob es da copy-konstruktoren gibt, ob da irgendwelche factorys zum einsatz kommen oder sonstwas...

Irgendwie musste ich bisher nirgends eine tiefe kopie von irgendwas erzeugen... Wo braucht man denn sowas? ???:L


edit: bestaune gerade Slater's Lösung... Kann mir mal einer sagen, wozu sowas gut sein soll:
Java:
    public static Object getDeepCopyO(Object o)
    {
        return o;
    }
statt
Code:
getDeepCopyO(o)
kann man doch an jeder stelle genausogut
Code:
o
hinschreiben?! :bahnhof: Ich raff nix^^ :oops:
 
Zuletzt bearbeitet:
S

SlaterB

Gast
in die Methode soll der Serialsierungscode rein oder wie auch immer man kopieren möchte ;)
 
S

SlaterB

Gast
ich bin gewohnt unkritisch zu derartigen Themen, die nicht Teil der Frage sind ;)
Optimieren erst später oder so

für zig verschiedene serialisierbare Objekte wäre das auch einige Arbeit,
und wenn die Serialisierung vielleicht nur selten für 0.1 sec benötigt wird..
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben