Domanda

Recentemente stavo leggendo un po 'di Java e mi sono imbattuto in qualcosa di (un idioma?) nuovo per me: nel programma, anche le classi con più costruttori includevano sempre un costruttore vuoto. Ad esempio:

public class Genotype {
  private boolean bits[];
  private int rating;
  private int length;
  private Random random;

  public Genotype() {              //  <= THIS is the bandit, this one right here
    random = new Random();
  }

  /* creates a Random genetoype */
  public Genotype(int length, Random r) {
    random = r;
    this.length = length;
    bits = new boolean[length];

    for(int i=0;i<length;i++) {
        bits[i] =random.nextBoolean();
    }
  }

  /* copy constructor */
  public Genotype(Genotype g,Random r) {
    random = r;
    bits = new boolean[g.length];
    rating = g.rating;
    length = g.length;

    for(int i=0;i<length;i++) {
        bits[i] = g.bits[i];
    }

  }
}

Il primo costruttore non sembra essere un "reale" costruttore, sembra che in ogni caso verrà utilizzato uno degli altri costruttori. Allora perché quel costruttore è definito affatto?

È stato utile?

Soluzione

Non sono sicuro che il codice che stavi leggendo fosse di alta qualità (in passato ho rivisto alcuni codici bioinformatici e purtroppo spesso non è stato scritto da sviluppatori professionisti). Ad esempio, quel terzo costruttore non è un costruttore di copie e in genere ci sono problemi in questo codice, quindi non "leggerei troppo in esso".

Il primo costruttore è un costruttore predefinito. Inizializza solo il minimo indispensabile e consente agli utenti di impostare il resto con getter e setter. Altri costruttori sono spesso "costruttori di convenienza" che aiutano a creare oggetti con meno chiamate. Tuttavia, ciò può spesso portare a incoerenze tra i costruttori. In effetti, esiste una ricerca recente che dimostra che è preferibile un costruttore predefinito con successive chiamate ai setter.

Ci sono anche alcuni casi in cui un costruttore predefinito è critico. Ad esempio, alcuni framework come digestore (utilizzato per creare oggetti direttamente da XML) utilizzano costruttori predefiniti. JavaBeans in generale usa costruttori predefiniti, ecc.

Inoltre, alcune classi ereditano da altre classi. potresti vedere un costruttore predefinito quando l'inizializzazione dell'oggetto padre è "abbastanza buono".

In questo caso specifico, se quel costruttore non fosse definito, si dovrebbero conoscere in anticipo tutti i dettagli. Non è sempre preferibile.

E infine, alcuni IDE generano automaticamente un costruttore predefinito, è possibile che chiunque abbia scritto la classe abbia avuto paura di eliminarlo.

Altri suggerimenti

L'oggetto Serializable ?

  

Per consentire la serializzazione di sottotipi di classi non serializzabili, il sottotipo può assumersi la responsabilità di salvare e ripristinare lo stato dei campi del pacchetto pubblico, protetto e (se accessibile) del supertipo. Il sottotipo può assumere questa responsabilità solo se la classe che estende ha un costruttore no-arg accessibile per inizializzare lo stato della classe. È un errore dichiarare una classe serializzabile se non è così. L'errore verrà rilevato in fase di esecuzione.

     

Durante la deserializzazione, i campi delle classi non serializzabili verranno inizializzati usando il costruttore pubblico o protetto no-arg della classe. Un costruttore no-arg deve essere accessibile alla sottoclasse serializzabile. I campi delle sottoclassi serializzabili verranno ripristinati dallo stream

Sì, accetto il "vuoto" Il costruttore non dovrebbe sempre esistere (nella mia esperienza i principianti spesso commettono questo errore), anche se ci sono casi in cui il costruttore vuoto sarebbe sufficiente. Tuttavia, se il costruttore vuoto viola l'invariante che tutti i membri sono correttamente istanziati dopo la costruzione , il costruttore vuoto non dovrebbe essere utilizzato. Se il costruttore è complicato, è meglio dividere la costruzione in diversi metodi protetti / privati. Quindi utilizza un metodo statico o un'altra classe Factory per chiamare i metodi protetti per la costruzione, se necessario.

