Metodo clone(), problemi con getter e setter

di il
6 risposte

Metodo clone(), problemi con getter e setter

Sto sistemando il codice scritto, ho questo errore da correggere:

"Mutable objects are those whose state can be changed. For instance, an array is mutable, but a String is not. Mutable class members should never be returned to a caller or accepted and stored directly. Doing so leaves you vulnerable to unexpected changes in your class state.

Instead use an unmodifiable Collection (via Collections.unmodifiableCollection, Collections.unmodifiableList, ...) or make a copy of the mutable object, and store or return the copy instead.

This rule checks that arrays, collections and Dates are not stored or returned directly."

Quindi in sostanza non devo far restituire la data direttamente ma devo clonarlo, e per questo leggo che c'è il metodo clone(). La mia classe ha questo attributo, ed i suoi get e set, ma se provo a clonare come faccio nel get mi chiede o di castare a Date o di cambiare il tipo di ritorno in Object, sembrndomi entrambe le soluzioni poco valide, cosa posso fare per evitare ciò?
private Date data;

public Date getData() {
		return data.clone();
	}

	public void setData(Date data) {
		this.data = data;
	}
Grazie

6 Risposte

  • Re: Metodo clone(), problemi con getter e setter

    WinstonSmith ha scritto:


    Mutable class members should never be returned to a caller or accepted and stored directly. Doing so leaves you vulnerable to unexpected changes in your class state.
    Riguardo questa affermazione, c'è da fare una doverosa precisazione. NON è ovviamente sempre tassativamente obbligatorio fare così! Dipende "chi" è il chiamante. Cioè bisogna conoscere bene anche il contesto in cui si opera.
    Se stai facendo una libreria che sarà poi usata da tante altre persone e non sai ovviamente chi/come userà la tua libreria ... allora sì, sarebbe bene prestare molta attenzione a questi aspetti di mutabilità vs immutabilità.
    Se invece stai facendo una singola applicazione, che è tutta sotto il tuo controllo .... beh, qui non è detto che devi andare a "cercare il pelo nell'uovo" su questi aspetti sempre e ovunque. Dipende ...
    Quindi quella affermazione va bene ma è da prendere con le "pinze" e da valutare/applicare in modo oculato secondo lo scenario specifico che si ha.

    WinstonSmith ha scritto:


    ma se provo a clonare come faccio nel get mi chiede o di castare a Date o di cambiare il tipo di ritorno in Object, sembrndomi entrambe le soluzioni poco valide, cosa posso fare per evitare ciò?
    Il Date (di java.util) ha un clone() ma ha come tipo statico di ritorno Object, non Date.
    Mettere nel tuo getter Object come tipo di ritorno, NO, non ha senso (sarebbe molto peggio). Il male minore sarebbe mettere un cast a Date:

    return (Date) data.clone();

    che comunque sbagliato non è. Se non ti piace il cast, si può sempre creare direttamente un nuovo Date:

    return new Date(data.getTime());

    Attenzione che se quel campo data può essere null, devi prenderlo in considerazione.
  • Re: Metodo clone(), problemi con getter e setter

    andbin ha scritto:



    Riguardo questa affermazione, c'è da fare una doverosa precisazione. NON è ovviamente sempre tassativamente obbligatorio fare così! Dipende "chi" è il chiamante. Cioè bisogna conoscere bene anche il contesto in cui si opera.
    Se stai facendo una libreria che sarà poi usata da tante altre persone e non sai ovviamente chi/come userà la tua libreria ... allora sì, sarebbe bene prestare molta attenzione a questi aspetti di mutabilità vs immutabilità.
    Se invece stai facendo una singola applicazione, che è tutta sotto il tuo controllo .... beh, qui non è detto che devi andare a "cercare il pelo nell'uovo" su questi aspetti sempre e ovunque. Dipende ...
    Quindi quella affermazione va bene ma è da prendere con le "pinze" e da valutare/applicare in modo oculato secondo lo scenario specifico che si ha.

    Il Date (di java.util) ha un clone() ma ha come tipo statico di ritorno Object, non Date.
    Mettere nel tuo getter Object come tipo di ritorno, NO, non ha senso (sarebbe molto peggio). Il male minore sarebbe mettere un cast a Date:

    return (Date) data.clone();

    che comunque sbagliato non è. Se non ti piace il cast, si può sempre creare direttamente un nuovo Date:

    return new Date(data.getTime());

    Attenzione che se quel campo date può essere null, devi prenderlo in considerazione.
    Sì, non si tratta di una applicazione in cui ho tutto sotto controllo, ma è "aperta" agli utenti, quindi come dici bisogna prestre attenzione a questo aspetto. Ricordo di un prof che diceva di evitare sempre il cast, perché indice di qualcosa che non funziona, per questo cercavo un alternativa, ma se non è sbagliato proseguo castando, sia nel getter che nel setter. Il campo può essere null, quindi devo inserire un controllo nei due metodi e procedere solo se è diverso da null? cosa accadrebbe altrimenti? Sempre grazie per la tua esperienza che metti a disposizione di noi "nuovi".
  • Re: Metodo clone(), problemi con getter e setter

    WinstonSmith ha scritto:


    ma se non è sbagliato proseguo castando, sia nel getter che nel setter.
    Il cast nel getter non è sbagliato .... è innocuo se il tuo campo data ha veramente un oggetto java.util.Date.

    Ma ATTENZIONE al setter. Nel setter NON devi usare il clone(), c'è un motivo ben preciso. Date è una classe estendibile, "qualcuno" potrebbe passarti un oggetto che estende Date e che ha il clone() "ravanato" o che magari restituisce un oggetto sottotipo di Date che si comporta poi in maniera inappropriata.
    Nel setter bisogna essere molto più "difensivi" ed è meglio costruire un nuovo Date espressamente anche per garantire che la tua classe contenga sempre un java.util.Date e non qualcos'altro di più specifico/strano.

    WinstonSmith ha scritto:


    Il campo può essere null, quindi devo inserire un controllo nei due metodi e procedere solo se è diverso da null? cosa accadrebbe altrimenti?
    Se il campo è null ... restituisci null.
  • Re: Metodo clone(), problemi con getter e setter

    Quindi qualcosa del genere:
    	public Date getDataAggiunta() {
    if(datAggiunta!= null){
    		return (Date) datAggiunta.clone();}
    else return null;
    	}
    
    	public void setDatAggiunta(Date datAggiunta() {
    		this.data = new Date(datAggiunta.getTime());

    andbin ha scritto:



    Se il campo è null ... restituisci null.
    Sì, intendevo cosa potrebbe accadere omettendo il controllo, se null o meno.
  • Re: Metodo clone(), problemi con getter e setter

    WinstonSmith ha scritto:


    Quindi qualcosa del genere:
    Più o meno .. salvo che anche nel setter dovresti gestire il null, se è lecito che ti venga passato ...

    andbin ha scritto:



    Sì, intendevo cosa potrebbe accadere omettendo il controllo, se null o meno.
    Un "bel" NullPointerException che ti schianta tutto


    Comunque, molto meglio se facessi una tua classe di "utilità" del tipo:
    import java.util.Date;
    
    public class CloneUtilities {
        private CloneUtilities() {}
    
        public static Date clone(Date date) {
            return date != null ? new Date(date.getTime()) : null;
        }
    
        // ....altri metodi eventuali....
    }

    E poi nel getter e setter usi semplicemente CloneUtilities.clone( ..... )
  • Re: Metodo clone(), problemi con getter e setter

    andbin ha scritto:



    Comunque, molto meglio se facessi una tua classe di "utilità" del tipo:
    import java.util.Date;
    
    public class CloneUtilities {
        private CloneUtilities() {}
    
        public static Date clone(Date date) {
            return date != null ? new Date(date.getTime()) : null;
        }
    
        // ....altri metodi eventuali....
    }

    E poi nel getter e setter usi semplicemente CloneUtilities.clone( ..... )
    Ottimo, grazie. Ed in effetti ci sono tante di quelle date che tornerebbe Mooolto utile una classe del genere, ma non avevo la libertà di poter inserire cose, dovevo solo applicare le correzioni indicate.
Devi accedere o registrarti per scrivere nel forum
6 risposte