43 votes

Pourquoi les constructeurs en java n'ont-ils pas de type de retour ?

Duplicata possible :
Pourquoi le constructeur ne renvoie pas de valeur

Pourquoi les constructeurs n'ont-ils pas un type de retour, même pas void ? Quelle est la raison de cela ?

50voto

zacheusz Points 4661

Le constructeur est en interne un méthode non statique avec nom <init> y void type de retour . Il ne renvoie rien. En interne, l'objet est d'abord alloué et ensuite son constructeur est appelé. L'objet n'est pas alloué avec le constructeur lui-même.
En d'autres termes, la syntaxe new Object() n'appelle pas seulement le constructeur mais crée aussi un nouvel objet et après avoir appelé le constructeur, le retourne. Le site Le tutoriel Java de Suns déclare que "L'opérateur new est suivi d'un appel à un constructeur, qui initialise le nouvel objet." Initialiser ne signifie pas créer.

Répondre à la question. La déclaration du type de retour manquant est un moyen de distinguer le constructeur d'une méthode. Mais vous pouvez retourner du constructeur comme de la méthode void. Par exemple, ce code se compile et s'exécute correctement :

public class TheClass {
    public TheClass(){
        return;
    }
    public void TheClass(){ //confusing, but this is void method not constructor
        return;
    }

    public static void main(String[]a){
        TheClass n = new TheClass();
        n.TheClass();//void method invocation
    }
}

Cette classe possède une méthode void ( n'essayez pas à la maison - La méthode en majuscules est un mauvais style) et un constructeur. La différence réside dans le type de retour déclaré.

Regardez cet extrait de code JNI qui démontre que le constructeur est une méthode non statique et vide :

 jstring
 MyNewString(JNIEnv *env, jchar *chars, jint len)
 {
     jclass stringClass;
     jmethodID cid;
     jcharArray elemArr;
     jstring result;

     stringClass = (*env)->FindClass(env, "java/lang/String");
     if (stringClass == NULL) {
         return NULL; /* exception thrown */
     }
 /* Get the method ID for the String(char[]) constructor */
     cid = (*env)->GetMethodID(env, stringClass,
                               "<init>", "([C)V");
     if (cid == NULL) {
         return NULL; /* exception thrown */
     }

     /* Create a char[] that holds the string characters */
     elemArr = (*env)->NewCharArray(env, len);
     if (elemArr == NULL) {
         return NULL; /* exception thrown */
     }
     (*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);

     result = (*env)->AllocObject(env, stringClass);
     if (result) {
         (*env)->CallNonvirtualVoidMethod(env, result, stringClass,
                                          cid, elemArr);
         /* we need to check for possible exceptions */
         if ((*env)->ExceptionCheck(env)) {
             (*env)->DeleteLocalRef(env, result);
             result = NULL;
         }
     }
     /* Free local references */
     (*env)->DeleteLocalRef(env, elemArr);
     (*env)->DeleteLocalRef(env, stringClass);
     return result;
 }

surtout ces fragments :

 /* Get the method ID for the String(char[]) constructor */
 cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");

et ensuite

 /* Allocate new object. */
 result = (*env)->AllocObject(env, stringClass);
 if (result) {
      /* Call uninitialized objects' constuctor. */
      (*env)->CallNonvirtualVoidMethod(env, result, stringClass, cid, elemArr);

le premier objet est alloué et ensuite non statique <init> est appelée. Pour plus de détails, voir aquí . Le site Documentation sur la fonction AllocObject déclare que "Alloue un nouvel objet Java sans invoquer aucun des constructeurs de l'objet. Retourne une référence à l'objet." Ainsi, dans la JVM, l'objet n'est pas alloué par le constructeur, mais seulement initialisé par lui. En regardant le bytecode des constructeurs, nous voyons qu'aucun objet n'est retourné (exactement comme dans les méthodes void).

D'une autre manière, lorsque vous démontez la classe d'exemple, vous verrez l'invocation du constructeur parent (Object) à partir de son constructeur :

#javap -c NewClass
Compiled from "NewClass.java"
public class NewClass extends java.lang.Object{
public NewClass();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

}

Notez que le <init> ne fait pas partie du langage Java. Il s'agit plutôt d'un élément que la machine virtuelle Java s'attend à voir dans un fichier de classe Java. Cette distinction est importante car le langage Java ne dépend pas du fichier de classe. Le code source Java peut être compilé dans d'autres formats binaires, notamment des exécutables natifs. Un compilateur Java qui traduit le source du langage Java en un autre format binaire n'a pas besoin de générer une méthode appelée <init> pour autant que les objets soient initialisés de la bonne manière et au bon moment. La spécification du langage Java (JLS) détaille l'ordre d'initialisation et le moment où elle se produit, mais ne dit pas comment elle est réellement accomplie.

Mais je vois que nous parlons de JVM ici.

Pour les non croyants, voici un exemple (merci à biziclop) qui montre que l'objet existe et est alloué avant de revenir du constructeur :

   class AnotherClass {

        private String field;
        public static AnotherClass ref;

        public AnotherClass() {
            this.field = "value";
            AnotherClass.ref = this;
            throw new RuntimeException();
        }

        @Override
        public String toString() {
            return field;
        }
    }

    public class MainClass {
        public static void main(String[] a) {
            try {
                new AnotherClass();
                return;
            } catch (RuntimeException ex) {
                System.out.println("exception");
            }
            System.out.println("instance: " + AnotherClass.ref);
        }
    }

3voto

user unknown Points 15555

Comment obtenir la valeur retournée ? Quel type de valeur vous intéresse, qui est retourné ? Comment déclareriez-vous le type de retour ?

 X x = new X ();

attribue une référence X à x. Maintenant, si new X rendrait quelque chose, comment l'obtenir ?

 class X { 
     public int X () { 
          return 42;
     }
 }

Quelle est la logique pour retourner quelque chose du ctor ? Un message d'erreur ? Un loginfo ? Ecrivez-le dans un fichier, ou dans un attribut, que vous interrogez plus tard.

Puisque le ctor n'est accédé qu'une seule fois par objet, la seule raison à laquelle je peux penser, pour utiliser une autre valeur de retour, serait d'informer sur le processus de création lui-même.

 class X { 
     private Y y;
     public int X () { 
          y = new Y ();
     }
     public Y getY () { return y; }
 }

1voto

Ben Points 367

Même si l'implémentation VM d'un constructeur ne doit pas retourner de valeur, dans la pratique, c'est ce qu'il fait - la référence du nouvel objet. Il serait alors syntaxiquement bizarre et/ou confus de pouvoir stocker une ou les deux références du nouvel objet et une valeur de retour supplémentaire dans une déclaration.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X