web-dev-qa-db-fra.com

Pourquoi les constructeurs de Java n'ont pas de type de retour?

Duplicata possible:
Pourquoi le constructeur ne retourne pas de valeur

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

43
user845932

Le constructeur est en interne une méthode non statique avec le nom <init> Et void type de retour . Il ne retourne rien. En interne, le premier objet est alloué, puis son constructeur est appelé. L'objet n'est pas alloué avec le constructeur lui-même.
En d'autres termes, la syntaxe new Object() appelle non seulement le constructeur mais crée également un nouvel objet et après l'appel du constructeur le renvoie. Le Suns 'Java tutorial signifie que "Le nouvel opérateur 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 de type de retour manquante est un moyen de distinguer le constructeur d'une méthode. Mais vous pouvez revenir 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 a une méthode void ( ne l'essayez pas à la maison - la méthode majuscule 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 montre que le constructeur est une méthode void non statique:

 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 alors

 /* 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é, puis la méthode <init> non statique est appelée. Pour plus de détails, regardez ici . La documentation de la fonction AllocObject signifie que "Alloue un nouvel objet Java sans invoquer aucun des constructeurs de l'objet. Renvoie une référence à l'objet." Donc, dans l'objet JVM n'est pas alloué par le constructeur, mais seulement initialisé par lui. En regardant dans le bytecode des constructeurs, nous voyons qu'aucun objet n'est retourné (exactement comme dans les méthodes void).

Une autre façon, lorsque vous démontez l'exemple de classe, 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 la méthode <init> Ne fait pas réellement partie du langage Java. Au contraire, c'est quelque chose que la machine virtuelle Java s'attend à voir dans a Java. Cette distinction est importante car le langage Java ne dépend pas du fichier de classe. Java peut être compilé dans d'autres formats binaires, y compris des exécutables natifs. A Java compilateur qui traduit Java source de langage dans un autre format binaire n'a pas besoin de générer une méthode nommée <init>, Tant que les objets sont initialisés de la bonne manière au bon moment. La spécification de langage Java Language (JLS) détaille l'ordre d'initialisation et le moment où il se produit, mais ne fonctionne pas) t dire comment cela est réellement accompli.

Mais je vois que nous parlons ici de JVM.

Pour certains non-croyants, voici un exemple (thx 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);
        }
    }
49
zacheusz

Comment obtiendriez-vous la valeur retournée? Quel type de valeur êtes-vous intéressé à être retourné? Comment déclareriez-vous le type de retour?

 X x = new X ();

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

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

Quelle est la logique de retourner quelque chose du ctor? Un message d'erreur? Quelques informations de connexion? Écrivez-le dans un fichier ou dans un attribut que vous interrogerez plus tard.

Étant donné que le ctor n'est accessible qu'une fois par objet, la seule raison pour 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; }
 }
3
user unknown

Même si l'implémentation VM d'un constructeur ne doit renvoyer aucune valeur, en pratique c'est le cas - la référence du nouvel objet. Il serait alors syntaxiquement étrange et/ou déroutant de pouvoir pour stocker une ou les deux références du nouvel objet et une valeur de retour supplémentaire dans une instruction.

1
Ben