Utilización de Objetos y Clases¶
Introducción a la POO¶
Orientado a objetos hace referencia a una forma diferente de acometer la tarea del desarrollo de software, frente a otros modelos como el de la programación imperativa, la programación funcional o la programación lógica. Supone una reconsideración de los métodos de programación, de la forma de estructurar la información y, ante todo, de la forma de pensar en la resolución de problemas.
La programación orientada a objetos (POO) es un modelo para la elaboración de programas que ha impuesto en los últimos años. Este auge se debe, en parte, a que esta forma de programar está fuertemente basada en la representación de la realidad; pero también a que refuerza el uso de buenos criterios aplicables al desarrollo de programas.
Atención
La orientación a objetos no es un tipo de lenguaje de programación. Es una metodología de trabajo para crear programas.
En POO, un programa es una colección de objetos que se relacionan entre sí de distintas formas.
Características de la POO¶
Cuando hablamos de Programación Orientada a Objetos, existen una serie de características que se deben cumplir. Cualquier lenguaje de programación orientado a objetos las debe contemplar. Las características más importantes del paradigma de la programación orientada a objetos son:
- Abstracción. Es el proceso por el cual definimos las características más importantes de un objeto, sin preocuparnos de cómo se escribirán en el código del programa, simplemente lo definimos de forma general. En la Programación Orientada a Objetos la herramienta más importante para soportar la abstracción es la clase. Básicamente, una clase es un tipo de dato que agrupa las características comunes de un conjunto de objetos. Poder ver los objetos del mundo real que deseamos trasladar a nuestros programas, en términos abstractos, resulta de gran utilidad para un buen diseño del software, ya que nos ayuda a comprender mejor el problema y a tener una visión global de todo el conjunto. Por ejemplo, si pensamos en una clase Vehículo que agrupa las características comunes de todos ellos, a partir de dicha clase podríamos crear objetos como Coche y Camión. Entonces se dice que Vehículo es una abstracción de Coche y de Camión.
- Modularidad. Una vez que hemos representado el escenario del problema en nuestra aplicación, tenemos como resultado un conjunto de objetos software a utilizar. Este conjunto de objetos se crean a partir de una o varias clases. Cada clase se encuentra en un archivo diferente, por lo que la modularidad nos permite modificar las características de la clase que define un objeto, sin que esto afecte al resto de clases de la aplicación.
- Encapsulación. También llamada "ocultamiento de la información". La encapsulación o encapsulamiento es el mecanismo básico para ocultar la información de las partes internas de un objeto a los demás objetos de la aplicación. Con la encapsulación un objeto puede ocultar la información que contiene al mundo exterior, o bien restringir el acceso a la misma para evitar ser manipulado de forma inadecuada. Por ejemplo, pensemos en un programa con dos objetos, un objeto Persona y otro Coche. Persona se comunica con el objeto Coche para llegar a su destino, utilizando para ello las acciones que Coche tenga definidas como por ejemplo conducir. Es decir, Persona utiliza Coche pero no sabe cómo funciona internamente, sólo sabe utilizar sus métodos o acciones.
- Jerarquía. Mediante esta propiedad podemos definir relaciones de jerarquías entre clases y objetos. Las dos jerarquías más importantes son la jerarquía "es un" llamada generalización o especialización y la jerarquía "es parte de", llamada agregación. Conviene detallar algunos aspectos:
- La generalización o especialización, también conocida como herencia, permite crear una clase nueva en términos de una clase ya existente (herencia simple) o de varias clases ya existentes (herencia múltiple). Por ejemplo, podemos crear la clase CochedeCarreras a partir de la clase Coche, y así sólo tendremos que definir las nuevas características que tenga.
- La agregación, también conocida como inclusión, permite agrupar objetos relacionados entre sí dentro de una clase. Así, un Coche está formado por Motor, Ruedas, Frenos y Ventanas. Se dice que Coche es una agregación y Motor, Ruedas, Frenos y Ventanas son agregados de Coche.
- Polimorfismo. Esta propiedad indica la capacidad de que varias clases creadas a partir de una antecesora realicen una misma acción de forma diferente. Por ejemplo, pensemos en la clase
Animaly la acción de expresarse. Nos encontramos que cada tipo deAnimalpuede hacerlo de manera distinta, losPerrosladran, losGatosmaullan, lasPersonashablamos, etc. Dicho de otra manera, el polimorfismo indica la posibilidad de tomar un objeto (de tipoAnimal, por ejemplo), e indicarle que realice la acción de expresarse, esta acción será diferente según el tipo de mamífero del que se trate.
Objetos y Clases¶
Características de los objetos¶
En este contexto, un objeto de software es una representación de un objeto del mundo real, compuesto de una serie de características y un comportamiento específico. Pero ¿qué es más concretamente un objeto en Programación Orientada a Objetos? Veámoslo.
Definición
Un objeto es un conjunto de datos con las operaciones definidas para ellos. Los objetos tienen un estado y un comportamiento.
Por tanto, estudiando los objetos que están presentes en un problema podemos dar con la solución a dicho problema. Los objetos tienen unas características fundamentales que los distinguen:
- Identidad. Es la característica que permite diferenciar un objeto de otro. De esta manera, aunque dos objetos sean exactamente iguales en sus atributos, son distintos entre sí. Puede ser una dirección de memoria, el nombre del objeto o cualquier otro elemento que utilice el lenguaje para distinguirlos. Por ejemplo, dos vehículos que hayan salido de la misma cadena de fabricación y sean iguales aparentemente, son distintos porque tienen un código que los identifica.
- Estado. El estado de un objeto viene determinado por una serie de parámetros o atributos que lo describen, y los valores de éstos. Por ejemplo, si tenemos un objeto
Coche, el estado estaría definido por atributos comoMarca,Modelo,Color,Cilindrada, etc. - Comportamiento. Son las acciones que se pueden realizar sobre el objeto. En otras palabras, son los métodos o procedimientos que realiza el objeto. Siguiendo con el ejemplo del objeto Coche, el el comportamiento serían acciones como:
arrancar(),parar(),acelerar(),frenar(), etc. Definición de clases.
Una clase java se escribe en un fichero con extensión .java que tiene el mismo nombre que la clase. Por ejemplo la clase Vehículo se escribiría en el fichero Vehiculo.java.
Cuando la clase se compila se obtiene un fichero con el mismo nombre que la clase y extensión .class. Ej.: Vehiculo.class.
Atención
Los identificadores de clase siguen las mismas reglas que otros identificadores de Java (contienen carácter alfanuméricos y especiales, no pueden comenzar por un dígito, no pueden coincidir con una palabra reservada, etc.). Por convenio los identificadores de las clases comienzan por mayúsculas.
Propiedades y métodos de los objetos¶
Como acabamos de ver todo objeto tiene un estado y un comportamiento. Concretando un poco más, las partes de un objeto son:
- Campos, Atributos o Propiedades: Parte del objeto que almacena los datos. También se les denomina Variables Miembro. Estos datos pueden ser de cualquier tipo primitivo (
boolean,char,int,double, etc) o ser a su vez otro objeto. Por ejemplo, un objeto de la claseCochepuede tener un objeto de la claseRuedas(o más concretamente cuatro). - Métodos o Funciones Miembro: Parte del objeto que lleva a cabo las operaciones sobre los atributos definidos para ese objeto.
La idea principal es que el objeto reúne en una sola entidad los datos y las operaciones, y para acceder a los datos privados del objeto debemos utilizar los métodos que hay definidos para ese objeto.
La única forma de manipular la información del objeto es a través de sus métodos. Es decir, si queremos saber el valor de algún atributo, tenemos que utilizar el método que nos muestre el valor de ese atributo. De esta forma, evitamos que métodos externos puedan alterar los datos del objeto de manera inadecuada. Se dice que los datos y los métodos están encapsulados dentro del objeto.
Atributos¶
Los atributos representan la información que almacenan los objetos de la clase. Los atributos son declaraciones de variables dentro de la clase.
Se sigue la siguiente sintaxis (los corchetes indican opcionalidad):
1 2 | |
donde …
- ámbito permite indicar desde qué clases es accesible el atributo.
- tipo indica el tipo de dato del atributo.
- nombreDelAtributo es el identificador del atributo.
Métodos¶
Los métodos determinan qué puede hacer un objeto de la clase, es decir, su comportamiento.
Los métodos realizan algún tipo de acción o tarea y, en ocasiones, devuelven un resultado.
Para realizar su trabajo puede ser necesario que pasemos al método cierta información. Por ejemplo, cuando llamamos al método round de la clase Math, para redondear un número real, debemos indicar al método cual es el número que queremos redondear. A esa información que pasamos a los métodos se le llama parámetros o argumentos.
Ejemplo
1 2 3 4 5 6 7 8 | |
En la definición de un método se distinguen dos partes
- La cabecera, en la cual se indica información relevante sobre el método.
- El cuerpo, que contiene las instrucciones mediante las cuales el método realiza su tarea.
Para definirlos, se sigue la siguiente sintaxis (los corchetes indican opcionalidad):
Ejemplo
1 2 3 4 5 6 7 | |
-
ámbito permite indicar desde qué clases es accesible el método.
-
static, cuando aparece, indica que el método es estático.
-
tipoDevuelto indica el tipo de dato que devuelve el método. La palabra reservada void (que no es ningún tipo de dato), indicaría que el método no devuelve nada.
-
nombreDelMetodo es el identificador del método
-
parámetros es una lista, separada por comas, de los parámetros que recibe el método. De cada parámetro se indica el tipo y un identificador.
Interacción entre objetos¶
Dentro de un programa los objetos se comunican llamando unos a otros a sus métodos. Los métodos están dentro de los objetos y describen el comportamiento de un objeto cuando recibe una llamada a uno de sus métodos. En otras palabras, cuando un objeto, objeto1, quiere actuar sobre otro, objeto2, tiene que ejecutar uno de sus métodos. Entonces se dice que el objeto2 recibe un mensaje del objeto1.
Un mensaje es la acción que realiza un objeto. Un método es la función o procedimiento al que se llama para actuar sobre un objeto.
Los distintos mensajes que puede recibir un objeto o a los que puede responder reciben el nombre de protocolo de ese objeto.
El proceso de interacción entre objetos se suele resumir diciendo que se ha "enviado un mensaje" (hecho una petición) a un objeto, y el objeto determina "qué hacer con el mensaje" (ejecuta el código del método). Cuando se ejecuta un programa se producen las siguientes acciones:
- Creación de los objetos a medida que se necesitan.
- Comunicación entre los objetos mediante el envío de mensajes unos a otros, o el usuario a los objetos.
- Eliminación de los objetos cuando no son necesarios para dejar espacio libre en la memoria del computador.
Recuerda
Los objetos se pueden comunicar entre ellos invocando a los métodos de los otros objetos.
Clases¶
Hasta ahora hemos visto lo que son los objetos. Un programa informático se compone de muchos objetos, algunos de los cuales comparten la misma estructura y comportamiento. Si tuviéramos que definir su estructura y comportamiento del objeto cada vez que queremos crear un objeto, estaríamos utilizando mucho código redundante. Por ello lo que se hace es crear una clase, que es una descripción de un conjunto de objetos que comparten una estructura y un comportamiento común. Y a partir de la clase, se crean tantas "copias" o "instancias" como necesitemos. Esas copias son los objetos de la clase.
Recuerda
Las clases constan de datos y métodos que resumen las características comunes de un conjunto de objetos. Un programa informático está compuesto por un conjunto de clases, a partir de las cuales se crean objetos que interactúan entre sí.
En otras palabras, una clase es una plantilla o prototipo donde se especifican:
- Los atributos comunes a todos los objetos de la clase.
- Los métodos que pueden utilizarse para manejar esos objetos.
Para declarar una clase en Java se utiliza la palabra reservada class. La declaración de una clase está compuesta por:
- Cabecera de la clase. La cabecera es un poco más compleja que como aquí definimos, pero por ahora sólo nos interesa saber que está compuesta por una serie de modificadores, en este caso hemos puesto public que indica que es una clase pública a la que pueden acceder otras clases del programa, la palabra reservada class y el nombre de la clase.
- Cuerpo de la clase. En él se especifican encerrados entre llaves los atributos y los métodos que va a tener la clase.
Ejemplo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Ejemplo
En la unidad anterior ya hemos utilizado clases, aunque aún no sabíamos su significado exacto. Por ejemplo, en los ejemplos de la unidad o en la tarea, estábamos utilizando clases, todas ellas eran clases principales, no tenían ningún atributo y el único método del que disponían era el método main().
Ejemplo
También es una clase Math y su método era random(), el que nos permitía usar números aleatorios.
Ejemplo
El método main() se utiliza para indicar que se trata de una clase principal, a partir de la cual va a empezar la ejecución del programa. Este método no aparece si la clase que estamos creando no va a ser la clase principal del programa.
¿Qué significa public class?¶
Significa que la clase que se define es pública. Una clase pública es una clase accesible desde otras clases o, dicho de otra forma, que puede ser utilizada por otras clases. Ya hemos dicho que un programa, de alguna manera, consiste en la creación de objetos de distintas clases, que se relacionan entre sí. Lo más común es que las clases que definimos sean públicas y que en cada fichero de extensión .java se defina una única clase.
Sin embargo, en ocasiones se definen clases (A) que solo van a ser utilizadas por una clase determinada (B). En ese caso, decimos que la clase A es una clase privada de la clase B. Las clases A y B se definen en el mismo fichero .java.
Atención
En un fichero pueden definirse varias clases pero solo una de ellas puede ser pública. De esta forma, si en un fichero se definen varias clases, una de ellas sería pública y el resto serían clases privadas de la primera, a las que solo ésta tendría acceso.
Utilización de Objetos¶
Una vez que hemos creado una clase, podemos crear objetos en nuestro programa a partir de esas clases.
Cuando creamos un objeto a partir de una clase se dice que hemos creado una "instancia de la clase". A efectos prácticos, "objeto" e "instancia de clase" son términos similares. Es decir, nos referimos a objetos como instancias cuando queremos hacer hincapié que son de una clase particular.
Los objetos se crean a partir de las clases, y representan casos individuales de éstas.
Ejemplo
Para entender mejor el concepto entre un objeto y su clase, piensa en un molde de galletas y las galletas. El molde sería la clase, que define las características del objeto, por ejemplo su forma y tamaño. Las galletas creadas a partir de ese molde son los objetos o instancias.
Otro ejemplo, imagina una clase Persona que reúna las características comunes de las personas (color de pelo, ojos, peso, altura, etc.) y las acciones que pueden realizar (crecer, dormir, comer, etc.). Posteriormente dentro del programa podremos crear un objeto Trabajador que esté basado en esa clase Persona. Entonces se dice que el objeto Trabajador es una instancia de la clase Persona, o que la clase Persona es una abstracción del objeto Trabajador.
Cualquier objeto instanciado de una clase contiene una copia de todos los atributos definidos en la clase. En otras palabras, lo que estamos haciendo es reservar un espacio en la memoria del ordenador para guardar sus atributos y métodos. Por tanto, cada objeto tiene una zona de almacenamiento propia donde se guarda toda su información, que será distinta a la de cualquier otro objeto. A las variables miembro instanciadas también se les llama variables instancia. De igual forma, a los métodos que manipulan esas variables se les llama métodos instancia.
En el ejemplo del objeto Trabajador, las variables instancia serían color_de_pelo, peso, altura, etc. Y los métodos instancia serían crecer(), dormir(), comer(), etc.
Ciclo de vida de los objetos¶
Todo programa en Java parte de una única clase, que como hemos comentado se trata de la clase principal.
Esta clase ejecutará el contenido de su método main(), el cual será el que utilice las demás clases del programa, cree objetos y lance mensajes a otros objetos.
Las instancias u objetos tienen un tiempo de vida determinado. Cuando un objeto no se va a utilizar más en el programa, es destruido por el recolector de basura para liberar recursos que pueden ser reutilizados por otros objetos.
A la vista de lo anterior, podemos concluir que los objetos tienen un ciclo de vida, en el cual podemos distinguir las siguientes fases:
- Creación, donde se hace la reserva de memoria e inicialización de atributos.
- Manipulación, que se lleva a cabo cuando se hace uso de los atributos y métodos del objeto.
- Destrucción, eliminación del objeto y liberación de recursos.
Declaración¶
Para la creación de un objeto hay que seguir los siguientes pasos:
-
Declaración: Definir el tipo de objeto.
-
Instanciación: Creación del objeto utilizando el operador
new. Pero ¿en qué consisten estos pasos a nivel de programación en Java? Veamos primero cómo declarar un objeto. Para la definición del tipo de objeto debemos emplear la siguiente instrucción:
1 | |
Donde:
- tipo es la case a partir de la cual se va a crear el objeto, y
- nombre_objeto es el nombre de la variable referencia con la cual nos referiremos al objeto.
Los tipos referenciados o referencias se utilizan para guardar la dirección de los datos en la memoria del ordenador.
Nada más crear una referencia, ésta se encuentra vacía. Cuando una referencia a un objeto no contiene ninguna instancia se dice que es una referencia nula, es decir, que contiene el valor null.
Esto quiere decir que la referencia está creada pero que el objeto no está instanciado todavía, por eso la referencia apunta a un objeto inexistente llamado "nulo".
Para entender mejor la declaración de objetos veamos un ejemplo. Cuando veíamos los tipos de datos, decíamos que Java proporciona un tipo de dato especial para los textos o cadenas de caracteres que era el tipo de dato String. Veíamos que realmente este tipo de dato es un tipo referenciado y creábamos una variable mensaje de ese tipo de dato de la siguiente forma:
1 | |
Los nombres de la clase empiezan con mayúscula, como String, y los nombres de los objetos con minúscula, como mensaje, así sabemos qué tipo de elemento utilizando.
Pues bien, String es realmente la clase a partir de la cual creamos nuestro objeto llamado mensaje(🤯).
Si observas, poco se diferencia esta declaración de las declaraciones de variables que hacíamos para los tipos primitivos. Antes decíamos que mensaje era una variable del tipo de dato String. Ahora realmente vemos que mensaje es un objeto de la clase String. Pero mensaje aún no contiene el objeto porque no ha sido instanciado, veamos cómo hacerlo.
Por tanto, cuando creamos un objeto estamos haciendo uso de una variable que almacena la dirección de ese objeto en memoria. Esa variable es una referencia o un tipo de datos referenciado, porque no contiene el dato si no la posición del dato en la memoria del ordenador.
1 2 3 | |
En las instrucciones anteriores, las variables s y saludo apuntan al mismo objeto de la clase String. Esto implica que cualquier modificación en el objeto saludo modifica también el objeto al que hace referencia la variable s, ya que realmente son el mismo.
Instanciación¶
Una vez creada la referencia al objeto, debemos crear la instancia u objeto que se va a guardar en esa referencia. Para ello utilizamos la orden new con la siguiente sintaxis:
1 | |
Donde:
- nombre_objeto es el nombre de la variable referencia con la cual nos referiremos al objeto.
- new es el operador para crear el objeto.
- Constructor_de_la_Clase es un método especial de la clase, que se llama igual que ella, y se encarga de inicializar el objeto, es decir, de dar unos valores iniciales a sus atributos.
- par1-parN, son parámetros que puede o no necesitar el constructor para dar los valores iniciales a los atributos del objeto.
Durante la instanciación del objeto, se reserva memoria suficiente para el objeto. De esta tarea se encarga Java y juega un papel muy importante el recolector de basura, que se encarga de eliminar de la memoria los objetos no utilizados para que ésta pueda volver a ser utilizada.
De este modo, para instanciar un objeto String, haríamos lo siguiente:
1 | |
Así estaríamos instanciando el objeto mensaje. Para ello utilizaríamos el operador new y el constructor de la clase String a la que pertenece el objeto según la declaración que hemos hecho en el apartado anterior. A continuación utilizamos el constructor, que se llama igual que la clase, String.
En el ejemplo anterior el objeto se crearía con la cadena vacía (""), si queremos que tenga un contenido debemos utilizar parámetros en el constructor, así:
1 | |
Java permite utilizar la clase String como si de un tipo de dato primitivo se tratara, por eso no hace falta utilizar el operador new para instanciar un objeto de la clase String (pero no es lo habitual en el resto de clases).
1 | |
La declaración e instanciación de un objeto puede realizarse en la misma instrucción, así:
1 | |
o para la clase String:
1 | |
Manipulación¶
Una vez creado e instanciado el objeto ¿cómo accedemos a su contenido? Para acceder a los atributos y métodos del objeto utilizaremos el nombre del objeto seguido del operador punto (.) y el nombre del atributo o método que queremos utilizar. Cuando utilizamos el operador punto se dice que estamos enviando un mensaje al objeto. La forma general de enviar un mensaje a un objeto es:
1 | |
Por ejemplo, para acceder a las variables instancia o atributos se utiliza la siguiente sintaxis:
1 | |
Y para acceder a los métodos o funciones miembro del objeto se utiliza la sintaxis es:
1 | |
En la sentencia anterior par1, par2, etc. son los parámetros que utiliza el método. (Aparece entre corchetes para indicar son opcionales).
Para entender mejor cómo se manipulan objetos vamos a utilizar un ejemplo. Para ello necesitamos la Biblioteca de Clases Java o API (Application Programming Interface ‐ Interfaz de programación de aplicaciones). Uno de los paquetes de librerías o bibliotecas es java.awt. Este paquete contiene clases destinadas a la creación de objetos gráficos e imágenes. Vemos por ejemplo cómo crear un rectángulo.
En primer lugar, instanciamos el objeto utilizando el método constructor, que se llama igual que el objeto, e indicando los parámetros correspondientes a la posición y a las dimensiones del rectángulo:
1 | |
Una vez instanciado el objeto rectángulo si queremos cambiar el valor de los atributos utilizamos el operador punto. Por ejemplo, para cambiar la dimensión del rectángulo:
1 2 | |
O bien podemos utilizar un método para hacer lo anterior:
1 | |
A continuación puedes acceder al código del ejemplo:
Ejemplo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Destrucción de objetos y liberación de memoria¶
Cuando un objeto deja de ser utilizado, es necesario liberar el espacio de memoria y otros recursos que poseía para poder ser reutilizados por el programa. A esta acción se le denomina destrucción del objeto.
En Java la destrucción de objetos corre a cargo del recolector de basura (garbage collector). Es un sistema de destrucción automática de objetos que ya no son utilizados. Lo que se hace es liberar una zona de memoria que había sido reservada previamente mediante el operador new. Esto evita que los programadores tengan que preocuparse de realizar la liberación de memoria.
El recolector de basura se ejecuta en modo segundo plano y de manera muy eficiente para no afectar a la velocidad del programa que se está ejecutando. Lo que hace es que periódicamente va buscando objetos que ya no son referenciados, y cuando encuentra alguno lo marca para ser eliminado.
Después los elimina en el momento que considera oportuno.
Justo antes de que un objeto sea eliminado por el recolector de basura, se ejecuta su método finalize(). Si queremos forzar que se ejecute el proceso de finalización de todos los objetos del programa podemos utilizar el método runFinalization() de la clase System. La clase System forma parte de la Biblioteca de Clases de Java y contiene diversas clases para la entrada y salida de información, acceso a variables de entorno del programa y otros métodos de diversa utilidad. Para forzar el proceso de finalización ejecutaríamos:
1 | |
Utilización de Métodos¶
Los métodos, junto con los atributos, forman parte de la estructura interna de un objeto. Los métodos contienen la declaración de variables locales y las operaciones que se pueden realizar para el objeto, y que son ejecutadas cuando el método es invocado. Se definen en el cuerpo de la clase y posteriormente son instanciados para convertirse en métodos instancia de un objeto.
Para utilizar los métodos adecuadamente es conveniente conocer la estructura básica de que disponen.
Al igual que las clases, los métodos están compuestos por una cabecera y un cuerpo. La cabecera también tiene modificadores, en este caso hemos utilizado public para indicar que el método es público, lo cual quiere decir que le pueden enviar mensajes no sólo los métodos del objeto sino los métodos de cualquier otro objeto externo.
Dentro de un método nos encontramos el cuerpo del método que contiene el código de la acción a realizar. Las acciones que un método puede realizar son:
- Inicializar los atributos del objeto
- Consultar los valores de los atributos
- Modificar los valores de los atributos
- Llamar a otros métodos, del mismo del objeto o de objetos externos
Parámetros y valores devueltos¶
Los métodos se pueden utilizar tanto para consultar información sobre el objeto como para modificar su estado. La información consultada del objeto se devuelve a través de lo que se conoce como valor de retorno, y la modificación del estado del objeto, o sea, de sus atributos, se hace mediante la lista de parámetros. En general, la lista de parámetros de un método se puede declarar de dos formas diferentes:
- Por valor. El valor de los parámetros no se devuelve al finalizar el método, es decir, cualquier modificación que se haga en los parámetros no tendrá efecto una vez se salga del método. Esto es así porque cuando se llama al método desde cualquier parte del programa, dicho método recibe una copia de los argumentos, por tanto cualquier modificación que haga será sobre la copia, no sobre las variables originales.
- Por referencia. La modificación en los valores de los parámetros sí tienen efecto tras la finalización del método. Cuando pasamos una variable a un método por referencia lo que estamos haciendo es pasar la dirección del dato en memoria, por tanto cualquier cambio en el dato seguirá modificado una vez que salgamos del método.
Atención
En el lenguaje Java, todas las variables se pasan por valor, excepto los objetos que se pasan por referencia.
En Java, la declaración de un método tiene dos restricciones:
- Un método siempre tiene que devolver un valor (no hay valor por defecto). Este valor de retorno es el valor que devuelve el método cuando termina de ejecutarse, al método o programa que lo llamó. Puede ser un tipo primitivo, un tipo referenciado o bien el tipo
void, que indica que el método no devuelve ningún valor. - Un método tiene un número fijo de argumentos. Los argumentos son variables a través de las cuales se pasa información al método desde el lugar del que se llame, para que éste pueda utilizar dichos valores durante su ejecución. Los argumentos reciben el nombre de parámetros cuando aparecen en la declaración del método.
Recuerda
El valor de retorno es la información que devuelve un método tras su ejecución.
Según hemos visto en el apartado anterior, la cabecera de un método se declara como sigue:
1 | |
Como vemos, el tipo de dato devuelto aparece después del modificador public y se corresponde con el valor de retorno.
La lista de parámetros aparece al final de la cabecera del método, justo después del nombre, encerrados entre signos de paréntesis y separados por comas. Se debe indicar el tipo de dato de cada parámetro así:
1 | |
Atención
Cuando se llame al método, se deberá utilizar el nombre del método, seguido de los argumentos que deben coincidir con la lista de parámetros.
La lista de argumentos en la llamada a un método debe coincidir en número, tipo y orden con los parámetros del método, ya que de lo contrario se produciría un error de sintaxis.
Constructores¶
¿Recuerdas cuando hablábamos de la creación e instanciación de un objeto? Decíamos que utilizábamos el operador new seguido del nombre de la clase y una pareja de abrir‐cerrar paréntesis.
Además, el nombre de la clase era realmente el constructor de la misma, y lo definíamos como un método especial que sirve para inicializar valores. En este apartado vamos a ver un poco más sobre los constructores.
Un constructor es un método especial con el mismo nombre de la clase y que no devuelve ningún valor tras su ejecución.
Cuando creamos un objeto debemos instanciarlo utilizando el constructor de la clase. Veamos la clase Date proporcionada por la Biblioteca de Clases de Java. Si queremos instanciar un objeto a partir de la clase Date tan sólo tendremos que utilizar el constructor seguido de una pareja de abrir‐cerrar paréntesis:
1 | |
Con la anterior instrucción estamos creando un objeto fecha de tipo Date, que contendrá la fecha y hora actual del sistema.
La estructura de los constructores es similar a la de cualquier método, salvo que no tiene tipo de dato devuelto porque no devuelve ningún valor. Está formada por una cabecera y un cuerpo, que contiene la inicialización de atributos y resto de instrucciones del constructor.
El método constructor tiene las siguientes particularidades:
- El constructor es invocado automáticamente en la creación de un objeto, y sólo esa vez.
- Los constructores no empiezan con minúscula, como el resto de los métodos, ya que se llaman igual que la clase y las clases empiezan con letra mayúscula.
- Puede haber varios constructores para una clase.
- Como cualquier método, el constructor puede tener parámetros para definir qué valores dar a los atributos del objeto.
- El constructor por defecto es aquél que no tiene argumentos o parámetros. Cuando creamos un objeto llamando al nombre de la clase sin argumentos, estamos utilizando el constructor por defecto.
- Es necesario que toda clase tenga al menos un constructor. Si no definimos constructores para una clase, y sólo en ese caso, el compilador crea un constructor por defecto vacío, que inicializa los atributos a sus valores por defecto, según del tipo que sean:
0para los tipos numéricos,falsepara losbooleanynullpara los tipo carácter y las referencias. Dicho constructor lo que hace es llamar al constructor sin argumentos de la superclase (clase de la cual hereda); si la superclase no tiene constructor sin argumentos se produce un error de compilación.
Atención
Cuando definimos constructores personalizados, el constructor por defecto deja de existir, y si no definimos nosotros un constructor sin argumentos cuando intentemos utilizar el constructor por defecto nos dará un error de compilación.
El operador this¶
Los constructores y métodos de un objeto suelen utilizar el operador this. Este operador sirve para referirse a los atributos de un objeto cuando estamos dentro de él. Sobre todo se utiliza cuando existe ambigüedad entre el nombre de un parámetro y el nombre de un atributo, entonces en lugar del nombre del atributo solamente escribiremos this.nombre_atributo, y así no habrá duda de a qué elemento nos estamos refiriendo.
Métodos estáticos¶
Cuando trabajábamos con cadenas de caracteres utilizando la clase String, veíamos las operaciones que podíamos hacer con ellas: obtener longitud, comparar dos cadenas de caracteres, cambiar a mayúsculas o minúsculas, etc. Pues bien, sin saberlo estábamos utilizando métodos estáticos definidos por Java para la clase String. Pero ¿qué son los métodos estáticos? Veámoslo.
Los métodos estáticos son aquellos métodos definidos para una clase que se pueden usar directamente, sin necesidad de crear un objeto de dicha clase. También se llaman métodos de clase.
Para llamar a un método estático utilizaremos:
-
El nombre del método, si lo llamamos desde la misma clase en la que se encuentra definido.
-
El nombre de la clase, seguido por el operador punto (
.) más el nombre del método estático, si lo llamamos desde una clase distinta a la que se encuentra definido:
1 | |
- El nombre del objeto, seguido por el operador punto (
.) más el nombre del método estático. Utilizaremos esta forma cuando tengamos un objeto instanciado de la clase en la que se encuentra definido el método estático, y no podamos utilizar la anterior:
1 | |
Los métodos estáticos no afectan al estado de los objetos instanciados de la clase (variables instancia), y suelen utilizarse para realizar operaciones comunes a todos los objetos de la clase. Por ejemplo, si necesitamos contar el número de objetos instanciados de una clase, podríamos utilizar un método estático que fuera incrementando el valor de una variable entera de la clase conforme se van creando los objetos.
En la Biblioteca de Clases de Java existen muchas clases que contienen métodos estáticos. Pensemos en las clases que ya hemos utilizado en unidades anteriores, como hemos comentado la clase String con todas las operaciones que podíamos hacer con ella y con los objetos instanciados a partir de ella. O bien la clase Math para la conversión de tipos de datos. Todos ellos son métodos estáticos que la API de Java define para esas clases. Lo importante es que tengamos en cuenta que al tratarse de métodos estáticos, para utilizarlos no necesitamos crear un objeto de dichas clases.
Fijémonos en esta secuencia de instrucciones
1 2 3 4 5 6 | |
y en esta otra
1 | |
En el primer ejemplo, .setRadio(200) va precedido por un objeto. La variable c1 es un objeto de la clase Círculo, por tanto, la instrucción está modificando el radio de un círculo concreto, el que se encuentra en la posición (50,50) . El método setRadio es un método no estático. Los métodos no estáticos actúan siempre sobre algún objeto (el que figura a la izquierda del punto).
En el segundo ejemplo, en cambio, a la izquierda de .sqrt(4) no se ha puesto el nombre de un objeto, sino el de una clase, la clase Math. El método sqrt no está actuando sobre un objeto concreto: no tiene sentido hacerlo, solo pretendemos calcular la raíz cuadrada de 4. Sqrt es un método estático. Los métodos estáticos se usan poniendo delante del punto el nombre de la clase en que se encuentran definidos.
Librerías de Objetos (Paquetes)¶
Conforme nuestros programas se van haciendo más grandes, el número de clases va creciendo. Meter todas las clases en único directorio no ayuda a que estén bien organizadas, lo mejor es hacer grupos de clases, de forma que todas las clases que estén relacionadas o traten sobre un mismo tema estén en el mismo grupo.
Un paquete de clases es una agrupación de clases que consideramos que están relacionadas entre sí o tratan de un tema común.
Recuerda
Las clases de un mismo paquete tienen un acceso privilegiado a los atributos y métodos de otras clases de dicho paquete. Es por ello por lo que se considera que los paquetes son también, en cierto modo, unidades de encapsulación y ocultación de información.
Java nos ayuda a organizar las clases en paquetes. En cada fichero .java que hagamos, al principio, podemos indicar a qué paquete pertenece la clase que hagamos en ese fichero.
Los paquetes se declaran utilizando la palabra clave package seguida del nombre del paquete.
Para establecer el paquete al que pertenece una clase hay que poner una sentencia de declaración como la siguiente al principio de la clase:
1 | |
Por ejemplo, si decidimos agrupar en un paquete ejemplos un programa llamado Bienvenida, pondríamos en nuestro fichero Bienvenida.java lo siguiente:
1 2 3 4 5 | |
El código es exactamente igual que como hemos venido haciendo hasta ahora, solamente hemos añadido la línea package ejemplos; al principio.
Sentencia import¶
Cuando queremos utilizar una clase que está en un paquete distinto a la clase que estamos utilizando, se suele utilizar la sentencia import. Por ejemplo, si queremos utilizar la clase Scanner que está en el paquete java.util de la Biblioteca de Clases de Java, tendremos que utilizar esta sentencia:
1 | |
Se pueden importar todas las clases de un paquete, así:
1 | |
Esta sentencia debe aparecer al principio de la clase, justo después de la sentencia package, si ésta existiese.
También podemos utilizar la clase sin sentencia import, en cuyo caso cada vez que queramos usarla debemos indicar su ruta completa:
1 | |
Hasta aquí todo correcto. Sin embargo, al trabajar con paquetes, Java nos obliga a organizar los directorios, compilar y ejecutar de cierta forma para que todo funcione adecuadamente.
Librerías Java¶
Cuando descargamos el entorno de compilación y ejecución de Java, obtenemos la API de Java. Como ya sabemos, se trata de un conjunto de bibliotecas que nos proporciona paquetes de clases útiles para nuestros programas. Utilizar las clases y métodos de la Biblioteca de Java nos va ayudar a reducir el tiempo de desarrollo considerablemente, por lo que es importante que aprendamos a consultarla y conozcamos las clases más utilizadas.
Ejemplo
1 2 | |
Los paquetes más importantes que ofrece el lenguaje Java son:
| Paquete o librería | Descripción |
|---|---|
| java.io | Contiene las clases que gestionan la entrada y salida, ya sea para manipular ficheros, leer o escribir en pantalla, en memoria, etc. Este paquete contiene por ejemplo la clase BufferedReader que se utiliza para la entrada por teclado. |
| java.lang | Contiene las clases básicas del lenguaje. Este paquete no es necesario importarlo, ya que es importado automáticamente por el entorno de ejecución. En este paquete se encuentra la clase Object, que sirve como raíz para la jerarquía de clases de Java, o la clase System que ya hemos utilizado en algunos ejemplos y que representa al sistema en el que se está ejecutando la aplicación. También podemos encontrar en este paquete las clases que "envuelven" los tipos primitivos de datos. Lo que proporciona una serie de métodos para cada tipo de dato de utilidad, como por ejemplo las conversiones de datos. |
| java.util | Biblioteca de clases de utilidad general para el programador. Este paquete contiene por ejemplo la clase Scanner utilizada para la entrada por teclado de diferentes tipos de datos, la clase Date, para el tratamiento de fechas, etc. |
| java.math | Contiene herramientas para manipulaciones matemáticas. |
| java.awt | Incluye las clases relacionadas con la construcción de interfaces de usuario, es decir, las que nos permiten construir ventanas, cajas de texto, botones, etc. Algunas de las clases que podemos encontrar en este paquete son Button, TextField, Frame, Label, etc. |
| java.swing | Contiene otro conjunto de clases para la construcción de interfaces avanzadas de usuario. Los componentes que se engloban dentro de este paquete se denominan componentes Swing, y suponen una alternativa mucho más potente que AWT para construir interfaces de usuario. |
| java.net | Conjunto de clases para la programación en la red local e Internet. |
| java.sql | Contiene las clases necesarias para programar en Java el acceso a las bases de datos. |
| java.security | Biblioteca de clases para implementar mecanismos de seguridad. |
Como se puede comprobar Java ofrece una completa jerarquía de clases organizadas a través de paquetes.
Cadenas de caracteres. La clase String¶
Cadenas de caracteres¶
Hasta ahora hemos utilizado literales de cadenas de caracteres que, como sabemos, se ponen entre comillas dobles, como en la siguiente expresión
1 | |
Para almacenar cadenas de caracteres en variables se utiliza la clase String. String se encuentra definida en el paquete java.lang. Recordemos que no es necesario importar este paquete para utilizar sus clases.
La forma de String es la siguiente:
1 | |
Ejemplo:
1 2 | |
Sin embargo, debido a que es una clase que se utiliza ampliamente en los programas, Java permite una forma abreviada de crear objetos String:
1 | |
Ejemplo:
1 2 | |
Leer cadenas desde teclado¶
Clase Scanner¶
Para leer cadenas de caracteres desde teclado podemos utilizar la clase Scanner. Ésta dispone de dos métodos para leer cadenas:
next(): Lee desde la entrada estándar (teclado) una secuencia de caracteres hasta encontrar un delimitador (un espacio). Devuelve unString.nextLine(): Lee desde la entrada estándar (teclado) una secuencia de caracteres hasta encontrar un salto de línea. Devuelve unString.
Ejemplo:
1 2 3 4 5 | |
Ejemplos de la UD01 pero utilizando Scanner (compatible con los IDE's)¶
A continuación vamos a ver los mismos ejemplos de la UD01, pero utilizando la clase Scanner que si es compatible con los IDE's. Para poder usar la clase Scanner necesitamos importar el paquete: java.util.Scanner.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
La clase String¶
Además de permitir almacenar cadenas de caracteres, String tiene métodos para realizar cálculos u operaciones con ellas.
Así por ejemplo, la clase tiene un método toUpperCase() que devuelve el String convertido a mayúsculas. El siguiente ejemplo ilustra su uso:
1 2 | |
Accede a la documentación en línea de Java y estudia los siguientes métodos de la clase:
charAtindexOfsubStringtoLowerCasetrim
printf o format¶
El método printf() o format() (son sinónimos) utilizan unos códigos de conversión para indicar si el contenido a mostrar de qué tipo es. Estos códigos se caracterizan porque llevan delante el símbolo %, algunos de ellos son:
%c: Escribe un carácter.%s: Escribe una cadena de texto.%d: Escribe un entero.%f: Escribe un número en punto flotante.%e: Escribe un número en punto flotante en notación científica.
Por ejemplo, si queremos escribir el número float 12345.1684 con el punto de los miles y sólo dos cifras decimales la orden sería:
1 | |
Esta orden mostraría el número 12.345,17 por pantalla.
Otro ejemplo seria:
1 2 3 | |
Puedes investigar más sobre printf o format en este enlace
Salida de error¶
La salida de error está representada por el objeto System.err. No parece muy útil utilizar out y err si su destino es la misma pantalla, o al menos en el caso de la consola del sistema donde las dos salidas son representadas con el mismo color y no notamos diferencia alguna. En cambio en la consola de varios entornos integrados de desarrollo como NetBeans o Eclipse la salida de err se ve en un color diferente. Teniendo el siguiente código:
1 2 | |
Tanto NetBeans, Eclipse como IntelliJ Idea mostraran el mensaje err en color rojo.
Ejemplo UD02¶
Clase Pajaro¶
Vamos a ilustrar mediante un ejemplo la utilización de objetos y métodos, así como el uso de parámetros y el operador this. Aunque la creación de clases la veremos en las siguientes unidades, en este ejercicio creamos una pequeña clase para que podamos instanciar el objeto con el que vamos a trabajar.
Las clases se suelen representar como un rectángulo, y dentro de él se sitúan los atributos y los métodos de dicha clase.
En la imagen, la clase Pajaro está compuesta por tres atributos, uno de ellos el nombre y otros dos que indican la posición del ave, posX y posY. Tiene tres métodos constructores y un método volar(). Como sabemos, los métodos constructores reciben el mismo nombre de la clase, y puede haber varios para una misma clase, dentro de ella se diferencian unos de otros por los parámetros que utilizan.
Enunciado:
Dada una clase principal llamada Pajaro, se definen los atributos y métodos que aparecen en la imagen. Los métodos realizan las siguientes acciones:
classDiagram
Pajaro
class Pajaro{
-String nombre
-int posX
-int posY
+Pajaro()
+Pajaro(String nombre)
+Pajaro(String nombre, int posX, int posY)
+double volar(int posX, int posY)
} Pajaro(). Constructor por defecto. En este caso, el constructor por defecto no contiene ninguna instrucción, ya que Java inicializa de forma automática las variables miembro, si no le damos ningún valor.Pajaro(String nombre). Constructor que recibe como argumentos una cadena de texto (el nombre del pájaro).Pajaro(String nombre, int posX, int posY). Constructor que recibe como argumentos una cadena de texto y dos enteros para inicializar el valor de los atributos.double volar(int posX, int posY). Método que recibe como argumentos dos enteros:posXyposY, y devuelve un valor de tipodoublecomo resultado, usando la palabra clavereturn. El valor devuelto es el resultado de aplicar un desplazamiento de acuerdo con la siguiente fórmula:
Diseña un programa que utilice la clase Pajaro, cree una instancia de dicha clase y ejecute sus métodos.
Lo primero que debemos hacer es crear la clase Pajaro, con sus métodos y atributos. De acuerdo con los datos que tenemos, el código de la clase sería el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
Debemos tener en cuenta que se trata de una clase principal, lo cual quiere decir que debe contener un método main() dentro de ella. En el método main() vamos a situar el código de nuestro programa. El ejercicio dice que tenemos que crear una instancia de la clase y ejecutar sus métodos, entre los que están el constructor y el método volar().
También es conveniente imprimir el resultado de ejecutar el método volar(). Por tanto, lo que haría el programa sería:
- Crear un objeto de la clase e inicializarlo.
- Invocar al método volar.
- Imprimir por pantalla la distancia recorrida.
Para inicializar el objeto utilizaremos el constructor con parámetros, después ejecutaremos el método volar() del objeto creado y finalmente imprimiremos el valor que nos devuelve el método.
Luego crearemos otro pajaro2 usando el constructor por defecto (sin parámetros). Le asignaremos el nombre y la posición manualmente, y calcularemos su desplazamiento llamando al método, pero usando los atributos del objeto (pajaro2.posX y pajaro2.posY) en lugar de constantes. El código del método main() quedaría como sigue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Si ejecutamos nuestro programa el resultado sería el siguiente:
1 2 | |
Clase String¶
Ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |