tener - tipos de constructores en java
¿Por qué los constructores en java no tienen un tipo de retorno? (3)
¿Cómo obtendrías el valor devuelto? ¿Qué tipo de valor te interesa, ser devuelto? ¿Cómo declararías el tipo de devolución?
X x = new X ();
asigna una X-referencia a x. Ahora, si la new X
devolvería algo, ¿cómo debería obtenerlo?
class X {
public int X () {
return 42;
}
}
¿Cuál es la lógica de devolver algo del ctor? Un mensaje de error? Algunos loginfo? Escríbalo en un archivo, o en un atributo, que sondea más tarde.
Dado que solo se puede acceder al ctor una vez por objeto, la única razón que se me ocurre es usar otro valor de retorno para informar sobre el proceso de creación en sí.
class X {
private Y y;
public int X () {
y = new Y ();
}
public Y getY () { return y; }
}
Posible duplicado:
Por qué el constructor no devuelve valor
¿Por qué los constructores no tienen un tipo de retorno, ni siquiera nulo? ¿Cuál es la razón de eso?
A pesar de que la implementación de VM de un constructor no devuelve ningún valor, en la práctica sí lo hace, la referencia del nuevo objeto. Entonces sería sintácticamente extraño y / o confuso poder almacenar una o las dos referencias del nuevo objeto y un valor de retorno adicional en una declaración.
Constructor es internamente un método no estático con nombre <init>
y tipo de retorno void
. No devuelve nada. Internamente se asigna el primer objeto y luego se llama a su constructor. El objeto no se asigna con el propio constructor.
En otras palabras, la sintaxis new Object()
no solo llama al constructor sino que también crea un nuevo objeto y después de llamar al constructor, lo devuelve. El tutorial de Java de los Suns destaca que "al nuevo operador le sigue una llamada a un constructor, que inicializa el nuevo objeto". Inicializar no significa crear.
Respondiendo a la pregunta. La declaración de tipo de retorno faltante es una forma en la que se distingue el constructor de un método. Pero puedes regresar del constructor como del método void. Por ejemplo, este código compila y ejecuta correctamente:
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
}
}
Esta clase tiene un método vacío ( no lo intentes en casa ; el método en mayúsculas es un estilo malo) y un constructor. La diferencia está en el tipo de retorno declarado.
Mire este fragmento de código JNI que demuestra que el constructor es un método vacío no estático:
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;
}
especialmente estos fragmentos:
/* Get the method ID for the String(char[]) constructor */
cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");
y entonces
/* Allocate new object. */
result = (*env)->AllocObject(env, stringClass);
if (result) {
/* Call uninitialized objects'' constuctor. */
(*env)->CallNonvirtualVoidMethod(env, result, stringClass, cid, elemArr);
El primer objeto se asigna y luego se llama al método <init>
no estático. Para más detalles mira here . La documentación de la función AllocObject sostiene que "Asigna un nuevo objeto Java sin invocar a ninguno de los constructores del objeto. Devuelve una referencia al objeto". Por lo tanto, en el objeto JVM no está asignado por el constructor, sino que solo lo inicializa. Al buscar en el código de bytes de los constructores, estamos viendo que no se devuelve ningún objeto (exactamente como en los métodos de vacío).
Otra forma, cuando desmonte la clase de muestra, verá la invocación del constructor padre (Objeto) de su constructor:
#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
}
Tenga en cuenta que el método <init>
no es realmente parte del lenguaje Java. Más bien, es algo que la máquina virtual de Java espera ver en un archivo de clase de Java. Esta distinción es significativa porque el lenguaje Java no depende del archivo de clase. La fuente Java se puede compilar en otros formatos binarios, incluidos los ejecutables nativos. Un compilador de Java que traduce la fuente del lenguaje Java a algún otro formato binario no necesita generar un método llamado <init>
, siempre que los objetos se inicialicen correctamente en el momento adecuado. La especificación del lenguaje Java (JLS) detalla el orden de inicialización y cuándo ocurre, pero no indica cómo se realiza realmente.
Pero veo que estamos hablando de JVM aquí.
Para algunos de los no creyentes, este es un ejemplo (thx biziclop) que muestra que el objeto existe y se asigna antes de regresar del constructor:
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);
}
}