web-dev-qa-db-fra.com

Comment une classe Java peut-elle ne pas avoir de constructeur sans argument?

Le site du tutoriel Java d’Oracle contient ce paragraphe qui m’embrouille:

Toutes les classes ont au moins un constructeur. Si une classe n'en déclare pas explicitement, le compilateur Java fournit automatiquement un constructeur sans argument, appelé constructeur par défaut. Ce constructeur par défaut appelle le constructeur sans argument du parent de la classe ou le constructeur Object si la classe n'a pas d'autre parent. Si le parent n'a pas de constructeur (Object en a un), le compilateur rejettera le programme.

Si tous les objets héritent directement ou indirectement d'Object, comment est-il possible de provoquer le rejet du compilateur dont il est question? Est-ce que cela a à voir avec le constructeur qui est privé?

17
offex

Si tous les objets héritent directement ou indirectement d'Object, comment est-il possible de provoquer le rejet du compilateur dont il est question?

Je pense que la base de votre malentendu est que vous pensez que les constructeurs sont hérités. En fait, les constructeurs ne sont pas hérités en Java. Alors, considérons l'exemple suivant:

public class A {
    public A(int i) { super(); ... }
}

public class B extends A {
    public B() { super(); ... }
}

La classe A:

  • n'hérite d'aucun constructeur de Object,
  • ne déclare pas explicitement un constructeur sans argument (c'est-à-dire public A() {...}), et
  • n'a pas de constructeur par défaut (puisqu'il en est déclaré par un autre constructeur).

Par conséquent, il a un et un seul constructeur: public A(int).

L'appel à super() dans la classe B essaie d'utiliser un constructeur no-args non existant dans A et génère une erreur de compilation. Pour résoudre ce problème, vous devez modifier le constructeur B afin qu'il utilise le constructeur A(int) ou déclarer un constructeur explicite no-args dans A.

(Incidemment, il n'est pas nécessaire qu'un constructeur appelle explicitement un constructeur de superclasse ... comme je l'ai fait. Mais beaucoup de gens le pensent. C'est un bon style pour inclure un appel explicite. Si vous le laissez pas, le compilateur Java insère un appel implicite au constructeur no-args des superclasses ... et entraîne une erreur de compilation si le no-args constructeur n'existe pas ou n'est pas visible pour la sous-classe.)

Est-ce que cela a à voir avec le constructeur qui est privé?

Pas directement. Cependant, la déclaration d'un constructeur privé empêchera ce constructeur d'être appelé à partir d'une classe enfant.

31
Stephen C

L'essentiel à comprendre est que le constructeur no-arg sera seulement généré automatiquement si la classe n'a pas déjà de constructeur.

Il est donc facile de créer une classe qui n'a pas de constructeur no-arg.

15
Arjan Tijms

La manière la plus simple de penser à ce problème est la suivante:

  1. Le constructeur non-args est fourni en tant que constructeur par défaut par Java pour toute classe que vous créez.

  2. Au moment où vous créez un constructeur personnalisé avec des arguments, Java déclare « hé, cette classe a un constructeur personnalisé, je ne vais donc pas me préoccuper de créer/fournir le constructeur par défaut non-args!

  3. En conséquence, votre classe NE dispose PAS du constructeur par défaut non-args.

  4. Cela signifie que lorsque vous créez une sous-classe, en fonction de votre classe, vous devez appeler explicitement le constructeur personnalisé à base d'arguments que vous avez créé.

9
TechThinker

Si vous avez une sous-classe d'une sous-classe

class A 
{
    A(int i) {..}
}

class B extends A 
{
}

Ici, le constructeur par défaut inséré dans B essaiera d'appeler le constructeur sans argument de A (qui n'existe pas) car il n'a qu'un constructeur prenant un argument

4
Carlo V. Dango

Oui. Un constructeur privé est un constructeur d'instance spéciale. Il est couramment utilisé dans les classes contenant uniquement des membres statiques. Si une classe a un ou plusieurs constructeurs privés et aucun constructeur public, les autres classes (à l'exception des classes imbriquées) ne sont pas autorisées à créer des instances de cette classe.

La déclaration d'un constructeur privé empêche la génération automatique d'un constructeur par défaut.

MODIFIER:

Une classe définie dans une autre classe Est appelée une classe imbriquée. Comme les autres membres d'une classe, une classe imbriquée peut être déclarée statique ou non. Une classe imbriquée Non statique est appelée une classe interne . Une instance d'une classe Interne ne peut exister qu'au sein d'une instance De sa classe englobante et A accès aux membres De sa classe englobante même s'ils sont déclaré privé .

1
ukhardy

La superclasse immédiate de l'objet doit avoir un constructeur protégé ou public (ou aucun constructeur, auquel cas un constructeur sera créé). Ainsi, si je crée une classe qui étend Object, avec un constructeur privé uniquement, rien ne pourra étendre ma classe.

1
Neil

Cela signifie que si vous héritez d'une ligne de classe qui rend le constructeur no-arg par défaut privé (ou n'existe pas, par exemple), vos sous-classes doivent déclarer un constructeur en ligne avec l'alternative de son parent. constructeur. 

Par exemple, la déclaration suivante de Bar n'est pas autorisée:

public class Foo {
  private Foo() {  } // or this doesn't even exist
  public Foo(int i) {
  }
}
public class Bar extends Foo {
}
0
kvista

Permettez-moi d’ajouter à tous les cas mentionnés ci-dessus où le constructeur default/no-arg est irréalisable, en ce sens que, sauf déclaration explicite, le compilateur ne peut l’assumer et pourtant cela n’a rien à voir avec le sous-classement. C'est le cas d'avoir une classe avec un champ final qui attend qu'un constructeur l'initialise. Par exemple:

class Foo extends Object {
    private final Object o;

    public Foo(Object o){
       this.o = o;
    }
}

Ici, il est facile de voir qu'une instanciation d'un objet Foo nécessite l'initialisation du champ final o alors toute invocation de Foo() - directement ou non - est vouée à l'échec ... Permettez-moi de souligner que le constructeur no-arg du super La classe (Object) existe et est accessible au public, mais c'est la présence du dernier champ (o) qui le désactive dans Foo.

0
Pantelis Sopasakis