Perché non viene generato alcun costruttore predefinito se si definisce un costruttore esplicito?

8
class Employee{

    String name;
    int id;

   //No explicit constructors
}

Ora posso richiamare la seguente dichiarazione:

Employee e1 = new Employee();

Con il codice sopra, il compilatore fornirà la definizione per il costruttore Employee() .

Se definisco un singolo costruttore esplicito come segue:

 class Employee{

    String name;
    int id;

    Employee(String aName){
        this.name=aName;
    }
}

Ora, perché non posso richiamare la seguente dichiarazione:

Employee e2 = new Employee();

Anche se il compilatore sa come fornire la definizione di Employee() .

Ora, solo perché ho definito un costruttore esplicito Employee(String aName) , perché non posso usare un costruttore predefinito?

Inoltre, se il compilatore avesse consentito l'uso del costruttore predefinito anche dopo averne definito uno esplicito, ci avrebbe aiutato a riutilizzare il codice per il costruttore predefinito.

    
posta Harish_N 03.10.2014 - 07:49
fonte

5 risposte

6

Prima di tutto, il costruttore predefinito non viene generato, è fornito dal compilatore se il costruttore di nessun argomento non è scritto in modo esplicito.

Quando non si scrive esplicitamente un costruttore no-argument per una classe, il compilatore non si lamenterà finché gli oggetti sono costruiti senza costruttori di parametri. (poiché il compilatore consente al costruttore predefinito di creare oggetti, che da solo chiama no -argument constructor).

Ma se definisci un costruttore senza argomenti, durante la compilazione, il compilatore controllerà la chiamata al costruttore e la sua definizione in classe. È come autenticare qualsiasi altro metodo di una classe.

Quindi darà un errore se chiami costruttore no-argument dopo aver definito un costruttore parametrizzato, dato che non trova alcun costruttore no-argument esplicitamente definito in classe. E, questo è logicamente corretto poiché, se si desidera bloccare la creazione di oggetti senza dati in esso, questo è un buon modo.

Ad esempio, considera che a un oggetto dipendente deve essere associato un ID dipendente. Per ottenere ciò, definire un costruttore di argomento singolo e non definire il costruttore senza argomenti.

    
risposta data 03.10.2014 - 19:27
fonte
38

Un costruttore con argomenti non è solo una comoda scorciatoia per usare setter. Scrivi un costruttore per assicurarti che un oggetto mai, mai esista senza che alcuni dati siano presenti.

Se non esiste un tale requisito, bene. Ma se ce n'è uno, come indicato dal fatto che hai scritto un tale costruttore, sarebbe irresponsabile generare un costruttore predefinito, attraverso il quale un client potrebbe eludere la regola "nessun oggetto senza dati". Sinceramente, perché il costruttore predefinito generato automaticamente è invisibile per un lettore di codice casuale, che nasconde il fatto che esiste! No, se vuoi i costruttori con argomenti e un costruttore predefinito, devi scrivere tu stesso il costruttore predefinito. Non è come se ci fosse un sacco di sforzo per scrivere un blocco vuoto, comunque.

    
risposta data 03.10.2014 - 09:56
fonte
8

Java che genera un costruttore senza parametri quando non ne hai è come un gentile cameriere che ti prende il cappotto.

Java continua a generare un costruttore senza parametri dopo aver definito un'altra versione di esso è come lo stesso cameriere che ti toglie il cappotto dopo aver dato una chiara indicazione che hai i tuoi piani su cosa fare con il cappotto.

Se ho una classe (che voglio essere immutabile):

class Person
{
    final String firstName;
    final String lastName;

E aggiungo un costruttore:

    Person(String firstName, String lastName) 
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

E Java doveva ancora fornire un costruttore predefinito, senza parametri, quindi questo codice non può essere compilato, perché i campi firstName e lastName sono dichiarati come finali, ma non vengono impostati dopo aver chiamato Person p = new Person() .

Mi stai costringendo a fornire un'altra implementazione:

private Person() 
{
    this.firstName = null; // or "", or whatever
    this.lastName = null;
}

E dal momento che non lo voglio - poiché è inutile, potrei sentirmi incline a mettere teschi e ossa incrociate su di esso:

@Deprecated
private Person() 
{
    // don't use this constructor! i don't want it to ever be called!
    throw new RuntimeException("Illegal constructor called");
}

Ma non posso ancora vietare a un altro sviluppatore di creare un metodo (all'interno della classe Person , quindi contrassegnare il costruttore come privato non ha aiutato):

public static Person createPerson()
{
    return new Person(); // this will blow in our face
}

Tutta questa confusione potrebbe essere - ed è - evitata grazie al fatto che Java (e non solo Java) funziona nel modo in cui funziona.

Se definisci un metodo setCoordinates(int x, int y) , non ti aspetti che il compilatore accetti automaticamente una versione senza parametri di esso - setCoordinates() . Non farebbe nulla.

In che modo è diverso dall'aspettarsi un costruttore senza parametri? Beh, ovviamente, un costruttore fa sempre almeno una cosa: crea un oggetto (o muore cercando).

Ma mi piace essere in controllo di come voglio che i miei oggetti siano istanziati. Costringermi ad avere un costruttore senza parametri, qualunque cosa faccia, toglie questo controllo da me.

    
risposta data 03.10.2014 - 11:14
fonte
3

La lingua inserisce il costruttore predefinito come favore per te. La presunzione è che se hai scritto un costruttore personalizzato, il tuo costruttore senza argomenti potrebbe richiedere anche un'attenzione speciale. Non un buon motivo, ma nemmeno orribile.

La ragione secondaria id che cruft si accumula su quel linguaggio senza alcun pensiero alla sua simmetria con la pratica esistente e pochissimo interesse nel renderla leggibile. L'originale "C with Classes" di Stoustroup era un preprocessore C compromesso che probabilmente non sarebbe dovuto uscire dal laboratorio. Il mondo è divertente in questo modo.

    
risposta data 03.10.2014 - 08:38
fonte
3

Se si definisce un costruttore con un parametro, è necessario che ci sia un motivo valido per farlo. Forse questo parametro è così importante per la tua classe che senza di esso lo stato dell'oggetto non è valido. Ecco perché Java non crea per te un costruttore senza argomenti quando ne hai già definito uno.

Se decidi che sarebbe utile avere un costruttore no-arg, puoi comunque definirlo:

Employee(){
  // good practice to call existing constructor with your favorite value
  this("");
}
    
risposta data 17.04.2015 - 23:29
fonte

Leggi altre domande sui tag