为什么java中的构造函数没有返回类型? [重复]

时间:2022-09-25 12:23:55

Possible Duplicate:
Why constructor not returns value

可能重复:为什么构造函数不返回值

Why don't constructors have a return type, not even void? What's the reason for that?

为什么构造函数不具有返回类型,甚至无效?这是什么原因?

3 个解决方案

#1


48  

Constructor is internally a nonstatic method with name <init> and void return type. It does not return anything. Internally first object is allocated and then its constructor is called. Object is not allocated with constructor itself.
In other words the syntax new Object() not only calls the constructor but also creates new object and after calling the constructor returns it. The Suns' Java tutorial stands that "The new operator is followed by a call to a constructor, which initializes the new object." Initialize does not mean create.

构造函数在内部是一个非静态方法,名称为 ,返回类型为void。它没有返回任何东西。分配内部第一个对象,然后调用其构造函数。对象未使用构造函数本身分配。换句话说,语法new Object()不仅调用构造函数,还创建新对象,并在调用构造函数后返回它。太阳队的Java教程认为“新操作符之后是对构造函数的调用,该构造函数初始化新对象。”初始化并不意味着创建。

Answering the question. Missing return type declaration is a way in which you distinguish the constructor from a method. But you can return from constructor as from void method. For example this code compiles and runs correctly:

回答这个问题。缺少返回类型声明是一种将构造函数与方法区分开的方法。但是你可以从构造函数返回,从void方法返回。例如,此代码编译并正确运行:

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

This class has one void method (don't try it at home - uppercase method is a bad style) and one constructor. The difference is in declared return type.

这个类有一个void方法(不要在家里尝试 - 大写方法是一个糟糕的样式)和一个构造函数。区别在于声明的返回类型。

Look at this JNI code snippet which demonstrates that constructor is a nonstatic void method:

看看这个JNI代码片段,它演示了构造函数是一个非静态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;
 }

especially these fragments:

特别是这些片段:

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

and then

接着

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

first object is allocated and then nonstatic <init> method is called. For details look here. The AllocObject function documentation stands that "Allocates a new Java object without invoking any of the constructors for the object. Returns a reference to the object." So in JVM object is not allocated by constructor, but only initialized by it. Looking in constructors' bytecode we are seeing that no object is returned (exactly like in void methods).

分配第一个对象,然后调用非静态 方法。详情请看这里。 AllocObject函数文档表示“在不调用对象的任何构造函数的情况下分配新的Java对象。返回对象的引用。”所以在JVM对象中没有由构造函数分配,而只是由它初始化。查看构造函数的字节码,我们发现没有返回任何对象(与void方法完全相同)。

Another way, when you dissasemble sample class, you will see invocation of parent (Object) constructor from its constructor:

另一种方法是,当您对样本类进行分解时,您将看到从其构造函数调用parent(Object)构造函数:

#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

}

Note that the <init> method is not actually part of the Java language. Rather, it is something the Java virtual machine expects to see in a Java class file. This distinction is significant because the Java language does not depend on the class file. Java source can be compiled into other binary formats, including native executables. A Java compiler that translates Java language source into some other binary format need not generate a method named <init>, so long as objects are initialized in the proper way at the proper time. The Java Language Specification (JLS) details the order of initialization and when it occurs, but doesn't say how it is actually accomplished.

请注意, 方法实际上不是Java语言的一部分。相反,它是Java虚拟机期望在Java类文件中看到的东西。这种区别很重要,因为Java语言不依赖于类文件。 Java源代码可以编译成其他二进制格式,包括本机可执行文件。将Java语言源转换为其他二进制格式的Java编译器无需生成名为 的方法,只要在适当的时间以适当的方式初始化对象即可。 Java语言规范(JLS)详细说明了初始化的顺序及其发生的时间,但没有说明它是如何实现的。

But I see that we're talking about JVM here.

但是我看到我们在这里谈论JVM。

For some of nonbelievers this is example (thx biziclop) which shows that object exists and is allocated before returning from constructor:

对于一些非信徒来说,这是示例(thx biziclop),它显示对象存在并在从构造函数返回之前分配:

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

#2


3  

How would you get the returned value? What kind of value are you interested in, being returned? How would you declare the return type?

你怎么得到返回值?您对什么样的价值感兴趣,被退回?你会如何申报退货类型?

 X x = new X ();

assigns an X-reference to x. Now, if new X would return something, how should you get it?

为x指定X引用。现在,如果新的X会返回一些东西,你应该怎么做呢?

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

What's the logic of returning something from the ctor? An error message? Some loginfo? Write it to a file, or to an attribute, which you poll later.

从ctor返回一些东西的逻辑是什么?错误消息?有些loginfo?将其写入文件或稍后轮询的属性。

Since the ctor is only accessed once per object, the only reason I can think of, to use another return value, would be, to inform about the process of creation itself.

由于每个对象只访问一次ctor,因此我可以想到使用另一个返回值的唯一原因是,通知创建过程本身。

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

#3


1  

Even though the VM implementation of a constructor isn't to return any value, in practice it kind of does - the new object's reference. It would then be syntactically weird and / or confusing to be able to store one or both of the new object's reference and an additional return value in one statement.

