uso tutorial seleccionar ruta obtener chooser carpeta cambiar archivos apariencia java c++ constructor initialization initialization-list

tutorial - selector de archivos java



¿Por qué Java no tiene listas de inicializadores como en C++? (3)

En C ++, puede usar una lista de inicializadores para inicializar los campos de la clase antes de que el constructor comience a ejecutarse. Por ejemplo:

Foo::Foo(string s, double d, int n) : name(s), weight(d), age(n) { // Empty; already handled! }

Tengo curiosidad por saber por qué Java no tiene una función similar. Según Core Java: Volumen 1 :

C ++ usa esta sintaxis especial para llamar a los constructores de campo. En Java, no es necesario porque los objetos no tienen subobjetos, solo punteros a otros objetos.

Aquí están mis preguntas:

  1. ¿Qué quieren decir con "porque los objetos no tienen subobjetos"? No entiendo qué es un subobjeto (intenté buscarlo); ¿quieren decir una instancia de una subclase que extiende una superclase?

  2. En cuanto a por qué Java no tiene listas de inicializadores como C ++, supongo que la razón es porque todos los campos ya están inicializados por defecto en Java y también porque Java usa la palabra clave super para llamar a la super (o base en la jerga de C ++) constructor. ¿Es esto correcto?


En C ++, las listas de inicializadores son necesarias debido a algunas características del lenguaje que no están presentes en Java o funcionan de manera diferente en Java:

  1. const : en C ++, puede definir un campo marcado const que no se puede asignar y debe inicializarse en la lista de inicializadores. Java tiene campos final , pero puede asignarlos a campos final en el cuerpo de un constructor. En C ++, la asignación a un campo const en el constructor es ilegal.

  2. Referencias : en C ++, las referencias (a diferencia de los punteros) se deben inicializar para enlazar a algún objeto. Es ilegal crear una referencia sin un inicializador. En C ++, la forma en que especifica esto es con la lista de inicializadores, ya que si tuviera que hacer referencia a la referencia en el cuerpo del constructor sin inicializarla primero, estaría utilizando una referencia no inicializada. En Java, las referencias a objetos se comportan como punteros C ++ y se pueden asignar a después de creado. Simplemente de manera predeterminada null .

  3. Subobjetos directos . En C ++, un objeto puede contener objetos directamente como campos, mientras que en Java los objetos solo pueden contener referencias a esos objetos. Es decir, en C ++, si declara un objeto que tiene una string como miembro, el espacio de almacenamiento para esa cadena se construye directamente en el espacio para el objeto en sí, mientras que en Java solo tiene espacio para una referencia a otra String objeto almacenado en otro lugar. En consecuencia, C ++ necesita proporcionar una forma de dar esos valores iniciales a los subobjetos, ya que de lo contrario simplemente no se inicializarían. De forma predeterminada, utiliza el constructor predeterminado para esos tipos, pero si desea usar un constructor diferente o no hay un constructor predeterminado disponible, la lista de inicializadores le brinda una forma de eludir esto. En Java, no necesita preocuparse por esto porque las referencias tendrán valor null por defecto, y luego puede asignarlas para referirse a los objetos a los que realmente quiere hacer referencia. Si desea utilizar un constructor no predeterminado, entonces no necesita ninguna sintaxis especial para él; simplemente establece la referencia a un nuevo objeto inicializado a través del constructor apropiado.

En los pocos casos en que Java podría querer listas de inicializadores (por ejemplo, para llamar constructores de superclase o dar valores predeterminados a sus campos), esto se maneja a través de otras dos características de lenguaje: la palabra clave super para invocar constructores de superclase y el hecho de que los objetos Java puede dar a sus campos los valores predeterminados en el punto en el que se declaran. Dado que C ++ tiene herencia múltiple, el solo hecho de tener una sola palabra clave super no se referiría inequívocamente a una sola clase base, y antes de C ++ 11 C ++ no era compatible con los inicializadores predeterminados en una clase y tenía que depender de las listas de inicializadores.

¡Espero que esto ayude!


Porque Java no los necesita para permitir la inicialización de campos cuyo tipo no tiene valor cero.

En C ++

class C { D d; }

sin un inicializador miembro para d , se llamará D::D() lo que hace que sea imposible inicializar el campo si no hay cero para D Esto puede suceder cuando D::D() se declara explícitamente private .

En Java, hay un zero-value conocido para todos los tipos de referencia, null , por lo que siempre se puede inicializar un campo.

Java también hace un montón de trabajo para asegurarse * de que todos los campos final se inicialicen antes del primer uso y antes de que termine el constructor, así que mientras que Java tiene un requisito como el requisito de inicialización del campo const C ++, simplemente sobrecarga this.fieldName = <expression> en el cuerpo constructor quiere decir inicialización de campo.

  • : excepciones de módulo arrojadas en el ctor, llamadas de método anuladas de la clase base, etc.

C ++

Hay una diferencia entre

ClassType t(initialization arguments);

y

ClassType * pt;

Este último no necesita ser inicializado (establecido en NULL). El primero sí. Piense en ello como un número entero. No puede tener un int sin un valor, PERO puede tener un puntero int sin un valor.

Entonces cuando tienes:

class ClassType { OtherClass value; OtherClass * reference; };

Entonces la declaración:

ClassType object;

crea automáticamente una instancia de OtherClass en value . Por lo tanto, si OtherClass tiene inicialización, debe hacerse en el constructor ClassType . Sin embargo, la reference es solo un puntero (dirección en la memoria) y puede permanecer sin inicializar. Si quieres una instancia de OtherClass , debes usar

object.reference = new OtherClass(initialization arguments);

Java

Solo hay

class ClassType { OtherClass reference; }

Esto es equivalente a un puntero en C ++. En este caso cuando lo haces:

ClassType object = new ClassType();

No creas automáticamente una instancia de OtherClass . Por lo tanto, no tiene que inicializar nada en el constructor a menos que lo desee. Cuando desee un objeto de OtherClass , puede usar

object.reference = new OtherClass();