Java para programadores(4.1). metodos y variables de clase y de objeto

LA PROGRAMACIÓN ORIENTADA A OBJETOS (OOP) es un intento de hacer programas mas cercanos al modelo de como las personas piensan sobre ellos, y como se comportan con el resto del mundo. En el centro de la programación está la idea es realizar un trabajo, y la programación consiste en encontrar una secuencia de instrucciones que realicen la tarea. En el centro de la programación orientada a objetos, hay objetos– entidades que tienen un comportamiento, que guardan información, y que interactuan con otros. La programación consiste entonces en diseñar un conjunto de objetos que tengan relación con el problema. El conjunto de “objetos programas” pueden representar entidades abstractas o reales en el área de definición del problema. Esto supone el hacer un diseño del programa mucho mas natural, y por consiguiente, mas fácil de seguir y de entender.

Lo mas importante de OOP es el cambio total del punto de vista. Cuando pensamos en objetos en la programación estándar, el término solo significa que vamos a unir unas cuantas variables con las rutinas necesarias para manejarlas.

De hecho es posible el utilizar las técnicas de la programación orientada a objetos en cualquier lenguaje de programación.

Sin embargo existe una gran diferencia entre un lenguaje que hace la OOP posible frente a otro que cuente con un soporte activo. En un lenguaje de programación orientada a objetos como Java, se incluyen muchas características que lo hacen totalmente distinto a un lenguaje estándar. Para poder emplear todas estas características adecuadamente, debe “orientar” su forma de pensar adecuadamente.

Las clases en Java son plantillas para hacer objetos. Cada objeto pertenece a una sola clase.

Un objeto es una instancia de una clase.

La clase de un objeto determina que tipo de datos contiene y cual es su comportamiento.Los datos de los objetos se guardan en un juego de variables que se llaman Instancias variables. Es importante entender que la clase de un objeto determina que tipo de variables contiene el objeto, sin embargo, los datos reales están contenidos en objetos individuales, no en la clase, de esta forma, cada objeto posee sus propios datos.

Por ejemplo,podría existir una clase llamada Student. La clase puede indicar que cada objeto del tipo Student incluye una variable llamada name de tipo String. Puede haber cualquier número de objetos pertenecientes a la clase Student. Cada uno de esos objetos, por pertenecer a la clase Student deben tener un name.

El hecho es que cada uno de los objetos Studen tendrán su propio nombre. De forma similar, si los objetos de la clase Student tienen una variable que representa las notas de los exámenes, cada uno de los objetos Student tienen su propio juego de notas.

Adicionalmente a los datos, los objetos también tienen comportamientos. Estos comportamientos son métodos que pertenecen al objeto. Generalmente estoy utilizando el termino de “método” para las subrutinas que pertenecen a un objeto y que representan como se comporta. Estos métodos son instancias de métodos, porque pertenecen a una instancia de la clase.

Los objetos que pertenecen a una misma clase tienen los mismos métodos , esto es tienen el mismo comportamiento. Sin embargo, no debe olvidar que las instancias de los métodos pertenecen a los objetos individuales y no a la clase.

Hay una sutil diferencia entre las instancias de un mismo método en dos objetos diferentes pertenecientes a la misma clase. El método perteneciente al objeto tiene un acceso directo a las variables del objeto en particular.Por ejemplo, la clase Student puede especificar un método instanciable para calcular la nota global de un estudiante promediando las notas de sus exámenes. Cuando se llama al método para un objeto concreto de la clase Student usara usará las notas de ese estudiante tomándolas de las variables del objeto. El mismo método llamado para un estudiante diferente, usara las notas de ese otro estudiante.

Las clases en Java tienen un doble propósito. Uno de ellos, es justamente el que se describe: servir como plantilla para hacer objetos. El otro es uno que ya vimos en anteriores capítulos: mantener agrupadas todas las variables static relacionadas y todos los métodos static. La regla es que las variables y métodos static– esto es, que se declaran con el modificador static, pertenecen a la misma clase y no se crea objeto de esa clase.

Las variables y los métodos non-static no pertenecen del todo a la clase!.En lugar de eso, hay que especificar que variables y métodos instanciables tendrá la clase. Todo esto es algo confuso, no hay duda sobre ello, y podemos afirmar que el diseño de Java en este aspecto, es defectuoso; hubiera sido mejor que asignaran a estas dos funciones distintas de las clases, dos características distintas del lenguaje.

Las variables y los métodos static se llaman también variables de clase y métodos de clase dado que pertenecen a la clase, y no a la instancia de la clase.