即使构造函数的VM实现不返回任何值,实际上它也有用 - 新对象的引用。然后,在一个语句中能够存储新对象的引用和附加返回值中的一个或两个,这在语法上会很奇怪和/或令人困惑。

#1


48  

Constructor is internally a nonstatic method with name <init> and void return type. It does not return anything. Internally first object is allocated and then its constructor is called. Object is not allocated with constructor itself.
In other words the syntax new Object() not only calls the constructor but also creates new object and after calling the constructor returns it. The Suns' Java tutorial stands that "The new operator is followed by a call to a constructor, which initializes the new object." Initialize does not mean create.

构造函数在内部是一个非静态方法,名称为 ,返回类型为void。它没有返回任何东西。分配内部第一个对象,然后调用其构造函数。对象未使用构造函数本身分配。换句话说,语法new Object()不仅调用构造函数,还创建新对象,并在调用构造函数后返回它。太阳队的Java教程认为“新操作符之后是对构造函数的调用,该构造函数初始化新对象。”初始化并不意味着创建。

Answering the question. Missing return type declaration is a way in which you distinguish the constructor from a method. But you can return from constructor as from void method. For example this code compiles and runs correctly:

回答这个问题。缺少返回类型声明是一种将构造函数与方法区分开的方法。但是你可以从构造函数返回,从void方法返回。例如,此代码编译并正确运行:

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

This class has one void method (don't try it at home - uppercase method is a bad style) and one constructor. The difference is in declared return type.

这个类有一个void方法(不要在家里尝试 - 大写方法是一个糟糕的样式)和一个构造函数。区别在于声明的返回类型。

Look at this JNI code snippet which demonstrates that constructor is a nonstatic void method:

看看这个JNI代码片段,它演示了构造函数是一个非静态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;
 }

especially these fragments:

特别是这些片段:

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

and then

接着

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

first object is allocated and then nonstatic <init> method is called. For details look here. The AllocObject function documentation stands that "Allocates a new Java object without invoking any of the constructors for the object. Returns a reference to the object." So in JVM object is not allocated by constructor, but only initialized by it. Looking in constructors' bytecode we are seeing that no object is returned (exactly like in void methods).

分配第一个对象,然后调用非静态 方法。详情请看这里。 AllocObject函数文档表示“在不调用对象的任何构造函数的情况下分配新的Java对象。返回对象的引用。”所以在JVM对象中没有由构造函数分配,而只是由它初始化。查看构造函数的字节码,我们发现没有返回任何对象(与void方法完全相同)。

Another way, when you dissasemble sample class, you will see invocation of parent (Object) constructor from its constructor:

另一种方法是,当您对样本类进行分解时,您将看到从其构造函数调用parent(Object)构造函数:

#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

}

Note that the <init> method is not actually part of the Java language. Rather, it is something the Java virtual machine expects to see in a Java class file. This distinction is significant because the Java language does not depend on the class file. Java source can be compiled into other binary formats, including native executables. A Java compiler that translates Java language source into some other binary format need not generate a method named <init>, so long as objects are initialized in the proper way at the proper time. The Java Language Specification (JLS) details the order of initialization and when it occurs, but doesn't say how it is actually accomplished.

请注意, 方法实际上不是Java语言的一部分。相反,它是Java虚拟机期望在Java类文件中看到的东西。这种区别很重要,因为Java语言不依赖于类文件。 Java源代码可以编译成其他二进制格式,包括本机可执行文件。将Java语言源转换为其他二进制格式的Java编译器无需生成名为 的方法,只要在适当的时间以适当的方式初始化对象即可。 Java语言规范(JLS)详细说明了初始化的顺序及其发生的时间,但没有说明它是如何实现的。

But I see that we're talking about JVM here.

但是我看到我们在这里谈论JVM。

For some of nonbelievers this is example (thx biziclop) which shows that object exists and is allocated before returning from constructor:

对于一些非信徒来说,这是示例(thx biziclop),它显示对象存在并在从构造函数返回之前分配:

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

#2


3  

How would you get the returned value? What kind of value are you interested in, being returned? How would you declare the return type?

你怎么得到返回值?您对什么样的价值感兴趣,被退回?你会如何申报退货类型?

 X x = new X ();

assigns an X-reference to x. Now, if new X would return something, how should you get it?

为x指定X引用。现在,如果新的X会返回一些东西,你应该怎么做呢?

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

What's the logic of returning something from the ctor? An error message? Some loginfo? Write it to a file, or to an attribute, which you poll later.

从ctor返回一些东西的逻辑是什么?错误消息?有些loginfo?将其写入文件或稍后轮询的属性。

Since the ctor is only accessed once per object, the only reason I can think of, to use another return value, would be, to inform about the process of creation itself.

由于每个对象只访问一次ctor,因此我可以想到使用另一个返回值的唯一原因是,通知创建过程本身。

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

#3


1  

Even though the VM implementation of a constructor isn't to return any value, in practice it kind of does - the new object's reference. It would then be syntactically weird and / or confusing to be able to store one or both of the new object's reference and an additional return value in one statement.

即使构造函数的VM实现不返回任何值,实际上它也有用 - 新对象的引用。然后,在一个语句中能够存储新对象的引用和附加返回值中的一个或两个,这在语法上会很奇怪和/或令人困惑。