Quello che ho scritto sopra è lo scenario ideale. Tuttavia, framework come spring rimuovono la logica del costruttore dal codice e in alcuni file di configurazione XML. Potresti avere funzioni getter e setter, ma probabilmente potresti essere evitato dall'interfaccia come descritto qui .

Il costruttore predefinito NON è obbligatorio.

Se nessun costruttore definito nella classe, allora il costruttore predefinito (vuoto) verrà creato automaticamente. Se hai fornito uno o più costruttori parametrizzati, il costruttore predefinito non verrà creato automaticamente ed è meglio crearlo da solo. I frame che usano l'iniezione delle dipendenze e la creazione dinamica del proxy in fase di runtime solitamente richiedono il costruttore predefinito. Quindi, dipende dai casi d'uso della classe che scrivi.

Il costruttore predefinito non è una buona pratica per la vista funzionale. Il costruttore predefinito viene utilizzato se l'oggetto ha una visibilità globale in un metodo: ad esempio, si desidera registrare lo stato effettivo di un oggetto in un tentativo / cattura puoi codificare

MyObejct myObject=null
try{...
}catch(Exception e){
    log.error(myObject);//maybe print null. information?
}

o preferisci

MyObejct myObject=new Object();
try{...
}catch(Exception e){
log.error(myObject);//sure print  myobject.toString, never null. More information
}

Inoltre, creare un oggetto VUOTO non ha molta logica, ma istatare un oggetto NULL è dannoso secondo me. Puoi leggere questo post

NON è un costruttore di copie. Fondamentalmente vuoi costruttori vuoti quando lavori con un framework. Ci sarà sempre un costruttore vuoto, ovviamente pubblico o privato, ma almeno ti permetterà di mantenere il controllo su come la classe viene (o meno) istanziata.

Di solito scrivo un costruttore che inizializza completamente l'oggetto; se ce ne sono altri, lo chiamano tutti (...) con le impostazioni predefinite appropriate.

Un oggetto deve essere inizializzato al 100% e pronto per l'uso quando viene creato.

Alcuni framework, ad esempio Hibernate, richiedono un costruttore no-arg. Il modo in cui si scontrano con le migliori pratiche a volte mi mette a disagio.

Avere un costruttore predefinito e vuoto (vuoto) ti impedisce di avere tutti i campi finali. Ciò porta a molta mutabilità laddove spesso non è necessaria.

Il modello builder consente di mescolare questi due stili e consentire un'inizializzazione più flessibile pur mantenendo l'immutabilità nascondendo un costruttore a molti argomenti dietro la fabbrica.

Per alcune classi POJO o classi semplici, il costruttore predefinito è utile quando a volte si desidera eseguire test di unità sulla classe utilizzandoli. Non è necessario deriderli, è possibile creare un nuovo oggetto con il costruttore predefinito e testare il set di valori e ottenerli o passarli come argomento.

Vuoi creare un costruttore vuoto per le classi che lo hanno esteso classe e poiché è stata estesa la classe ... il bambino ora ha super che fa riferimento alla classe sopra di essa è genitore. Nel caso in cui il bambino non specifichi super (roba) ... la roba all'interno per fare riferimento agli altri costruttori per usarla ora tenterà di fare riferimento al costruttore vuoto.

Non sono sicuro di quale sarà l'errore, sto codificando la mia prima relazione con l'oggetto genitore ora e stavo cercando cose qui.

Immagino che dovrei aggiungere il momento in cui crei un costruttore che non è quello vuoto, perdi quello vuoto predefinito, quindi ora super () che è predefinito nella classe estesa non avrà qualcosa a cui puntare. Naturalmente se hai creato le classi estese per occuparti del super specificando su quale si sbarazza del super () predefinito, allora lo elimini, ma cosa succede se qualcuno vuole usare la tua classe e estenderla e non ti rendi conto che non c'è ' t un set vuoto quando potresti averlo ne ho appena creato uno.

Questo è il mio primo post, ma volevo prendere una breccia da come lo capisco.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top