43 votes

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

Dupliquer possible:
Pourquoi le constructeur ne renvoie pas de valeur

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

50voto

zacheusz Points 4661

Le constructeur est à l'intérieur d'une méthode non statique avec le nom <init> et void type de retour. Elle ne retourne rien. D'abord en interne objet est alloué, puis son constructeur est appelé. L'objet n'est pas allouée avec le constructeur lui-même.
En d'autres mots, la syntaxe new Object() non seulement appelle le constructeur, mais aussi crée un nouvel objet et après l'appel au constructeur de la retourne. Les Soleils " Java tutoriel stands ", Le nouvel opérateur est suivi par un appel à un constructeur qui initialise le nouvel objet." Initialiser ne signifie pas créer.

Répondre à la question. Manque de retour de la déclaration de type est une manière dans laquelle vous distinguer le constructeur à partir d'une méthode. Mais vous pouvez retourner dans le constructeur comme de méthode void. Par exemple ce code 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 ça à la maison - majuscules méthode est un mauvais style) et un constructeur. La différence est déclarée de type de retour.

Regardez cette JNI extrait de code qui montre que le constructeur est un non statique méthode void:

 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;
 }

en particulier, ces fragments:

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

et puis

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

premier objet est alloué et puis non statiques <init> méthode est appelée. Pour plus de détails regardez ici. Le AllocObject fonction de la documentation , se dresse la "Alloue un nouvel objet Java sans invoquer l'un des constructeurs de l'objet. Renvoie une référence à l'objet." Ainsi, dans la JVM de l'objet n'est pas affecté par le constructeur, mais seulement initialisé par elle. À la recherche de constructeurs de bytecode nous constatons qu'aucun objet n'est retourné (exactement comme dans les méthodes void).

D'une autre manière, lorsque vous dissasemble échantillon de la classe, vous verrez l'invocation de la mère (Objet) constructeur 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 l' <init> méthode ne fait pas partie du langage Java. C'est plutôt quelque chose de 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 de la classe fichier. Source Java peuvent être compilés dans d'autres formats binaires, y compris des exécutables natifs. Un compilateur Java qui traduit le langage Java source 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 façon au bon moment. Le Langage Java Specification (JLS) détails de l'ordre de l'initialisation et quand il se produit, mais ne dit pas comment il est en fait accompli.

Mais je vois que nous parlons de la JVM ici.

Pour certains des non-croyants c'est l'exemple (thx biziclop) qui montre que l'objet existe et est alloué avant le retour 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 voulez-vous obtenir la valeur renvoyée? Quel type de valeur vous intéresse, étant retourné? Comment voulez-vous déclarer le type de retour?

 X x = new X ();

attribue un X-références à x. Maintenant, si new X serait de retour quelque chose, comment devriez-vous obtenir?

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

Quelle est la logique de revenir à quelque chose de l'ctor? Un message d'erreur? Certains loginfo? Écrire dans un fichier, ou d'un attribut, qui vous sondage plus tard.

Depuis le ctor n'est accessible qu'une fois par objet, la seule raison pour laquelle je peux penser, d'utiliser une autre valeur de retour, serait, pour les 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 de la machine virtuelle d'un constructeur ne doit renvoyer aucune valeur, c'est en quelque sorte le cas - la référence du nouvel objet. Il serait alors étrangement et / ou déroutant sur le plan syntaxique de pouvoir stocker une ou les deux références du nouvel objet et une valeur de retour supplémentaire dans une seule instruction.

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