Déjeme mostrarle un ejemplo especifico para ver como trabaja todo esto. Considere esta versién simplificada de la clase Student:

public class Student {

       public String name; // Nombre del estudiante
       public int ID; // identificador del estudiante (unico)
       public double test1, test2, test3; // nota de tres exámenes

       public double getAverage() { // Calcular el promedio de nota
          return (test1 + test2 + test3) / 3;
       }

       private static int nextUniqueID = 1;

       public static int getUniqueID() { // devuelve identificador unico
          int thisID = nextUniqueID;
          nextUniqueID++;
          return thisID;
       }

} // Fin de la clase Student

Esta definición de clase dice que un objeto de la clase Student incluirá unas variables instanciables llamadas name, test1, test2, y test3, e incluirá un método instanciable llamado getAverage(). Los names, IDs y tests en los diferentes objetos tendrán, normalmente, valores diferentes. Cuando para un estudiante en particular se llame al método getAverage()calculará el promedio del estudiante, usando las notas de sus exámenes.

Por otra parte, nextUniqueID y getUniqueID() son miembros static de la clase Student. Esto quiere decir que solo hay una copia de la variable nextUniqueID y pertenece a la clase. De forma similar, getUniqueID esta asociado a la clase, y no a una instancia particular. No tiene sentido, y puede ser un error de sintaxis, el que getUniqueID() se refiera a una variable instanciable como name. Un método static no forma parte del objeto y no tiene accedo directo a las variables instanciables que están dentro de un objeto.

El método getUniqueID() puede ser llamado desde fuera de la clase usando el nombre “Student.getUniqueID()” indicando su pertenencia a la clase Student. Esto se puede hacer tanto si existan como si no existen instancias de la clase . El método getAverage(), por otra parte, solo puede ser llamado cuando existe algún objeto de la clase Student. Si std es tal objeto, entonces el método puede llamarse usando el nombre “std.getAverage()” indicando que el método pertenece al objeto std las variables instanciables de std pueden ser mencionadas como std.name, std.ID, std.test1, std.test2, y std.test3.

