Java para programadores(4.2). Constructores

EN JAVA LOS TIPOS DE OBJETO SON MUY DIFERENTES a los tipos primitivos. La simple declaración de una variable cuyo tipo se define como clase, no crea automáticamente un objeto de esa clase. Los objetos se deben construir de forma explícita. El proceso de construir un objeto representa primero, encontrar memoria disponible en el área heap que pueda emplearse para guardar el objeto y, segundo, rellenar el objeto con las variables instanciables. Como programador, normalmente querrá ejercer algún control sobre el valor inicial que se almacena en las instancias de las variables de este objeto. Hay dos maneras de hacerlo. La primera es proporcionar el valor inicial en la definición de clase en donde se declaran las variables instanciables. Por ejemplo, considere la clase:

        class Mosaic {

             // la clase que representa "mosaics" consiste en
             // cuadrados coloreados alineados en filas y columnas

             int ROWS = 10; // numero de cuadrados por fila
             int COLS = 20; // número de cuadrados por columna
             .
             .   // (resto de la definición de la clase)
             .
          }

Cuando se crea un objeto tipo Mosaic se  incluye dos variables instanciables llamadas ROWS y COLS, que se han inicializado con los valores 10 y 20 respectivamente. De esta manera, cada vez que se cree un objeto nuevo ,msc, de tipo Mosaic, el valor de msc.ROWS será 10 y el valor de msc.COLS será 20. ( Naturalmente, no hay nada que le impida cambiar estos valores, una vez se haya creado el objeto.)

Si no quiere facilitar el valor inicial de una variable instanciable, por defecto, el valor inicial  de la instancia de una variable tipo numérico (int, double,...)   es cero, una boolean se inicializa a False, y una char al carácter de Unicode con numero de código cero.

Una variable instanciable, a su vez también puede ser de tipo Objeto. Para esas variables, el valor inicial es null. (En particular, y dado que String es un objeto, el valor inicial por defecto de una variable de este tipo será null). Naturalmente que si quiere, puede proporcionarles valores iniciales alternativos.

Por ejemplo, la clase Mosaic puede contener una variable instanciable de tipo MosaicWindow, siendo MosaicWindow el nombre de otra clase. La instancia de la variable puede ser inicializada como un nuevo objeto de tipo MosaicWindow de la siguiente manera:

         class Mosaic {
             int ROWS = 10; //numero de cuadros por fila
             int COLS = 20; // numero de cuadros por columna
             MosaicWindow window = new MosaicWindow(); 
                           // la ventana para presentar el mosaico
             .
             .   // (el resto de la definición de la clase)
             .
          }

Cuando se construye un objeto de la clase Mosaic, automáticamente se construye otro objeto de la clase MosaicWindow y la referencia al nuevo MosaicWindow se almacena en la instancia de la variable llamada window (Observe que la instrucción «MosaicWindow window = new MosaicWindow();» no se ejecuta hasta que no se crea el objeto de la clase Mosaic. Y se ejecuta cada vez que se crea un nuevo objeto de la clase Mosaic, lo que quiere decir que cada objeto Mosaic tiene su propio objeto MosaicWindow.)


Existe una segunda manera de llenar con valores iniciales las instancias de las variables de una clase. Se hace facilitando uno o mas constructores por clase. De hecho, los constructores pueden hacer mas cosas que rellenar la instancia de las variables.Pueden realizar cualquier acción que necesite se ejecute cada vez que se crea un objeto de la clase.

El constructor de una clase se define como un método con el mismo nombre de la clase y que no devuelve valor, sin necesidad de void. Un constructor puede tener parámetros. En una clase puede haber varios constructores, creados con diferentes firmas (esto es, creados con diferente numero o tipos de parámetros). Un constructor no puede ser declarado como static, pero por otra parte, no es realmente un método instanciable. La única forma con la que se puede llamar a un constructor es con el operador new. De hecho la sintaxis del operador new es:

new llamada-constructor

Cuando el ordenador evalúa esta expresión, crea un nuevo objeto, ejecuta el constructor, y devuelve una referencia al nuevo objeto.

Como ejemplo, vamos a reescribir la clase Student que utilizamos en la sección anterior:

        public class Student {

           private String name;  // nombre del estudiante
           private int ID;  // identificador del estudiante
           public double test1, test2, test3;   // notas

           private static int nextUniqueID = 1;
                     // Proximo identificador disponible

           Student(String theName) {
                // constructor para objetos Studen;
                // carga el nombre del estudiante,
                // y asigna al estudiante el número
                // de identificacion (ID)
              name = theName;
              ID = nextUniqueID;
              nextUniqueID++;
           }

           public String getName() {
                // metodo accesorio para leer el valor de la
                // instancia de la variable privada, name
              return name;
           }

           public getID() {
                // Metodo para leer el valor de ID
              return ID;
           }

           public double getAverage() {  // Calcula la nota promedio
              return (test1 + test2 + test3) / 3;
           }

        }  // end of class Student

