Visualizzazione dei risultati da 1 a 6 su 6
  1. #1

    Clonazione di oggetti e super.clone

    Salve a tutti,
    oggi a lezione stavamo vedendo la clonazione di oggetti in java.
    Mi pare di aver capito che alcuni oggetti già hanno la loro implementazione del metodo clone oppure riescono ad utilizzare semplicemente quella generale di object (questo mi sfugge).

    Ad ogni modo in un esempio di creazione di una propria implementazione di clone, quindi implementando clonable, tale metodo grossomodo (a parte un try-catch per la gestione degli errori) sostanzialmente eseguiva questo codice:

    codice:
    class Myobject implements Cloneable{
    public Object clone(){
    Object o = null;
    o = super.clone();
    return o;
    }
    }
    Ora non capisco grossomodo cosa fa quel super.clone(). Cioè chiama il comando clone sulla superclasse e poi con il return lo ritorna? Cioè in realtà non reimplementa nulla in questo caso, tutto quel codice serve solo per rendere il clone di object da privato a pubblico o sbaglio?!

    Stavo guardando anche questo sito per un pò di esempi:
    http://www.cosenonjaviste.it/linterf...ava-cloneable/

    Non riesco però comuqnue a darmi conferma dell'interrogativo di sopra e mi nasce anche un dubbio sull'ultimo esempio che propone, ve lo riporto:

    codice:
    public Persona clone() {
    	try {
    		return (Persona) super.clone();
    	} catch (CloneNotSupportedException e) {
    		throw new RuntimeException(e);
    	}
    }
    
    Persona p1 = new Persona("Mario", "Rossi", "Via Firenze 1", new GregorianCalendar(2000, 0, 1).getTime());
    Persona p2 = p1.clone();
    p1.getDataDiNascita().setTime(System.currentTimeMillis());
    System.out.println(p1.getDataDiNascita().equals(p2.getDataDiNascita()));
    Secondo loro il metodo clone in quell'esempio darebbe problemi, anche se non ho capito perchè, ed andrebbe reimplementato così:

    codice:
    public Persona clone() {
    	try {
    		Persona p = (Persona) super.clone();
    		p.dataDiNascita = (Date) dataDiNascita.clone();
    		return p;
    	} catch (CloneNotSupportedException e) {
    		throw new RuntimeException(e);
    	}
    }
    Ricapitolando non riesco a capire questo loro esempio e perchè il metodo clone di sopra non andrebbe bene. Inoltre non riesco a capire se quel reimplementare Cloneable in quel modo chiamando semplicemente super.clone non sia semplicemente un modo per rendere pubblica l'implmentazione del metodo clone, o se in realtà aggiunge un qualcosa e se si cosa.

    Vi ringrazio in anticipo per l'attenzione,
    Neptune.
    "Estremamente originale e fantasioso" By darkiko;
    "allora sfiga crepuscolare mi sa che e' meglio di atmosfera serale" By NyXo;
    "per favore, già è difficile con lui" By fcaldera;
    "se lo apri te e invece di "amore" ci metti "lavoro", l'effetto è lo stesso" By fred84

  2. #2
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    1,123
    Dunque..noto non poca confusione..vediamo se riesco a chiarirti tutti i punti.

    Iniziamo con una cosa fondamentale: Object è la superclasse di tutte le classi in Java. Questo significa che tutti gli oggetti Java derivano
    da Object. Questa classe, tra gli altri metodi, dichiara protected Object clone(); la seguente funzione ritorna un oggetto uguale al chiamante,
    crea appunto un clone!

    L'interfaccia Cloneable (http://download.oracle.com/javase/6/...Cloneable.html) non ha implementazione, è vuota. Come dice
    la documentazione è solamente un "modo" per identificare gli oggetti clonabili da quelli non clonabili. Ad esempio GregorianCalendar implementa
    l'interfaccia Cloneable; questo significa che può essere clonata. Se crei una tua classe devi implementare l'interfaccia Cloneable...altrimenti,
    in caso contrario, otterrai una CloneNotSupportedException.
    Ovviamente, la clonazione avviene sempre tramite il metodo clone() definito da Object (che restituisce una copia dell'oggetto chiamante).


    Iniziamo con un esempio semplice. GregorianCalendar come abbiamo detto implementa clone, quindi può essere clonata.
    Se volessimo in una nostra applicazione clonare un GregorianCalendar dovremmo solamente fare:
    codice:
    // Ridefinito da Object
    public Object clone() {
      return super.clone(); // super sta ad indicare che la funzione da richiamare
                     // è nella superclasse (Object)
    }
    
    public void metodo(GregorianCalendar gc) {
      GregorianCalendar g = (GregorianCalendar) gc.clone();
      g.add(Calendar.DAY,1);
    }
    Qui l'oggetto g è un clone di gc. Per clonarlo è stato necessario creare una nostra versione del metodo supportato da Object (questo "creare una nostra
    versione" prende il nome di Override).


    [quote]
    Ora non capisco grossomodo cosa fa quel super.clone(). Cioè chiama il comando clone sulla superclasse e poi con il return lo ritorna?
    Cioè in realtà non reimplementa nulla in questo caso, tutto quel codice serve solo per rendere il clone di object da privato a pubblico o sbaglio?
    [/code]

    Il super.clone(), come detto, richiama quello della superclasse e ritorna così l'oggetto Clonato.
    Il clone di Object non è privato, ma è protected; questo significa che possono richiamarlo solamente le sue sottoclassi.


    La versione mostrata sopra ci costringe ad effettuare un cast.
    Sul sito, ti mostra questo esempio:
    codice:
    public Persona clone() {
    	try {
    		return (Persona) super.clone();
    	} catch (CloneNotSupportedException e) {
    		throw new RuntimeException(e);
    	}
    }
    
    Persona p1 = new Persona("Mario", "Rossi", "Via Firenze 1", new GregorianCalendar(2000, 0, 1).getTime());
    Persona p2 = p1.clone();
    p1.getDataDiNascita().setTime(System.currentTimeMillis());
    System.out.println(p1.getDataDiNascita().equals(p2.getDataDiNascita()));
    Questo essenzialmente è "uguale" a quello mostrato sopra.
    Come abbiamo detto, ogni oggetto è una sottoclasse di Object; questo significa che gli oggetti creati dal programmatore non fanno eccezione!
    La differenza è che in questo modo si fa già tornare un'istanza di Persona. Bada bene...questo è corretto con da java 1.6 (come dice sul sito, con
    una versione > alla 1.5 di Java, prima non era permesso); ora questa operazione è consentita poichè Persona è una sottoclasse di Object, quindi
    questa firma del metodo non crea problemi.

    Il loro metodo non da problemi! Lo reimplementano poichè suppongono la memorizzazione di un oggetto Date (ma possiamo supporre un GregorianCalendar),
    e questo oggetto non è immutabile (può essere cambiato). Se fai un clone dell'oggetto Persona, che al suo interno ha un Date (o GregorianCalendar o
    un oggetto mutabile) è necessario clonarlo al fine di avitare condivisioni di memoria.

    Ma chehe accadrebbe precisamente e praticamente?
    Praticamente, se non crei un clone anche dell'oggetto mutabile (Date nel loro caso) ti ritrovi con 2 oggetti che puntano allo stesso oggetto. Questo
    significa che modificando la data di un oggetto modifichi inevitabilmente anche l'altra.

    Se hai dubbi, chiedi!

  3. #3
    [QUOTE]Originariamente inviato da Patrick Jane
    Dunque..noto non poca confusione..vediamo se riesco a chiarirti tutti i punti.

    Iniziamo con una cosa fondamentale: Object è la superclasse di tutte le classi in Java. Questo significa che tutti gli oggetti Java derivano
    da Object. Questa classe, tra gli altri metodi, dichiara protected Object clone(); la seguente funzione ritorna un oggetto uguale al chiamante,
    crea appunto un clone!

    L'interfaccia Cloneable (http://download.oracle.com/javase/6/...Cloneable.html) non ha implementazione, è vuota. Come dice
    la documentazione è solamente un "modo" per identificare gli oggetti clonabili da quelli non clonabili. Ad esempio GregorianCalendar implementa
    l'interfaccia Cloneable; questo significa che può essere clonata. Se crei una tua classe devi implementare l'interfaccia Cloneable...altrimenti,
    in caso contrario, otterrai una CloneNotSupportedException.
    Ovviamente, la clonazione avviene sempre tramite il metodo clone() definito da Object (che restituisce una copia dell'oggetto chiamante).


    Iniziamo con un esempio semplice. GregorianCalendar come abbiamo detto implementa clone, quindi può essere clonata.
    Se volessimo in una nostra applicazione clonare un GregorianCalendar dovremmo solamente fare:
    codice:
    // Ridefinito da Object
    public Object clone() {
      return super.clone(); // super sta ad indicare che la funzione da richiamare
                     // è nella superclasse (Object)
    }
    
    public void metodo(GregorianCalendar gc) {
      GregorianCalendar g = (GregorianCalendar) gc.clone();
      g.add(Calendar.DAY,1);
    }
    Qui l'oggetto g è un clone di gc. Per clonarlo è stato necessario creare una nostra versione del metodo supportato da Object (questo "creare una nostra
    versione" prende il nome di Override).


    Ora non capisco grossomodo cosa fa quel super.clone(). Cioè chiama il comando clone sulla superclasse e poi con il return lo ritorna?
    Cioè in realtà non reimplementa nulla in questo caso, tutto quel codice serve solo per rendere il clone di object da privato a pubblico o sbaglio?
    [/code]

    Il super.clone(), come detto, richiama quello della superclasse e ritorna così l'oggetto Clonato.
    Il clone di Object non è privato, ma è protected; questo significa che possono richiamarlo solamente le sue sottoclassi.


    La versione mostrata sopra ci costringe ad effettuare un cast.
    Sul sito, ti mostra questo esempio:
    codice:
    public Persona clone() {
    	try {
    		return (Persona) super.clone();
    	} catch (CloneNotSupportedException e) {
    		throw new RuntimeException(e);
    	}
    }
    
    Persona p1 = new Persona("Mario", "Rossi", "Via Firenze 1", new GregorianCalendar(2000, 0, 1).getTime());
    Persona p2 = p1.clone();
    p1.getDataDiNascita().setTime(System.currentTimeMillis());
    System.out.println(p1.getDataDiNascita().equals(p2.getDataDiNascita()));
    Questo essenzialmente è "uguale" a quello mostrato sopra.
    Come abbiamo detto, ogni oggetto è una sottoclasse di Object; questo significa che gli oggetti creati dal programmatore non fanno eccezione!
    La differenza è che in questo modo si fa già tornare un'istanza di Persona. Bada bene...questo è corretto con da java 1.6 (come dice sul sito, con
    una versione > alla 1.5 di Java, prima non era permesso); ora questa operazione è consentita poichè Persona è una sottoclasse di Object, quindi
    questa firma del metodo non crea problemi.

    Il loro metodo non da problemi! Lo reimplementano poichè suppongono la memorizzazione di un oggetto Date (ma possiamo supporre un GregorianCalendar),
    e questo oggetto non è immutabile (può essere cambiato). Se fai un clone dell'oggetto Persona, che al suo interno ha un Date (o GregorianCalendar o
    un oggetto mutabile) è necessario clonarlo al fine di avitare condivisioni di memoria.

    Ma chehe accadrebbe precisamente e praticamente?
    Praticamente, se non crei un clone anche dell'oggetto mutabile (Date nel loro caso) ti ritrovi con 2 oggetti che puntano allo stesso oggetto. Questo
    significa che modificando la data di un oggetto modifichi inevitabilmente anche l'altra.

    Se hai dubbi, chiedi!
    Un dubbio è risolto, ovvero quello dell'esempio del calendario, ovvero c'era bisogno di dare il clone anche del calendario perchè mutabile. Nell'altro caso erano tutti oggetti immutabili (le classi wrapper sono tutti immutabili, li avevamo delle stringhe, modellabili con le classi wrapper, quindi immutabili).

    Quello che non riesco a capire è se clone fa parte della superclasse object ed è protected, tutte le classi ereditano da object, non potremmo usare object anche senza specificare che implementano da clonable? o è solo un "infiochettattura" per riconoscerle?

    Poi il succo del discorso è che se abbiamo un oggetto composto da altri oggetti mutabili oltre che clonare l'oggetto stesso dobbiamo clonare anche gli oggetti di cui è composto. Se è composta da oggetto immutabili semplicemente diamo il clone sull'oggetto stesso e basta?

    In aula se non ricordo male c'era l'esempio dell'array di interi, clonando solo l'array in realta clonavamo solo l'alias, per avere veramente due oggetti dovevamo clonare singolarmente anche gli interi che ne facevano parte.
    Però qui ho un pò di confusione, se gli interi sono modellati da classi wrapper che sono immutabili, quando noi facciamo un operazione qualsiasi tra interi in realtà stiamo creando un nuovo oggetto (visto che sono immutabili al massimo ne creiamo di nuovi), ma allora com'è possibiel che in aula è stato detto che se non li cloniamo uno ad uno poi modificando uno modificheremo anche l'altro?

    -Mi spiego meglio: gli oggetti immutabili da quel che so quando ci fai operazioni sopra non fai altro che crearne di nuovi;

    -Le classi wrapper sono tutte immutabili da quel che so, quindi gli interi sono immutabili;

    -Se fai un operazione tra oggetti immutabili, nel nostro caso interi, non fai altro che creare un nuovo oggetto;

    - Ma allora se tanto devi sempre creare nuovi oggetti, non ha senso clonarli, ed anche non clonandoli se hai:

    A = 1,2,3

    crei B clone di A

    fai A[1] = 100;

    non fai altro che creare un nuovo oggetto intero, ovvero 100, e dire che A[1] non deve più puntare all'oggetto con valore 1 ma al nuovo oggetto con valore 100;
    Quindi B qualsiasi cosa fai su A non dovrebbe rimanere invariato?!? o mi è sfuggito qualcosa?
    "Estremamente originale e fantasioso" By darkiko;
    "allora sfiga crepuscolare mi sa che e' meglio di atmosfera serale" By NyXo;
    "per favore, già è difficile con lui" By fcaldera;
    "se lo apri te e invece di "amore" ci metti "lavoro", l'effetto è lo stesso" By fred84

  4. #4
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    1,123
    Originariamente inviato da Neptune
    Quello che non riesco a capire è se clone fa parte della superclasse object ed è protected, tutte le classi ereditano da object, non potremmo usare object anche senza specificare che implementano da clonable? o è solo un "infiochettattura" per riconoscerle?
    Come hai ben detto, l'implementazione dell'interfaccia è solo per dire che quella classe (quell'oggetto) può essere clonato. Io ti ho citato GregorianCalendar, ma potrei citarti anche ArrayList, LinkedHashSet, e tante altre classi. Tutte queste, anche se il programmatore "non lo sa", implementano cloneable...proprio come GregorianCalendar!


    Poi il succo del discorso è che se abbiamo un oggetto composto da altri oggetti mutabili oltre che clonare l'oggetto stesso dobbiamo clonare anche gli oggetti di cui è composto. Se è composta da oggetto immutabili semplicemente diamo il clone sull'oggetto stesso e basta?
    Se cloni un tuo oggetto che contiene ad esempio GregorianCalendar, ArrayList, e fai un clone sul tuo oggetto sarebbe bene clonare anche GregorianCalendar e ArrayList. Questo per il semplice fatto che ti ritroveresti con 2 riferimenti che puntano allo stesso oggetto!

    Il modo migliore per capire questo concetto è buttar giù un pò di codice. Creati una tua classe che contiene un Date (o un GregorianCalendar fai tu..ricorda che i metodi di Date, come setTime() sono deprecati) e stringhe od interi ad esempio. Crei un oggetto del tipo in questione e lo cloni; richiami i metodi per ottenere la data di entrambi gli oggetti, l'originale ed il clone, e confronti le date. Poi, fai la stessa cosa, ma facendo all'interno del metodo clone() la clonazione anche dell'oggetto Date...e poi vedi i risultati


    In aula se non ricordo male c'era l'esempio dell'array di interi, clonando solo l'array in realta clonavamo solo l'alias, per avere veramente due oggetti dovevamo clonare singolarmente anche gli interi che ne facevano parte.
    Però qui ho un pò di confusione, se gli interi sono modellati da classi wrapper che sono immutabili, quando noi facciamo un operazione qualsiasi tra interi in realtà stiamo creando un nuovo oggetto (visto che sono immutabili al massimo ne creiamo di nuovi), ma allora com'è possibiel che in aula è stato detto che se non li cloniamo uno ad uno poi modificando uno modificheremo anche l'altro?

    -Mi spiego meglio: gli oggetti immutabili da quel che so quando ci fai operazioni sopra non fai altro che crearne di nuovi;

    -Le classi wrapper sono tutte immutabili da quel che so, quindi gli interi sono immutabili;

    -Se fai un operazione tra oggetti immutabili, nel nostro caso interi, non fai altro che creare un nuovo oggetto;

    - Ma allora se tanto devi sempre creare nuovi oggetti, non ha senso clonarli, ed anche non clonandoli se hai:

    A = 1,2,3

    crei B clone di A

    fai A[1] = 100;

    non fai altro che creare un nuovo oggetto intero, ovvero 100, e dire che A[1] non deve più puntare all'oggetto con valore 1 ma al nuovo oggetto con valore 100;
    Quindi B qualsiasi cosa fai su A non dovrebbe rimanere invariato?!? o mi è sfuggito qualcosa?
    Hai un pò di confusione!
    Gli interi (intesi come int), come i double, float, char,... non sono oggetti! Si chiamano appunto tipi semplici, o tipi primitivi. Le classi Wrapper servono per avere una rappresentazione di un tipo sottoforma di oggetto.
    Le classi wrapper sono Integer, Double, Character, Boolean, Float, Byte, Short.

    Non ho capito bene che intendi comunque...puoi mostrarmi che ha fatto il prof?

  5. #5
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    1,123
    Ah, ho dimenticato una precisazione importante!
    Quando ho fatto l'esempio di GregorianCalendar o Date, citando anche altri oggetti, è ovvio che la stessa cosa vale per altri oggetti.
    Se hai un oggetto con al suo intero un riferimento ad un oggetti di altro tipo, clonando l'oggetto principale ti ritroverai con 2 oggetti clonati...ma l'oggetto al loro interno punterà alla stessa risorsa.

  6. #6
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    Originariamente inviato da Patrick Jane
    Ah, ho dimenticato una precisazione importante!
    Quando ho fatto l'esempio di GregorianCalendar o Date, citando anche altri oggetti, è ovvio che la stessa cosa vale per altri oggetti.
    Se hai un oggetto con al suo intero un riferimento ad un oggetti di altro tipo, clonando l'oggetto principale ti ritroverai con 2 oggetti clonati...ma l'oggetto al loro interno punterà alla stessa risorsa.
    sono i tipici problemi relativi alla clonazione: non ho letto tutta la discussione (perdonate), ma da quest'ultimo commento si evince che devi prestare molta attenzione al clone di un oggetto, devi considerare quanto profonda vuoi la clonazione (es ti può andare bene che l'oggetto interno non sia clonato) oppure una clonazione profonda (che è cura dello sviluppatore).
    In questo caso ogni oggetto contenuto nella classe deve essere clonabile e dentro il clone devi crearne una copia.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.