Contactos

Constructores Java. ¿Por qué se necesitan constructores? El concepto de un constructor por defecto

1. El concepto de un constructor por defecto

Un constructor predeterminado es un constructor que no toma parámetros. Un constructor predeterminado puede declararse explícitamente en una clase o generarse automáticamente.

En el caso más general, para la clase ClassName, el constructor predeterminado se ve así:

clase Nombre de la clase(... // declaración del constructor Nombre de la clase() ( // cuerpo del constructor // ... } ... }
2. ¿En qué casos se genera automáticamente el constructor por defecto en la clase y en cuáles no? Ejemplo

Si no se declara ningún constructor en la clase, se generará un constructor predeterminado. Es decir, un constructor predeterminado se genera automáticamente en una clase solo si la clase no contiene implementaciones de otros constructores. Si una clase contiene una implementación de al menos un constructor con parámetros, para declarar un constructor predeterminado, debe declararse explícitamente en la clase.

Por ejemplo. En la siguiente declaración de clase, se genera automáticamente un constructor predeterminado

clase CMiClase( En t d; En t Obtener d() ( devolver d; ) vacío EstablecerD( En t sf) ( d = sf; ) )

El código anterior significa que puede declarar un objeto de clase utilizando el constructor predeterminado:

// funciona porque la clase ya no implementa ningún constructor CMiClase mc = nuevo CMiClase();

Si se agrega al menos otro constructor al cuerpo de la clase CMyClass (por ejemplo, un constructor con un parámetro), el constructor predeterminado no se generará automáticamente.

clase CMiClase( En t d; // el constructor predeterminado ya no se genera automáticamente CMiClase( En t sf) ( d = sf; ) En t Obtener d() ( devolver d; ) vacío Establecer( En t sf) ( d = sf; ) )

Después de la implementación anterior, la declaración de un objeto mediante un constructor predeterminado fallará. Sin embargo, es posible declarar un objeto usando un constructor con un parámetro

// error de compilación porque ya se declaró otro constructor en la clase // CMyClass mc = new CMyClass(); CMiClase mc2= nuevo CMiClase(7); // y este código funciona

La línea anterior dará como resultado un error de compilación:

El constructor CMyClass() no está definido

Para tener una implementación de constructor predeterminada y declarar un objeto de clase usando un constructor predeterminado, debe establecerse explícitamente. Podría ser, por ejemplo, de la siguiente manera

clase CMiClase( En t d; // declaración explícita del constructor por defecto CMyClass() ( d = 0; ) // declaración del constructor con 1 parámetro, CMiClase( En t sf) ( d = sf; ) En t Obtener d() ( devolver d; ) vacío Establecer( En t sf) ( d = sf; ) )

Después de tal implementación, puede crear una instancia de la clase usando dos constructores, por ejemplo

CMiClase mc = nuevo CMiClase(); // se llama al constructor por defecto mc.d = 25; CMiClase mc2= nuevo CMiClase(5); // se llama al constructor con 1 parámetro

3. Llamar a constructores de otros constructores. Ejemplo

El lenguaje de programación Java le permite llamar a constructores de clases desde otro constructor de la misma clase. Para ello se utiliza la palabra clave this, que es una referencia a la clase actual.

Ejemplo. El ejemplo demuestra el uso de la clase CPixel, que implementa un píxel en la pantalla de un monitor.

// Clase que implementa un píxel en la pantalla del monitor público clase CPixel( // variables de clase internas privado En t x, y; // coordenadas de píxeles privado En t color; // color de píxel // constructor sin parámetros (constructor por defecto) CPixel() ( x = y = color = 0; ) // constructor con 2 parámetros que solo inicializan coordenadas CPixel( En t _X, En t _y) ( x = _x; y = _y; color = 0; ) // constructor con 1 parámetro que solo inicializa el color CPixel( En t _color) ( color = _color; x = y = 0; ) // constructor de 3 parámetros que llama al constructor de 2 parámetros CPixel( En t _X, En t _y, En t _color) ( // llamar al constructor con 2 parámetros: primera operación obligatoria y solo una vez este(_x, _y); //este color); // está prohibida la llamada repetida del constructor este.color = _color; // por lo que es posible) // métodos de acceso En t ObtenerX() ( devolver X; ) En t ObtenerY() ( devolver y; ) En t ObtenerColor() ( devolver color; ) )

Usando la clase CPixel en otro código de programa (método)

CPixel cp1= nuevo CPixel(2,8); // llama al constructor con 2 parámetros CPixel cp2= nuevo CPixel(3,5,8); // llamar a un constructor que llamará a otro constructor En t d; d = cp1.GetX(); // d = 2 d = cp2.GetColor(); // d = 8 d = cp2.GetY(); // re = 5...

4. ¿Qué restricciones (requisitos) se imponen al llamar a otros constructores desde un constructor de clase?

Para llamar correctamente a otros constructores desde un constructor de clase, se deben cumplir los siguientes requisitos (restricciones):

  • solo se puede llamar a otro constructor de clase. Está prohibido llamar a dos o más constructores de esta clase. Esto se deriva de la lógica de que un constructor de clase está diseñado para crear un objeto de clase solo una vez (y no dos o más);
  • llamar a otro constructor debe ser la primera operación en el constructor que llama. Si en el constructor que llama se implementa la llamada de otro constructor mediante la segunda (tercera, etc.) operación, el compilador generará un error.

Método en Java es un conjunto de expresiones, cuya totalidad le permite realizar una determinada operación. Entonces, por ejemplo, cuando se llama al método System.out.println(), el sistema ejecuta una serie de comandos para imprimir un mensaje en la consola.

En este paso, aprenderá a crear sus propios métodos con o sin valores de retorno, llamar a métodos con o sin parámetros y aislar métodos al desarrollar un programa.

Crear un método

A continuación se muestra un ejemplo que ilustra la sintaxis de un método, cómo crear un método en Java.

Sintaxis

public static int methodName(int a, int b) ( // cuerpo )
  • public static - modificador;
  • int - tipo de devolución;
  • methodName - nombre del método;
  • a, b - parámetros formales;
  • int a, int b - lista de parámetros.

La definición de un método está representada por el encabezado y el cuerpo del método. Podemos observar lo mismo en la siguiente sintaxis de creación de métodos.

Sintaxis

modificador returnType nameOfMethod (Lista de parámetros) ( // cuerpo del método )

La sintaxis anterior incluye:

  • modificador: determina el tipo de acceso para el método y la posibilidad de su uso.
  • returnType: el método puede devolver un valor.
  • nameOfMethod: especifica el nombre del método. La firma de un método incluye el nombre del método y una lista de parámetros.
  • Lista de parámetros: la lista de parámetros está representada por el tipo, orden y número de parámetros del método. Esta opción se establece arbitrariamente; un parámetro nulo puede estar presente en el método.
  • cuerpo del método: el cuerpo del método define el método de trabajo con los comandos.

Ejemplo

/* fragmento de código devuelve el mínimo entre dos números */ public static int minFunction(int n1, int n2) ( int min; if (n1 > n2) min = n2; else min = n1; return min; )

llamada de método

Antes de usar un método, debe ser llamado. Hay dos formas de llamar a un método en Java, es decir, el método produce un valor de retorno o no produce (no hay valor de retorno).

El algoritmo de llamada al método es bastante simple. Cuando un programa llama a un método en Java, el control programático se transfiere al método llamado. Este método llamado luego devuelve el control al cliente que llama en dos casos, si:

  • se ejecuta una declaración de retorno;
  • se ha alcanzado la llave de cierre del final del método.

El método de devolución void invoca el comando. Considere un ejemplo:

¡Sistema.fuera.!");

El método de devolución de valor se puede ilustrar con el siguiente ejemplo:

resultado int = suma (6, 9);

El siguiente ejemplo muestra cómo definir y llamar a un método en Java.

Ejemplo

public class EjemploMinNumber ( public static void main(String args) ( int a = 11; int b = 6; int c = minFunction(a, b); System.out.println("Valor mínimo = " + c); ) / * Devuelve el mínimo de dos números */ public static int minFunction(int n1, int n2) ( int min; if (n1 >

Valor mínimo = 6

La palabra clave vacía

La palabra clave vacía en Java nos permite crear métodos que no devuelven un valor. En el siguiente ejemplo, hemos considerado un método del tipo void - methodRankPoints. Los métodos vacíos de Java no devuelven ningún valor. La llamada a un método de tipo vacío se realiza mediante un comando, es decir, métodoRankPoints(255.7);. Esta es una expresión java que termina con un punto y coma, como se muestra en el siguiente ejemplo:

Ejemplo

public class ExampleVoid ( public static void main(String args) ( methodRankPoints(255.7); ) public static void methodRankPoints(puntos dobles) ( if (points >= 202.5) ( System.out.println("Rank A1"); )else if (puntos >= 122.4) ( System.out.println("Rango A2"); )else ( System.out.println("Rango A3"); ) ) )

Como resultado, se obtendrá el siguiente resultado:

Rango A1

Pasar parámetros por valor en Java

Cuando se ejecuta el proceso de llamada, Java pasa argumentos. El procedimiento debe llevarse a cabo en el orden especificado por los parámetros correspondientes en la especificación del método. Los parámetros se pueden pasar por valor o por referencia.

En Java, pasar parámetros por valor significa llamar a un método con un parámetro. Debido a esto, el valor del argumento se pasa al parámetro.

Ejemplo

El siguiente programa muestra un ejemplo de pasar un parámetro por valor. Los valores de los argumentos permanecen sin cambios incluso después de llamar al método.

Ejemplo de intercambio de clase pública ( public static void main(String args) ( int a = 30; int b = 45; System.out.println("Antes de pasar, los valores de los argumentos a = " + a + " y b = " + b ); // Llamar al método de transferencia swapFunction(a, b); System.out.println("\nAhora, antes y después de pasar el valor de los argumentos "); System.out.println("permaneció sin cambios, a = " + a + " and b = " + b); ) public static void swapFunction(int a, int b) ( System. out. println("Antes de intercambiar: a = " + a + " b = " + b ); // Pasar parámetros int c = a; a = b; b = c; System.out.println("Después del reemplazo: a = " + a + " b = " + b); ) )

Obtenemos el siguiente resultado:

Antes de pasar, los valores de los argumentos a = 30 y b = 45 Antes de reemplazar: a = 30 b = 45 Después de reemplazar: a = 45 b = 30 Ahora, antes y después de pasar, quedaron los valores de los argumentos sin cambios, a = 30 y b = 45

Sobrecarga de métodos

Sobrecarga de métodos en Java- el caso cuando hay dos o más métodos en la clase con el mismo nombre, pero diferentes parámetros. Este proceso es diferente de los métodos de anulación. Cuando se anulan los métodos, el método se caracteriza por el mismo nombre, tipo, número de parámetros, etc.

Considere el ejemplo que se presentó anteriormente al definir los números mínimos de un tipo entero. Así que digamos que queremos definir el número mínimo de un tipo doble. En este caso, se introducirá el concepto de sobrecarga para crear dos o más métodos con el mismo nombre pero diferentes parámetros.

El ejemplo anterior ilustra lo anterior.

Ejemplo

public class ExampleOverloading ( public static void main(String args) ( int a = 7; int b = 3; double c = 5.1; double d = 7.2; int result1 = minFunction(a, b); // misma función con otros parámetros double result2 = minFunction(c, d); System.out.println("Valor mínimo = " + resultado1); System.out.println("Valor mínimo = " + resultado2); ) // para entero public static int minFunction ( int n1, int n2) ( int min; if (n1 > n2) min = n2; else min = n1; return min; ) // for double public static double minFunction(double n1, double n2) ( double min; if ( n1 > n2) min = n2; si no min = n1; volver min; ) )

Como resultado, se obtendrá el siguiente resultado:

Valor mínimo = 3 Valor mínimo = 5,1

Los métodos de sobrecarga hacen que un programa sea legible. Así que hay dos métodos con el mismo nombre pero diferentes parámetros. Como resultado, obtuvimos el número int mínimo y el número de tipo doble.

Uso de argumentos de línea de comandos

Durante el programa, es posible que deba transferir cierta información. Esto se puede hacer en Java pasando los argumentos de la línea de comandos a main().

En Java, un argumento de línea de comandos representa la información que sigue inmediatamente al nombre de un programa en la línea de comandos cuando se ejecuta. Obtener acceso a los argumentos de la línea de comandos en un programa java no es difícil. Se almacenan como una cadena en la matriz de cadenas que se pasa a main().

Ejemplo

El siguiente programa muestra todos los argumentos de la línea de comandos invocados.

Clase pública CommandLine ( public static void main(String args) ( for(int i = 0; i

Intente ejecutar este programa como se muestra a continuación:

$java CommandLine es la línea de comando 300 -200

Como resultado, se obtendrá el siguiente resultado:

args: esto es args: línea de comando args: cadena args: 300 args: -200

Constructor en Java

en Java constructor inicializa un objeto cuando se crea. Su nombre es similar al nombre de la clase y su sintaxis es similar a la de un método. Sin embargo, a diferencia de este último, el constructor no tiene un valor de retorno.

Por lo general, un constructor en Java se puede usar para establecer un valor inicial para las variables de instancia definidas por una clase, o para realizar cualquier otro procedimiento de inicio necesario para crear un objeto completamente formado.

Los constructores están presentes en todas las clases, independientemente de cómo se especifiquen, porque Java proporciona automáticamente un constructor predeterminado que inicializa todas las variables de los miembros de la clase a cero. Sin embargo, una vez que defina su propio constructor, ya no se utilizará el constructor predeterminado.

Ejemplo

El siguiente ejemplo muestra el uso de un constructor de clase sin parámetros.

// Constructor sencillo. class MyClass ( int x; // Luego viene el constructor MyClass() ( x = 10; ) )

Para inicializar objetos, debe realizar una llamada de constructor como en el siguiente ejemplo.

Clase pública ConsDemo ( public static void main(String args) ( MyClass t1 = new MyClass(); MyClass t2 = new MyClass(); System.out.println(t1.x + " " + t2.x); ) )

Obtenemos el resultado:

Constructor parametrizado

La mayoría de las veces, necesitará un constructor que tome uno o más parámetros. Agregar parámetros a un constructor es lo mismo que agregarlos a un método, solo necesita ponerlos entre paréntesis después del nombre del constructor.

Ejemplo

// Constructor sencillo. class MyClass (int x; // Debajo del constructor MyClass(int i) ( x = i; ) )

Para inicializar objetos, deberá llamar al constructor como en el siguiente ejemplo.

Clase pública ConsDemo ( public static void main(String args) ( MyClass t1 = new MyClass(10); MyClass t2 = new MyClass(20); System.out.println(t1.x + " " + t2.x); ) )

Obtenemos el siguiente resultado:

palabra clave esta

palabra clave esta- se usa para referirse a la clase actual dado un método de instancia o constructor. Usando esto en Java, puede hacer referencia a instancias de clase como constructores, variables y métodos.

Nota: la palabra clave this solo se usa dentro de métodos de instancia o constructores.

Por lo general, la palabra clave this en Java se usa para:

  • diferenciación entre variables de instancia y variables locales si tienen el mismo nombre, como parte de un constructor o método.
clase Estudiante ( int edad; Estudiante(int edad) ( this.edad = edad; ) )
  • llamar a un constructor de un tipo (constructor parametrizado o constructor predeterminado) desde otro dentro de una clase. Este proceso también se denomina invocación explícita del constructor.
clase Estudiante ( int edad Estudiante() ( this(20); ) Estudiante(int edad) ( this.edad = edad; ) )

Ejemplo

Clase pública This_Example ( // Inicializar la variable num int num = 11; This_Example() ( System. out. println("Este es un programa de ejemplo con la palabra clave this"); ) This_Example(int num) ( // Llamar al valor predeterminado constructor this( ); // Asigne la variable local num a la variable de instancia num this.num = num; ) public void greeting() ( System.out.println("¡Hola! ¡Bienvenido a ProgLang!"); ) public void print() ( // Variable local num int num = 20; // Llamar al método de la clase de saludo this.greet(); // Imprime la variable local. System. out. println("Valor de la variable local num: " + num); // Imprimir variable de instancia. System .out.println("Instance variable value num: " + this.num); ) public static void main(String args) ( // Inicializar This_Example class obj1 = new This_Example(); // Llamar al método de impresión obj1.print() ; // Pasar el nuevo valor de la variable num a través del constructor parametrizado This_Example obj2 = new This_Example(30); // Usted llamando al método de impresión de nuevo obj2.print(); ) )

Como resultado, se obtendrá el siguiente resultado:

Este es un programa de ejemplo con esta palabra clave ¡Hola! ¡Bienvenido a Proglang! Valor de la variable local num: 22 Valor de la variable de instancia num: 11 Este es un programa de ejemplo con la palabra clave this ¡Hola! ¡Bienvenido a Proglang! Valor de la variable local num: 22 Valor de la variable de instancia num: 30

Argumentos variables (var-args)

JDK 1.5 y superior le permite pasar un número variable de argumentos del mismo tipo a un método. Un parámetro en un método se declara así:

TipoNombre... parámetroNombre

Al declarar un método, especifica el tipo seguido de puntos suspensivos (...). Solo se puede especificar un parámetro de longitud variable en un método, y este parámetro debe ser el último parámetro. Cualquier parámetro regular debe precederlo.

Ejemplo

public class VarargsDemo ( public static void main(String args) ( // Método de llamada con argumentos variable printMax(27, 11, 11, 5, 77.1); printMax(new double(10, 11, 12, 77, 71)); ) public static void imprimirMax(doble... numeros) ( if (numeros.longitud == 0) ( System.out.println("Ningún argumento pasó"); return; ) resultado doble = numeros; for (int i = 1 ; i resultado) resultado = numeros[i]; System.out.println("Valor maximo " + resultado); ) )

Como resultado, se obtendrá el siguiente resultado:

Valor máximo 77,1 Valor máximo 77,0

método finalizar ()

método finalizar ()- un método que será llamado inmediatamente antes de la destrucción final del objeto por parte del recolector de basura. (finalizador). En Java, se puede utilizar finalize() para garantizar la finalización limpia de un objeto.

Por ejemplo, podemos usar finalize() para asegurarnos de que se haya cerrado un archivo abierto propiedad de un objeto dado.

Para agregar un finalizador a una clase, simplemente necesita definir un método finalize() en Java. El entorno de tiempo de ejecución de Java llama a este método justo antes de procesar un objeto de esta clase.

Como parte del método finalize(), especifica las acciones que se deben realizar antes de que se destruya el objeto.

En general, el método finalize() se ve así:

Protected void finalize() (//finalización del código aquí)

Aquí, la palabra clave protected representa un especificador que evita que se acceda a finalize() mediante un código definido fuera de su clase.

Esto indica que no puede saber cómo o incluso cuándo se ejecutará finalize(). Por ejemplo, si su programa finaliza antes de la recolección de basura, no se ejecutará finalize().

Un constructor es un método especial que se llama cuando se crea un nuevo objeto. No siempre es conveniente inicializar todas las variables de clase al crear una instancia de la misma. A veces es más fácil tener algunos valores creados por defecto cuando se crea el objeto. De hecho, el constructor es necesario para la inicialización automática de variables.

Un constructor inicializa un objeto directamente en el momento de la creación. El nombre del constructor es el mismo que el nombre de la clase, incluido el caso, y la sintaxis de un constructor es similar a la de un método sin valor de retorno.

Gato int privado(); // así es como se ve el método llamado Cat Cat(); // así es como se ve el constructor de la clase Cat

A diferencia de un método, un constructor nunca devuelve nada.

Un constructor define las acciones a realizar cuando se crea un objeto de una clase y es una parte importante de una clase. Como regla general, los programadores intentan especificar explícitamente un constructor. Si no hay un constructor explícito, Java creará automáticamente uno para uso predeterminado. Cuando implementamos la clase caja, entonces no se creó ningún constructor.

Agreguemos un constructor a la clase que simplemente establecerá los valores iniciales para el cuadro.

Class Box ( int ancho; // ancho de caja int altura; // altura de caja int profundidad; // profundidad de caja // Box() constructor ( ancho = 10; altura = 10; profundidad = 10; ) // calcular volumen de caja int getVolume() (retorna ancho * alto * profundidad; ) )

Hemos eliminado temporalmente el método. establecerDim() y agregó un constructor. Veamos qué pasa:

Caja catBox = nueva Caja(); mInfoTextView.setText("Volumen de caja: " + catBox.getVolume());

El programa generará el volumen de la caja, aunque no le hayamos especificado ninguna dimensión. Gracias al constructor, cualquier caja creada tendrá un volumen fijo.

Naturalmente, puede devolver un método establecerDim()(vea el artículo sobre las clases) y establezca sus propias dimensiones para la caja:

Caja catBox = nueva Caja(); // establecer dimensiones personalizadas para el cuadro catBox.setDim(10, 20, 30); mInfoTextView.setText("Volumen de caja: " + catBox.getVolume());

A estas alturas debería quedarle claro que cuando después de la palabra clave nuevo escribimos el nombre de la clase entre corchetes, entonces en realidad estamos llamando al constructor de la clase.

Surge la pregunta, pero al principio, al crear la clase, no creamos un constructor, sin embargo, el código caja nueva() trabajó. El hecho es que si el constructor no está definido explícitamente, Java creará un constructor que se utilizará de forma predeterminada. En este caso, simplemente asignará valores cero a todas las variables. Si ha creado un constructor usted mismo, no se utilizará el constructor predeterminado.

Como cualquier método, un constructor puede tener argumentos. Los argumentos del constructor pasan parámetros para inicializar el objeto. Por ejemplo, si la clase gato hay un constructor que toma como argumento un entero que denota la edad del gato, entonces los objetos gato se creará así:

Gato gato = nuevo Gato(8); // el gato tiene 8 años

si un gato (int) es el único constructor de clases, el compilador no permitirá que se creen objetos gato de alguna otra manera.

Pero volvamos a las cajas para gatos. El constructor que creamos no es particularmente útil, ya que crea las mismas cajas. Creemos un constructor con parámetros en la clase. caja y comentar el primer constructor sin parámetros:

// Segundo constructor Box(int ​​W, int h, int d) ( ancho = w; alto = h; profundidad = d; )

Si la clase contiene un constructor con parámetros, deberá especificar los valores al declarar la clase:

// Este constructor ya no es válido // Box catBox = new Box(); // En el constructor, debe especificar los valores del tamaño del cuadro Box catBox = new Box(100, 200, 100); mInfoTextView.setText("Volumen de caja: " + catBox.getVolume());

Por cierto, con tal constructor, el método establecerDim() ya no lo necesitamos. Podemos establecer las dimensiones de la caja directamente en el constructor. Dado que lo más probable es que la caja sea constante y no cambie de tamaño, el método quizás sea superfluo. Pero si cambiamos el tamaño del cuadro, entonces habrá que dejar el método.

Una clase puede tener múltiples constructores. Descomente el primer constructor y cree dos cuadros: un cuadro predeterminado y un cuadro grande.

Cuadro defaultBox = new Box(); mInfoTextView.setText("Volumen de caja estándar: " + defaultBox.getVolume()); Caja caja grande = caja nueva (100, 200, 200); mInfoTextView.append("\nVolumen de caja grande: " + bigBox.getVolume());

Es decir, vemos que los constructores admiten la sobrecarga, al igual que los métodos.

Por ejemplo, podemos crear otro constructor específicamente para una caja en forma de cubo, donde todos los lados son iguales:

// Tercer constructor del cubo Box(int ​​​​len) ( ancho = alto = profundidad = largo; )

Calcular el tamaño del cubo:

Caja cubo = nueva Caja(5); intvol = cubo.getVolume(); mInfoTextView.setText("Volumen del cubo: " + vol);

Usar un objeto como parámetro

Hasta ahora hemos usado tipos simples como parámetros en constructores. Pero también puedes pasar un objeto de la propia clase. Agreguemos otro constructor:

// Usa un objeto de tipo Box Box(Box ob) ( ancho = ob.ancho; alto = ob.alto; profundidad = ob.profundidad; )

En el código del programa, puede usar el constructor de la siguiente manera:

Caja1 = nueva Caja(100, 200, 100); Box cloneBox = new Box(box1); intvol = cloneBox.getVolume(); mInfoTextView.setText("Volumen de la caja: " + vol);

Clase de caja (fuente)

paquete en.alexanderklimov.box; class Box ( int ancho; // ancho del cuadro int alto; // alto del cuadro int profundidad; // profundidad del cuadro // Constructor Box() ( ancho = 10; alto = 10; profundidad = 10; ) // Segundo constructor Box( int w, int h, int d) ( ancho = w; alto = h; profundidad = d; ) // Tercer constructor del cubo Box(int ​​​​len) ( ancho = alto = profundidad = len; ) // Usa un objeto de tipo Box Box(Box ob) ( ancho = ob.ancho; alto = ob.alto; profundidad = ob.profundidad; ) // calcula el volumen del cuadro int getVolume() ( return ancho * alto * profundidad; ) // establecer las dimensiones de la caja void setDim (int w, int h, int d) ( ancho = w; altura = h; profundidad = d; ) )

Llamar a constructores sobrecargados a través de this()

Cuando se trata de constructores sobrecargados, es conveniente llamar a un constructor desde otro a través de la palabra clave este. Al ejecutar el constructor este() el constructor sobrecargado que coincide con la lista de parámetros se ejecuta primero. Luego, se ejecutan las declaraciones dentro del constructor original, si las hay. Llamada del constructor este() debe ser la primera declaración en el constructor.

Primero, creemos una clase que no use un constructor. este() para entender la diferencia.

Clase Gato ( int edad; int cumpleaños; // Inicializar variables explícitamente Gato(int i, int j) ( edad = i; cumpleaños = j; ) // Inicializar variables con el mismo valor Gato(int i) ( edad = i; cumpleaños = i; ) // Establecer los valores predeterminados en 0 Cat() ( edad = 0; cumpleaños = 0; ) )

Hemos creado una clase con tres constructores. Reescribir la clase usando el constructor. este().

Clase Cat( int edad; int cumpleaños; // Inicializa variables explícitamente Cat(int i, int j) ( edad = i; cumpleaños = j; ) // Inicializa variables con el mismo valor Cat(int i) ( this(i, i); // llamando a Cat(i, i); ) // Establece los valores predeterminados en 0 Cat() ( this(0); // llamando a Cat(0); ) )

Ahora solo tenemos un constructor que asigna valores a los campos: Cat(int, int). Qué sucede cuando se ejecuta la instrucción:

Gato gato = nuevo Gato(8);

Llamada del constructor gato(8) hace que se ejecute el constructor esto(8, 8), que es equivalente a llamar al constructor Gato(8, 8).

Qué sucede cuando se ejecuta la instrucción:

Gato gato2 = nuevo Gato();

En este caso, el constructor se llama este(0), lo que hace que el constructor se ejecute gato(0), ya que esta es la versión del constructor que coincide con la lista de parámetros. Al mismo tiempo, el constructor gato(0) esencialmente llama al constructor gato(0, 0).

Uso de constructores sobrecargados a través de un constructor este() le permite eliminar la duplicación de código, reduciendo el tiempo de carga de clases.

Pero cuidado, porque los constructores que llaman a un constructor este(), son un poco más lentos.

constructor privado

A veces, una clase se crea solo para almacenar algunos campos estáticos y métodos estáticos. Es costumbre que tales clases sean nombradas utilidades, pero esto es opcional. Dicha clase no necesita un constructor, pero si el autor de la clase no creó uno, entonces el propio sistema creará un constructor predeterminado. Tal constructor no tiene sentido y también puede ser una fuente de errores. Para protegerse contra este problema, usted mismo debe crear explícitamente un constructor vacío y hacerlo privado.

Public class Utils ( private Utils() ( throw new AssertionError(); ) ... //su código correcto // ¡Código incorrecto, solo con fines de demostración! public static void someMethod()( Utils utils = new Utils(); utils .toString(); ) )

Línea lanzar un nuevo error de afirmación () no es obligatorio, pero ayudará a detectar el error si llama al constructor en la clase misma. El compilador omitirá esta opción, pero el programa se cerrará con un error.

Utils.algunMetodo(); // el programa se cerrará con un error

No puede crear una subclase para esta clase.

El hecho es que:

1. Si crea una clase y define un constructor con argumentos (clase AClass, que tiene solo un constructor que toma int i), entonces el compilador ya no creará un constructor predeterminado. Porque eso rompería el contrato de AClass, que no se puede inicializar sin argumentos. Si también desea tener un constructor predeterminado, configúrelo explícitamente ahora.

De lo contrario, sería imposible evitar la creación de un constructor predeterminado, lo que sería malo.

2. Al crear constructores de una clase BClass que se hereda de otra clase, el compilador requiere que la primera línea del constructor sea una llamada a otro constructor (heredado o de esta clase).

¿Por qué? Porque dado que se deriva de una clase, desea reutilizar su lógica. El constructor trae una instancia de la clase a algún estado integral inicial. En su caso, AClass requiere un argumento para inicializarse, sin el cual la JVM no sabe cómo inicializar una instancia de la clase.

Si la clase no tiene constructores definidos, intenta crear un constructor predeterminado, es decir, sin argumentos:

clase pública AClass1 ( )

Dado que aquí no se definen explícitamente constructores Y la clase no se hereda de otras clases, el compilador genera un constructor predeterminado.

Esto es equivalente a esta definición:

Clase pública AClass1 ( pública AClass1() ( ) )

Ahora veamos BClass1:

clase pública BClass1 extiende AClass1 ( )

Aquí, también, los constructores no están definidos explícitamente y el compilador intenta crear un constructor predeterminado. Dado que la clase AClass1 tiene un constructor predeterminado, creará un constructor predeterminado que llamará al constructor de AClass1. Este código es equivalente a esto:

La clase pública BClass1 extiende AClass1 (public BClass1() (super(); ))

En su caso, se crea una clase SIN un constructor predeterminado:

Clase A pública ( Clase A pública (int i) ( ) )

Dado que (al menos un) constructor se declara aquí, el constructor predeterminado ya no se crea. Es decir, dicho código ya no se compilará:

ClaseA a = new ClaseA(); // No funciona

necesito algo como

ClaseA a = nueva ClaseA(1);

En consecuencia, cualquier constructor de BClass requerirá una llamada a algún constructor de AClass o BClass. Con esta descripción, el compilador jurará:

BClass pública extiende AClass()

Porque habrá un intento de llamar al constructor predeterminado de la clase AClass, que no está definido:

Public BClass extiende AClass ( public BClass() ( super(); // error; no existe tal constructor en AClass ) )

Sin embargo, es posible crear una BClass con un constructor predeterminado configurando el constructor AClass en algún valor:

La clase pública BClass extiende AClass (public BClass() (super(1);))

Esto compilará.

¡Hola! Hoy analizaremos un tema muy importante que concierne a nuestros objetos. ¡Aquí, sin exagerar, podemos decir que utilizará este conocimiento todos los días en el trabajo real! Hablaremos de constructores.

Es posible que haya escuchado este término por primera vez, pero de hecho probablemente usó constructores, solo que usted mismo no lo notó :) Veremos esto más adelante.

¿Qué son los constructores y por qué son necesarios?

Consideremos dos ejemplos. public class Car ( String model; int maxSpeed; public static void main (String args) ( Car bugatti = new Car () ; bugatti. model = "Bugatti Veyron" ; bugatti. maxSpeed ​​​​= 407 ; ) ) Creamos nuestro auto e instalado para él modelo y máxima velocidad. Sin embargo, en un proyecto real, el objeto Coche obviamente no tendrá 2 campos. Y, por ejemplo, ¡16 campos! coche de clase pública ( String modelo; //modelo int maxSpeed; //máxima velocidad//volumen del motor//apellido del propietario//cantidad de asientos en la cabina Salón de cuerdasMaterial; // material interior seguro booleano; // esta asegurado//país productor inttrunkVolume; // volumen del maletero int aceleración a 100 km; public static void main (String args) ( Coche bugatti = nuevo Coche () ; bugatti. color = "azul" ; bugatti. aceleración a 100 km = 3 ; bugatti. engineVolume = 6.3 ; bugatti. fabricantePaís = "Italia" ; bugatti. propietarioNombre = " Amigo" ; bugatti. yearOfIssue = 2016 ; bugatti. insurance = true ; bugatti. price = 2000000 ; bugatti. isNew = false ; bugatti. placesInTheSalon = 2 ; bugatti. maxSpeed ​​​​= 407 ; bugatti. model = "Bugatti Veyron" ; ) ) Hemos creado un nuevo objeto Coche. Un problema: tenemos 16 campos, pero inicializamos solo 12! ¡Prueba ahora por código para encontrar los que olvidamos! No es tan fácil, ¿verdad? En tal situación, el programador puede cometer un error fácilmente y omitir la inicialización de algún campo. Como resultado, el comportamiento del programa será erróneo: public class Car ( String model; //model int maxSpeed; //máxima velocidad ruedas internas; //ancho del disco double engineVolume; //volumen del motor color de cuerda; //color int yearOfIssue; //año de emisión String propietarioNombre; //nombre del propietario String propietarioApellido; //apellido del propietario precio largo; //precio booleano esNuevo; //nuevo o no int lugaresEnElSalon; //cantidad de asientos en la cabina Salón de cuerdasMaterial; // material interior seguro booleano; // esta asegurado País fabricante de cuerdas; //país productor inttrunkVolume; // volumen del maletero int aceleración a 100 km; //aceleración a 100 km/h en segundos public static void main (String args) ( Coche bugatti = nuevo Coche () ; bugatti. color = "azul" ; bugatti. aceleración a 100 km = 3 ; bugatti. engineVolume = 6.3 ; bugatti. fabricantePaís = "Italia" ; bugatti. propietarioNombre = " Amigo" ; bugatti. yearOfIssue = 2016 ; bugatti. insurance = true ; bugatti. price = 2000000 ; bugatti. isNew = false ; bugatti. placesInTheSalon = 2 ; bugatti. maxSpeed ​​​​= 407 ; bugatti. model = "Bugatti Veyron" ; System.out.println( "Modelo Bugatti Veyron. Tamaño del motor - "+ bugatti. volumen del motor + ", maletero - " + bugatti. maleteroVolumen+ ", el salón está hecho de"+ bugatti. salonMaterial + ", ancho del disco -"+ bugatti. ruedas + ". Fue adquirida en 2018 por el Sr. "+ bugatti. propietarioApellido); ) ) Salida de consola: Modelo Bugatti Veyron. Tamaño del motor - 6.3, maletero - 0, interior hecho de nulo, ancho de rueda - 0. Fue comprado en 2018 por el Sr. nulo A su comprador que pagó $ 2 millones por un automóvil obviamente no le gustará que lo nombren " señor nulo”! Pero en serio, como resultado, nuestro programa terminó con un objeto creado incorrectamente: un automóvil con un ancho de disco de 0 (es decir, sin discos), un baúl perdido, un interior hecho de un material desconocido e incluso perteneciente a alguien que sabe. ¡Uno solo puede imaginar cómo un error de este tipo puede "disparar" cuando el programa se está ejecutando! Tenemos que evitar de alguna manera tales situaciones. Es necesario que nuestro programa tenga una restricción: al crear un nuevo objeto máquina para él siempre debe especificarse, por ejemplo, el modelo y la velocidad máxima. De lo contrario, no permita la creación de objetos. Esta tarea se maneja fácilmente funciones constructoras. Obtuvieron su nombre por una razón. El constructor crea una especie de "esqueleto" de la clase, al que debe corresponder cada nuevo objeto de la clase. Para mayor comodidad, volvamos a una versión más simple de la clase Car con dos campos. Dados nuestros requisitos, el constructor de la clase Car se verá así: public Car (String model, int maxSpeed) ( this . model = model; this . maxSpeed ​​​​= maxSpeed; ) Y la creación del objeto ahora se verá así: public static void main (String args) (Car bugatti = new Car ("Bugatti Veyron", 407) ;) como se crea el constructor. Es similar a un método regular, pero no tiene un tipo de devolución. En este caso, el nombre de la clase se indica en el constructor, también con mayúscula. En nuestro caso - Coche . Además, el constructor usa una nueva palabra clave para usted este. "esto" en inglés - "este". Esta palabra se refiere a un tema específico. El código en el constructor: public Car (String model, int maxSpeed) ( this . model = model; this . maxSpeed ​​​​= maxSpeed; ) se puede traducir casi literalmente: " model for this car (que estamos creando actualmente) = argumento modelo, que se especifica en constructor.maxSpeed ​​​​para esta máquina (que estamos creando) = al argumento maxSpeed ​​​​dado en el constructor". Y así sucedió: public class Car ( String model; int maxSpeed; public Car (String model, int maxSpeed) ( this . model = model; this . maxSpeed ​​​​= maxSpeed; ) public static void main (String args) ( Car bugatti = coche nuevo ("Bugatti Veyron" , 407 ) ; System. out. println (bugatti. model) ; System. out. println (bugatti. maxSpeed) ; ) ) Salida de la consola: bugatti veyron 407 El constructor asignó con éxito los valores deseados. ¡Puede que hayas notado que un constructor es muy similar a un método regular! Así es: un constructor es un método, solo un poco específico :) Al igual que en un método, pasamos parámetros a nuestro constructor. Y al igual que llamar a un método, llamar a un constructor fallará si no se especifican: public class Car ( String model; int maxSpeed; public Car (String model, int maxSpeed) ( this . model = model; this . maxSpeed ​​​​= maxSpeed; ) public static void main (String args) ( Car bugatti = new Car () ; //error! ) ) Mira, el constructor hizo lo que estábamos tratando de lograr. ¡Ahora no puedes crear un coche sin velocidad o sin modelo! Las similitudes entre constructores y métodos no terminan ahí. Al igual que los métodos, los constructores pueden ser sobrecarga. Imagina que tienes 2 gatos en casa. Tomaste a uno de ellos cuando era un gatito, y trajiste al segundo a casa de la calle cuando era adulto y no sabes exactamente cuántos años tiene. Esto significa que nuestro programa debería poder crear gatos de dos tipos: con un nombre y una edad para el primer gato, y solo con un nombre, para el segundo gato. Para ello sobrecargaremos el constructor: public class Gato ( String nombre; int edad; //para el primer gato //para el segundo gato public Cat (String name) ( this . name = name; ) public static void main (String args) ( Cat barsik = new Cat ("Barsik" , 5 ) ; Cat streetCatNamedBob = new Cat ("Bob" ) ; ) ) el constructor original con los parámetros “nombre” y “edad”, le añadimos otro, solo con el nombre. De la misma manera, sobrecargamos los métodos en lecciones anteriores. Ahora podemos crear con éxito ambas variantes de gatos :)

¿Recuerda, al comienzo de la lección, dijimos que ya usaba constructores, pero usted mismo no lo notó? Y ahí está. El hecho es que cada clase en Java tiene un llamado Constructor predeterminado. No toma ningún argumento, pero se dispara cada vez que se crea cualquier objeto de cualquier clase. public class Cat ( public static void main (String args) ( Cat smears = new Cat () ; ) ) A primera vista, esto es invisible. Bueno, crearon un objeto y lo crearon, ¿dónde está el trabajo del constructor? Para ver esto, escribamos directamente un constructor vacío para la clase Cat, y dentro de él mostraremos alguna frase en la consola. Si se muestra, entonces el constructor ha funcionado. public class Cat ( public Cat () ( System. out. println ("¡Se creó un gato!"); ) public static void main (String args) ( Cat smears = new Cat () ; //aquí es donde trabajaba el constructor por defecto } } Salida de la consola: ¡Creó un gato! ¡Aquí está la confirmación! El constructor predeterminado siempre está presente de forma invisible en sus clases. Pero necesitas saber una característica más de él. El constructor predeterminado desaparece de la clase cuando crea algún constructor con argumentos. La prueba de esto, de hecho, ya la hemos visto más arriba. Aquí en este código: public class Cat (String name; int age; public Cat (String name, int age) ( this . name = name; this . age = age; ) public static void main (String args) ( Cat barsik = new Cat () ; //error! ) ) No pudimos crear un gato sin nombre y edad porque definimos un constructor para Cat: cadena + número. El constructor predeterminado justo después de eso desaparecido de la clase Por lo tanto, asegúrese de recordar: si necesita varios constructores en su clase, incluido el vacío, debe crearse por separado. Por ejemplo, estamos creando un programa para una clínica veterinaria. Nuestra clínica quiere hacer buenas obras y ayudar a los gatos sin hogar, de los que no sabemos ni el nombre ni la edad. Entonces nuestro código debería verse así: public class Cat ( String name; int age; //para gatos domésticos public Cat (String nombre, int edad) ( este . nombre = nombre; este . edad = edad; ) //para gatos callejeros public Cat () ( ) public static void main (String args) ( Cat barsik = new Cat ("Barsik" , 5 ) ; Cat streetCat = new Cat () ; ) ) Ahora que hemos escrito explícitamente un constructor predeterminado, podemos crea gatos de ambos tipos :) Para un constructor (como para cualquier método), el orden de los argumentos es muy importante. Intercambiemos los argumentos de nombre y edad en nuestro constructor. public class Gato ( String nombre; int edad; public Cat (int edad, String nombre) ( this . nombre = nombre; this . edad = edad; ) public static void main (String args) ( Cat barsik = new Cat ("Barsik " , 10 ) ; //¡Error! ) ) ¡Error! El constructor describe claramente: al crear un objeto Cat, debe pasarse número y cadena, en ese orden. Por lo tanto, nuestro código no funciona. Asegúrese de tener esto en cuenta y tenga esto en cuenta al crear sus propias clases: public Cat (String name, int age) ( this . name = name; this . age = age; ) public Cat (int age, String name) ( this . age = age; this .name = name; ) ¡Estos son dos constructores completamente diferentes! Si expresas en una oración la respuesta a la pregunta ¿Por qué necesitas un constructor?, puedes decir: para garantizar que los objetos estén siempre en el estado correcto. Cuando usa constructores, todas sus variables se inicializarán correctamente y no habrá máquinas con velocidad 0 y otros objetos "incorrectos" en el programa. Su uso es muy beneficioso principalmente para el propio programador. Si inicializa los campos usted mismo, existe un gran riesgo de perder algo y cometer un error. Pero esto no sucederá con el constructor: si no le pasó todos los argumentos requeridos o mezcló sus tipos, el compilador inmediatamente dará un error. Por separado, vale la pena mencionar que dentro del constructor no debes poner la lógica de tu programa. Para ello, tienes a tu disposición métodos, en el que puedes describir toda la funcionalidad que necesitas. Veamos por qué la lógica del constructor es una mala idea: public class CarFactory ( String name; int age; int carsCount; public CarFactory (String name, int age, int carsCount) ( this . name = name; this . age = age; this. cantidaddeautos = cantidaddeautos;sistema.salida.println( "Ella fue fundada" "En promedio ella produce"+ (this . carsCount/ this . age) + "cars per year" ) ; ) public static void main (String args) ( CarFactory ford = new CarFactory ("Ford", 115 , 50000000 ) ; ) ) Tenemos una clase Fábrica de coches, que describe una fábrica de automóviles. Dentro del constructor, inicializamos todos los campos y ponemos la lógica aquí: imprime información sobre la fábrica en la consola. Parece que no hay nada de malo en esto, el programa funcionó perfectamente. Salida de la consola: Nuestra fábrica de autos se llama Ford Fue fundada hace 115 años Durante ese tiempo, produjo 50,000,000 autos En promedio, produce 434,782 autos por año Pero, de hecho, hemos colocado una bomba de relojería. Y dicho código puede conducir muy fácilmente a errores. Imagine que ahora no estamos hablando de Ford, sino de la nueva fábrica "Amigo Motors", que existe desde hace menos de un año y produjo 1000 autos: public class CarFactory ( String name; int age; int carsCount; public CarFactory (String nombre, int edad, int cantidad de autos) ( este . nombre = nombre; esta . edad = edad; esta . cantidad de autos = cantidad de autos; System. out. println ( "Nuestra fábrica de automóviles se llama"+ esto nombre); Sistema. afuera. imprimir ( "Ella fue fundada"+ esto edad + "hace años"); Sistema. afuera. imprimir ( "Durante este tiempo se produjo"+ esto cochesCuenta + "coches" ) ; Sistema. afuera. imprimir ( "En promedio ella produce"+ (this . carsCount/ this . age) + "cars per year" ) ; ) public static void main (String args) ( CarFactory ford = new CarFactory ("Amigo Motors", 0 , 1000 ) ; ) ) Salida de la consola: Nuestra fábrica de automóviles se llama Amigo Motors Exception en el subproceso "main" java.lang.ArithmeticException: / by zero Fue fundada hace 0 años Durante este tiempo, produjo 1000 automóviles en CarFactory. (CarFactory.java:15) en CarFactory.main(CarFactory.java:23) El proceso terminó con el código de salida 1¡Hemos llegado! El programa terminó con algún extraño error. ¿Puedes adivinar cuál es la razón? La razón está en la lógica que ponemos en el constructor. En concreto, en esta línea: System. afuera. imprimir ( "En promedio ella produce"+ (this . carsCount/ this . age) + "cars per year" ) ; Aquí realizamos un cálculo y dividimos el número de máquinas producidas por la edad de la fábrica. Y como nuestra fábrica es nueva (es decir, tiene 0 años), el resultado es una división por 0, lo cual está prohibido en matemáticas. Como resultado, el programa termina con un error. ¿Cómo deberíamos haber hecho? Mueva toda la lógica a un método separado y llámelo, por ejemplo, printFactoryInfo() . Puede pasarle un objeto CarFactory como parámetro. También puede poner toda la lógica allí y, al mismo tiempo, el procesamiento de posibles errores, como el nuestro con cero años. A cada uno lo suyo. Se necesitan constructores para establecer correctamente el estado de un objeto. Para la lógica de negocios, tenemos métodos. No mezcle uno con el otro. Aquí hay algunos enlaces útiles donde puede leer más sobre los constructores:



¿Te gustó el artículo? Compártelo