(Con esto, es posible pensar que un método o una variable static en una clase se comparte por todas las instancias de la clase. Basado en ese razonamiento, Java le va a permitir referirse a los miembros static tanto a través de los objetos, como a través del propio nombre de clase. Esto es, si std es una instancia de la clase Student es correcto el referirse a std.getUniqueID() en lugar de Student.getUniqueID(). Sin embargo, pienso que esa sintaxis solo puede aumentar la confusión y les animo a que la ignoren.

Creo que vale la pena hablar algo sobre la presencia de la variable static nextUniqueID. Dado que es una variable static solo existe una versión de esa variable y solo existe mientras el programa esta funcionando.(Las instancias de las variables, por otra parte, aparecen y desaparecen cuando los objetos se crean o se destruyen).

Al empezar el programa, se almacena en la variable Student.nextUniqueID el valor inicial 1. Cada vez que se llama al método static Student.getUniqueID se incrementa el valor de nextUniqueID. Ahora bien, dado que nextUniqueID como privado, es completamente inaccesible desde fuera de la clase Student. Podemos ver todo lo que se puede hacer con esa variable examinando la clase Student.

Esto es la mejor garantía de que solo hay una manera de cambiar el valor de nextUniqueID y es llamando al método getUniqueID(). Podría ser interesante que otras variables como las instanciables test1, test2 y test3 tuvieran una protección similar. Volverá al tema de controlar el acceso a las variables, mas tarde.

Hasta ahora hemos hablado de que los objetos pueden ser creados usando las clases como plantilla, pero no hemos hablado de como crear los objetos en los programas. Si tiene una clase, como Student, puede declarar una variable de esa clase:

Student std; //declarar variable std como de tipo Student

Sin embargo, declarar una variable no crea un objeto.Esto es un punto muy importante, que queda definido con la siguiente Afirmación Muy Importante:

En Java, una variable no puede almacenar un objeto
La variable solo puede almacenar la referencia al objeto.

Debe pensar que los objetos deben estar flotando independientes por la memoria del ordenador. (De hecho, los objetos viven en una parte de la memoria llamada heap.) En lugar del objeto en si mismo, lo que se guarda en la variable es la información necesaria para encontrar ese objeto en la memoria. Esta información se llama referencia o puntero al objeto.En efecto, la referencia a un objeto es la dirección de la posición de la memoria donde se almacena el objeto. Cuando usa una variable tipo objeto, el ordenador emplea la referencia que esta en la variable para poder encontrar el objeto real.

Los objetos realmente se crean con un operador llamado new, que crea el objeto y devuelve la referencia al objeto. Por ejemplo, asumiendo que std es una variable del tipo Student,

std = new Student();

creará  un nuevo objeto del tipo Student y guardará  la referencia a este objeto en la variable std. Se puede acceder a las variables y métodos instanciables del objeto por medio de std,como “std.test1”.

Para una variable como std , cuyo tipo esta definido por una clase, el no referirse a ningún objeto no está inicializada. En ese caso se dice que std guarda una referencia nula.En Java la referencia nula debe ser escrita como “null”. Puede asignar una referencia nula a la variable std diciendo:

std = null;

y puede comprobar si el valor de la variable es nulo

if (std == null) .. ..

Si el valor de la variable es nulo, como puede suponer, será ilegal el referirse a una instancia de variable o a una instancia de método, dado que no existe el objeto, y por lo tanto no hay variables a las que se pueda referir. Por ejemplo, si el valor de la variable std es nulo, entonces es ilegal el referirse a std.test1.Si su programa intenta usar una referencia nula, se producirá un error llamado “null pointer exception”.

A continuación, se muestra la secuencia correcta para trabajar con objetos:

Student std = new Student(); // Declara la variable std
                             // y la inicializa con la
                             // referencia al nuevo objeto
                             // creado de la clase Student
Student std1 = new Student();// Declara std1 y la inicializa
                             // con la referencia a otro
                              // objeto nuevo.
Student std2 = std1; //Declara std2 y la inicializa
                    // por lo que se refiere al
                    // MISMO objeto std1
Studen std3; // Declara std3 y lo inicializa
               // a nulo. (automaticamente)
std.name= "John Smith";
std.ID = Student.getUniqueID();
std1.name = "Mary Jones";
std1.ID = Student.getUniqueID();// El resto de la variables instanciables
                                // tendran como valor cero

Cuando el ordenador ejecuta estas instrucciones, la situación es algo semejante a esto (asumiendo que las dos llamada a getUniqueID() fueron las dos primeras veces que se llamo a este método en el programa):

Java. Clase en memoriaEste dibujo presenta las variables en pequeñas cajas, etiquetadas con el nombre de las variables. Los objetos se presentan como cajas con los bordes redondeados. Cuando una variable contiene una referencia a un objeto,  el valor de la variable se presenta como una flecha que apunta al objeto. Las flechas desde std1 y std2 apuntan al mismo objeto. Esto ilustra el siguiente Punto Muy Importante :

Cuando una variable objeto se asigna a otra, solo se copia la referencia.
El objeto referenciado no se copia.

Esto es muy diferente a la semántica asociada a las instrucciones de asignación.(Donde los valores se referían a los tipos primitivos de Java, la asignación obedecía a la semántica esperada. Esto es: cuando se asignaba, se copiaba el valor entre los tipos primitivos.) Observe que en este ejemplo dado que a std1.names se le asignó el valor “Mary Jones”,  también es cierto que std2.name tiene el valor “Mary Jones”. De hecho, std1.name y std2.name son dos maneras distintas de referirse exactamente a la misma cosa.

Puede utilizar los operadores == y != para comprobar la igualdad o desigualdad entre dos objetos, pero aquí otra ves la semántica es especial. Cuando hace la pregunta “if (std1 == std2)” esta comprobando que las referencias de std1 y std2 apuntan exactamente a la misma dirección de memoria, no esta comprobando si los valores contenidos en los objetos son iguales.Puede ser posible tener dos objetos con el mismo valor en una variable instanciable. Sin embargo, los objetos no se consideraran iguales por el operador ==, porque están almacenados en distintas direcciones de memoria.

Hay una pequeña sorpresa en la ilustración superior. Ya sabíamos que en Java las Strings eran objetos.

En particular, es posible que el valor de la string sea nulo. y, en todos los caso, la variable String solo almacena la referencia a la String no la string en si misma.

Esto explica  el porqué el operador == no funcionaba como se esperaba si se usaba sobre una String (se explicó anteriormente):Dos strings se consideran iguales por el operador == solo si ambas están almacenadas en la misma dirección de memoria, no siendo meramente casual, que ambas tengan los mismos caracteres.

Esto es, si s1 y s2 son dos strings, es posible que s1==s2 sea falso cuando ambas contienen los mismos caracteres!. Es por esto por lo que debe usar la comprobación s1.equals(s2) para comprobar si ambas son iguales.

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.1). metodos y variables de clase y de objeto

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

Deja un comentario