web-dev-qa-db-fra.com

Pourquoi aucun constructeur par défaut n'est-il généré si vous définissez un constructeur explicite?

class Employee{

    String name;
    int id;

   //No explicit constructors
}

Je peux maintenant invoquer la déclaration suivante:

Employee e1 = new Employee();

Avec le code ci-dessus, le compilateur fournira la définition du constructeur Employee().

Si je définis un seul constructeur explicite comme suit:

 class Employee{

    String name;
    int id;

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

Maintenant, pourquoi ne puis-je pas invoquer la déclaration suivante:

Employee e2 = new Employee();

Même si le compilateur sait comment fournir la définition de Employee().

Maintenant, juste parce que j'ai défini un constructeur explicite Employee(String aName), pourquoi ne puis-je pas utiliser un constructeur par défaut?

De plus, si le compilateur avait autorisé l'utilisation du constructeur par défaut même après en avoir défini un explicite, cela nous aurait aidés à réutiliser le code du constructeur par défaut.

9
Harish_N

Tout d'abord, le constructeur par défaut n'est pas généré, il est fourni par le compilateur si le constructeur sans argument n'est pas écrit explicitement.

Lorsque vous n'écrivez pas explicitement un constructeur sans argument pour une classe, le compilateur ne se plaindra pas tant que les objets sont construits sans constructeurs de paramètres (puisque le compilateur permet au constructeur par défaut de créer des objets, qui lui-même appelle le constructeur sans argument ).

Mais si vous définissez un constructeur sans argument, lors de la compilation, le compilateur vérifiera l'appel au constructeur et sa définition en classe. C'est comme authentifier n'importe quelle autre méthode d'une classe.

Il donnera donc une erreur si vous appelez un constructeur sans argument après avoir défini un constructeur paramétré, car il ne trouve aucun constructeur sans argument défini explicitement dans la classe. Et, c'est logiquement correct car, si vous souhaitez bloquer la création d'objets sans aucune donnée, c'est une bonne façon.

Par exemple, considérez qu'un objet employé doit être associé à un ID employé. Pour cela, définissez un constructeur à argument unique et ne définissez pas de constructeur sans argument.

6
Tyson

Un constructeur avec des arguments n'est pas seulement un raccourci pratique pour utiliser des setters. Vous écrivez un constructeur afin de vous assurer qu'un objet jamais, jamais existera sans la présence de certaines données.

S'il n'y a pas une telle exigence, très bien. Mais s'il y en a un, comme indiqué par le fait que vous avez écrit un tel constructeur, il serait irresponsable de générer un constructeur par défaut, par lequel un client pourrait contourner la règle "pas d'objet sans données". Doublement, car le constructeur par défaut généré automatiquement est invisible pour un lecteur de code occasionnel, ce qui cache le fait qu'il existe! Non, si vous voulez des constructeurs avec des arguments et un constructeur par défaut, vous devez écrire le constructeur par défaut vous-même. Ce n'est pas comme si c'était beaucoup d'efforts pour écrire un bloc vide, de toute façon.

38
Kilian Foth

Java générer un constructeur sans paramètre lorsque vous n'en avez pas, c'est comme un serveur poli prenant votre manteau pour vous.

Java génère toujours un constructeur sans paramètre après que vous en ayez défini une autre version, c'est comme le même serveur qui vous enlève le manteau après avoir donné une indication claire que vous avez vos propres plans de quoi faire avec le manteau.

Si j'ai une classe (que je veux être immuable):

class Person
{
    final String firstName;
    final String lastName;

Et j'ajoute un constructeur:

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

Et Java devait toujours fournir un constructeur sans paramètre par défaut, alors ce code ne peut pas être compilé, car les champs firstName et lastName sont déclarés comme définitifs, mais ils ne sont pas définis après avoir appelé Person p = new Person().

Vous me forcez à fournir une autre implémentation:

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

Et comme je n'en veux pas - comme c'est inutile, je pourrais me sentir enclin à y mettre le crâne et les os croisés:

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

Mais je ne peux toujours pas interdire à un autre développeur de créer une méthode (à l'intérieur de la classe Person, donc marquer le constructeur comme privé n'a pas aidé):

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

Tout ce tapage pourrait être - et est - évité grâce au fait que Java (et pas seulement Java) fonctionne comme il fonctionne).

Si vous définissez une méthode setCoordinates(int x, int y), vous ne vous attendez pas à ce que le compilateur en accepte automatiquement une version sans paramètre - setCoordinates(). Ça ne ferait rien.

En quoi est-ce différent de l'attente d'un constructeur sans paramètre? Eh bien, évidemment, un constructeur fait toujours au moins une chose - il crée un objet (ou meurt en essayant).

Mais j'aime être en contrôle sur la façon dont je veux que mes objets soient instanciés. Me forcer à avoir un constructeur sans paramètre quoi que je fasse me prive de ce contrôle.

8
Konrad Morawski

Le langage vous fait une faveur au constructeur par défaut. La présomption est que si vous avez écrit un constructeur personnalisé, votre constructeur sans argument peut également nécessiter une attention particulière. Pas une bonne raison, mais pas horrible non plus.

La raison secondaire qui a fait que la cruauté ne fait qu'empiler cette langue sans penser à sa symétrie avec la pratique existante et très peu d'intérêt à la rendre lisible. Le "C with Classes" original de Stoustroup était un préprocesseur C piraté qui ne devrait probablement pas sortir du laboratoire. Le monde est drôle comme ça.

3
msw

Si vous définissez un constructeur avec un paramètre, il doit y avoir une raison valable de le faire. Peut-être que ce paramètre est si important pour votre classe que sans lui, l'état de l'objet n'est pas valide. C'est pourquoi le Java ne fait pas de constructeur sans argument pour vous quand vous en définissez déjà un.

Si vous décidez qu'il serait pratique d'avoir un constructeur sans argument, vous pouvez toujours le définir:

Employee(){
  // good practice to call existing constructor with your favorite value
  this("");
}
3
MaxZoom