En esta versión de la clase, he facilitado un constructor, Student(String). Este constructor tiene un parámetro de tipo String para especificar el nombre del estudiante. He transformado la variable instanciable name a private, de esta manera tengo un completo control sobre este valor. Si examina la clase , el valor de name solo puede ser asignado por el constructor y no hay forma de cambiarlo: El nombre se asigna a Studenten el momento en que se crea el objeto, y permanece constante durante toda la vida del objeto.

Dado que name es una variable private, he proporcionado una función,getName()que puede ser llamada desde fuera de la clase para obtener el nombre del estudiante. De esta forma, desde fuera de la clase es posible averiguar el nombre del estudiante pero no se puede cambiar. Esta forma es la normal para controlar el acceso a una variable.La instancia de la variable ID de la clase Student trabaja de forma semejante.

Debe saber, de todas formas, que si proporciona valores iniciales a la instancia de una variable, estos valores se calculan antes de llamar al constructor. Es muy normal el emplear una combinación de valores iniciales y constructores para   cargar un objeto nuevo con los valores que deba tener.

Dado que el constructor de esta clase tiene un parámetro de tipo String, deberemos incluir un valor de este tipo cuando realicemos la llamada al constructor. Aquí tenemos algunos ejemplos del uso de este constructor para crear un nuevo objeto de la clase Student:

        std = new Student("John Smith");
        std1 = new Student("Mary Jones");

Probablemente se habrá dado cuenta que en la versión anterior de la clase Student no se había incluido constructor. Y a pesar de eso, también podíamos construir instancias de la clase usando el operador «new Student()«. Existe una regla según la cual, si la clase no tienen ningún constructor, se crea automáticamente uno por defecto, que no tiene parámetros. El constructor por defecto no puede hacer mas que rellenar las instancias de las variables con los valores iniciales.


La única forma de acceder a un objeto, ya existente en la memoria, es a través de la variable que guarda la referencia al objeto. Que le pasa a un objeto si no hay ninguna variable que se refiera a él?. Considere las dos instrucciones siguientes (Aunque en realidad, nunca debería hacer algo así):

           Student std = new Student("John Smith");
           std = null;

En la primera línea, creamos un nuevo objeto Student y guardamos la referencia en la variable std. Pero en la línea siguiente, cambiamos el calor de std, y destruimos la referencia al objeto Student.En realidad no existe ninguna variable mas que haga referencia al objeto ya esta, no la habíamos guardado en ninguna otra variable. Siendo así, no hay ninguna posibilidad que el programa pueda volver a emplear el objeto. Es como si no existiera. De hecho, la memoria ocupada por el objeto puede ser reclamada para usarla en cualquier otro propósito.

Java emplea un proceso llamado garbage collection (recogida de desperdicios) para recuperar la memoria ocupada por los objetos que ya no pueden ser accedidos desde el programa. Es responsabilidad del sistema, no del programador, el seguirle la pista a todos estos «desperdicios».

En muchos otros lenguajes de programación esto es responsabilidad del programador. Desafortunadamente, el seguirle la pista al uso de memoria es una fuente muy importante de errores, y muchos problemas en los programas vienen provocados por estos errores.

Un programador puede borrar accidentalmente un objeto aun cuando tenga todavía referencias al objeto. Esto se llama  un error de «dangling pointer» o puntero falso y provoca el problema cuando el programa intenta acceder al objeto que ya no existe.

Otro tipo de problema es el de «memory leak» o fuga de memoria, donde el programador de forma negligente, olvida ir borrando los objetos que ya no necesita. Esto provoca que la memoria se vaya llenando con objetos que son totalmente inaccesibles y el programa puede llegar a quedarse sin memoria, aunque en realidad haya gran cantidad de ella desperdiciada.

Gracias al sistema empleado en Java, de «recolección de desperdicios», es sencillamente imposible que ocurra este error . Puede que se pregunte el porque de que todos los lenguajes no utilicen este método. En el pasado se considero lento y antirentable. Sin embargo, la investigación en las técnicas de garbage collection combinada con la increíble velocidad de los modernos ordenadores, han conseguido que sea un sistema factible. Los programadores nos debemos alegrar.

Acerca de Miguel Garcia

Programador, Desarrollador web, Formador en distintas areas de informatica y director de equipos multidisciplinares.
Esta entrada fue publicada en Formacion, Java y etiquetada , . Guarda el enlace permanente.

Una respuesta a Java para programadores(4.2). Constructores

  1. Pingback: Java - Un resumen organizado....o no.Recursos para formacion

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.