¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Java
  3. Programación orientada a objetos
Extrait - Java Los fundamentos del lenguaje (con ejercicios corregidos)
Extractos del libro
Java Los fundamentos del lenguaje (con ejercicios corregidos) Volver a la página de compra del libro

Programación orientada a objetos

Introducción

Con Java, la noción de objeto es omnipresente y precisa un mínimo de aprendizaje. En primer lugar, nos centraremos en los principios de la programación orientada a objetos y en su vocabulario asociado, para pasar luego a ponerlo todo en práctica con Java.

En un lenguaje procedural clásico, el funcionamiento de una aplicación está regido por una sucesión de llamadas a diferentes procedimientos y funciones disponibles en el código. Estos procedimientos y funciones son los encargados de procesar los datos de la aplicación representados por las variables de esta última. No existe relación alguna entre los datos y el código que los manipula. Por el contrario, en un lenguaje orientado a objetos, lo que se intenta es agrupar el código. A esta agrupación se le llama clase. Por lo tanto, una aplicación desarrollada con un lenguaje orientado a objetos está formada por numerosas clases que representan los diferentes elementos procesados por la aplicación. Las clases describirán las características de cada uno de los elementos. El ensamblado de estos elementos va a permitir el funcionamiento de la aplicación. 

Este principio se utiliza ampliamente en otras disciplinas, además de la informática. En la industria automovilística, por ejemplo, seguramente no existe...

Puesta en práctica con Java

1. Contexto

En el resto del capítulo, vamos a trabajar con la clase Persona y sus subclases. La representación UML (Unified Modeling Language) simplificada de esta herencia de clase es la siguiente.

images/cap3_1.png

UML es un lenguaje gráfico destinado a la representación de los conceptos de programación orientada a objetos. Para obtener más información sobre este lenguaje, puede consultar el manual UML 2.5 en la colección Recursos Informáticos de Ediciones ENI.

2. Creación de una clase

La creación de una clase consiste en su declaración y la de todos los elementos que la componen.

a. Declaración de la clase

La declaración de una clase se lleva a cabo utilizando la palabra clave class seguida del nombre de la clase y de un bloque de código delimitado por los caracteres { y } (llaves). En este bloque de código se encuentran las declaraciones de variables, que serán los campos de la clase, y las funciones, que serán los métodos de la clase. Se pueden añadir varias palabras clave para modificar las características de la clase. Por lo tanto, la sintaxis de la declaración de una clase es la siguiente.

[modificadores] class NombreDeLaClase 
           [extends NombreDeLaClaseBasica]  
           [implements NombreDeInterfaz1,NombreDeInterfaz2,...] 
{  
    Código de la clase  
} 

Los signos [ y ] (corchetes) se utilizan para indicar qué elemento es opcional. No se deben utilizar en el código de declaración de una clase.

Los modificadores permiten determinar la visibilidad de la clase y la manera de utilizarla. A continuación presentamos la lista de los modificadores disponibles:

public: indica que la clase puede ser utilizada por cualquier otra clase. Sin este modificador, la clase solo podrán utilizarla clases que formen parte del mismo package. Para más información sobre los paquetes, vaya a la sección correspondiente, un poco más adelante en este capítulo.

abstract: indica que la clase es abstracta y no puede ser instanciada. Solo se la puede utilizar como clase básica en una relación de herencia. En este tipo...

Los paquetes

1. Presentación

La meta principal de los paquetes es organizar y ordenar las clases y las interfaces de una aplicación. El principio es el mismo que en la vida corriente. Si disponemos de un gran armario en casa, es obvio que la instalación de estanterías en este armario facilitará la organización y la búsqueda de los objetos guardados en relación con un almacenamiento en desorden.

La organización de las clases en paquetes conlleva las ventajas siguientes:

  • Facilidad para encontrar y utilizar de nuevo un elemento.

  • Limitación de los riesgos de conflictos de nombres.

  • Creación de una nueva visibilidad (la visibilidad package) además de las estándares (private, protected, public). Cuando un elemento (una clase, un campo, un método) no tiene modificadores de visibilidad, entonces este elemento solo es visible por los elementos presentes en el mismo paquete. Hay una sutileza para los elementos protegidos (campos, métodos). Por supuesto, son accesibles en las clases derivadas, pero también en las clases del mismo paquete.

2. Creación de un paquete

Lo primero que hay que hacer cuando se quiere crear un paquete es darle un nombre. Hay que elegirlo con cuidado para permitir que el paquete cumpla totalmente con su papel. Debe ser único y representativo de los elementos almacenados en su interior.

Para asegurar la unicidad del nombre de un paquete, por convención se utiliza el nombre de dominio de la empresa invirtiendo el orden de los elementos como primera parte para el nombre del paquete.

Por ejemplo, si el nombre del dominio es eni.es, la primera parte del nombre del paquete será es.eni. Si el nombre del dominio contiene caracteres prohibidos para los nombres de paquetes, se sustituyen por el carácter _ (guión bajo). De este modo, para el nombre de dominio eni-escuela.es, la primera parte del nombre del paquete será es.eni_escuela. Esta primera parte del nombre permite garantizar la unicidad de los elementos respecto al exterior de la empresa. La parte siguiente del nombre del paquete asegurará la unicidad de los elementos...

Los módulos

1. Instalación

Al crear un proyecto de Java con Eclipse, aparece la siguiente ventana para solicitar la creación de un archivo llamado module-info.java:

images/cap3_pag92.png

Este paso está vinculado a la aparición de la noción de módulo con Java 9. Haga clic en Create y se crea un archivo module-info.java en el directorio raíz, que contiene las fuentes. Su contenido es el siguiente:

module Proyecto_JavaSE_Cap3_Modulos {   
} 

2. Presentación

Desde Java 9, la API de Java se ha modularizado. El objetivo es múltiple. La principal ventaja de la modularización de la API es la ganancia en el rendimiento durante la ejecución del programa. De hecho, la modularización permite que la máquina virtual cargue solo los módulos necesarios para el correcto funcionamiento de los programas que ejecuta.

Esto puede parecer superfluo con la capacidad de cálculo de las máquinas actuales, pero, si miramos el Internet de las cosas (IOT - Internet Of Things), esto tiene sentido.

Otros intereses que se pueden identificar son:

  • Una plataforma modular es más fácil de mantener y, por lo tanto, escalable.

  • Gestión más precisa de los elementos disponibles. De hecho, hasta ahora, tan pronto como era necesaria una clase más allá del paquete en el que se declaraba, era preciso declararla pública. La consecuencia fue que estaba...

La gestión de los errores

¡La vida de un desarrollador no es del todo fácil! Los errores son una de las fuentes principales de estrés. De hecho, si nos fijamos bien, podemos clasificar estos errores que nos arruinan la vida en tres categorías. Veremos cada una de ellas, así como las soluciones existentes para resolverlos.

1. Los diferentes tipos de error

a. Los errores de sintaxis

Este tipo de errores se produce en tiempo de compilación cuando el desarrollador comete un error tipográfico. Son habituales con las herramientas de desarrollo, en las cuales el editor de código y el compilador son dos entidades separadas, y menos frecuentes en entornos de desarrollo integrado (Eclipse, NetBeans, Jbuilder…). La mayoría de estos entornos proporcionan un análisis sintáctico al mismo tiempo que se escribe el código.

Si se detecta un error de sintaxis, el entorno propone soluciones que permiten corregir este error.

images/03RI34.png

Además, las «faltas de ortografía» en los nombres de campos o métodos se eliminan fácilmente mediante las funcionalidades disponibles en estos entornos.

images/cap3_29.png

b. Los errores de ejecución

Estos errores aparecen después de la compilación, cuando lanzamos la ejecución de la aplicación. La sintaxis del código es correcta, pero el entorno de la aplicación no permite ejecutar alguna instrucción empleada en la aplicación. Esto sucede, por ejemplo, cuando intenta abrir un archivo que no existe en el disco de su máquina. Sin duda, obtendrá un mensaje de este tipo.

images/cap3_notFound.png

¡No es un mensaje muy simpático para el usuario!

Afortunadamente, Java permite que nos recuperemos de este tipo de errores y evita, así, la visualización de este mensaje preocupante. Vamos a detallar esto más adelante en este capítulo.

c. Los errores de lógica

Son los peores enemigos de los desarrolladores. Todo se compila sin problema, todo se ejecuta sin errores, y sin embargo ¡¡¡no funciona como estaba previsto!!! 

En este caso, hay que revisar la lógica de funcionamiento de la aplicación. Las herramientas de depuración permiten seguir el desarrollo de la aplicación, situar puntos de interrupción, visualizar el contenido de las variables, etc.

Estas herramientas no sustituyen...

Los genéricos

1. Presentación

Los tipos genéricos son elementos de un programa que se adaptan automáticamente para lograr la misma funcionalidad sobre diferentes tipos de datos. Cuando crea un elemento genérico, no necesita diseñar una versión diferente para cada tipo de datos con los que desea lograr la funcionalidad. Para hacer una analogía con un objeto actual, tomaremos el ejemplo de un destornillador. Dependiendo del tipo de tornillo que tenga que usar, puede tomar un destornillador específico para este tipo de tornillo (plano, en cruz, etc.). Una técnica utilizada frecuentemente por un técnico experimentado es adquirir un destornillador universal con múltiples puntas. Dependiendo del tipo de tornillo, elige la que mejor se adapte. El resultado final es el mismo que si tuviera una variedad de destornilladores diferentes: puede atornillar y desatornillar. 

Cuando usa un tipo genérico, lo configura con un tipo de datos. Esto permite que el código se adapte automáticamente y realice la misma acción independientemente del tipo de datos. Una alternativa podría ser el uso del tipo universal Object. El uso de tipos genéricos tiene varias ventajas respecto a esta solución:

  • Requiere la verificación de los tipos de datos en el momento de la compilación y evita las verificaciones inevitables que deben hacerse manualmente con el uso del tipo Object.

  • Evita las operaciones de conversión del tipo Object a un tipo más específico y viceversa.

  • La escritura del código se facilita en ciertos entornos de desarrollo, con la visualización automática de todos los miembros disponibles para un tipo particular de datos.

  • Promueve la escritura de algoritmos que son independientes de los tipos de datos.

Sin embargo, los tipos genéricos pueden imponer ciertas restricciones sobre el tipo de datos utilizados. Por ejemplo, pueden obligar a que el tipo utilizado implemente una o más interfaces o derive de una clase particular. Es importante comprender algunos términos utilizados con los genéricos.

  • Tipo genérico: esta es la definición de una clase, interfaz o función para la que se especifica al menos un tipo de datos durante su declaración.

  • Tipo de parámetro: este es el espacio reservado para el tipo...

Las colecciones

1. Presentación

Las aplicaciones necesitan, con frecuencia, manipular una gran cantidad de información. Existen numerosas estructuras que facilitan la gestión de dicha información. Se agrupan bajo el término «colección». Como ocurre en la vida, existen distintos tipos de colecciones y de coleccionadores. Puede haber personas que lo guardan todo pero que no tienen una organización particular para clasificarlo; otras que se especializan en la colección de ciertos tipos de objetos, o incluso los maníacos que toman todas las precauciones posibles para poder encontrar rápidamente un objeto…

El lenguaje Java proporciona distintas clases que permiten implementar varios modelos de gestión.

La primera solución para gestionar un conjunto de elementos consiste en utilizar tablas. Esta solución se ha descrito en la sección Los arrays del capítulo Fundamentos del lenguaje. Si bien son sencillas de implementar, esta solución no es demasiado flexible. Su principal defecto es el carácter fijo del tamaño de la tabla. Si no hay espacio para almacenar elementos suplementarios, hay que crear una nueva tabla, más grande, y transferirle el contenido de la tabla anterior. Esta solución, muy pesada de implementar, consume además muchos recursos. 

El lenguaje Java proporciona una vasta paleta de interfaces y de clases que permiten gestionar fácilmente conjuntos de elementos. Las interfaces describen las funcionalidades disponibles, mientras que las clases implementan y proveen realmente dichas funcionalidades. En función del modelo de gestión que se desee tener sobre los elementos, se utilizará la clase mejor adaptada. No obstante, las mismas funcionalidades básicas deben estar accesibles sea cual sea el modelo de gestión. Para asegurar la presencia de estas funcionalidades, indispensables en todas las clases, se han agrupado en la interfaz Collection, que se utiliza como interfaz básica.

La jerarquía de interfaces se presenta en el siguiente diagrama.

images/03RI49.png

Todas estas interfaces son genéricas, con el objetivo de gestionar conjuntos compuestos por no importa qué tipos de elementos, evitando así las molestas operaciones de cambio de tipo.

  • La interfaz Collection es la interfaz básica...

Ejercicios

1. Ejercicio 1

Crear una clase que represente un artículo de una tienda de venta por correspondencia. Un artículo se caracteriza por su referencia, su nombre y su precio. Crear, a continuación, un método main que permita probar el correcto funcionamiento de la clase anterior.

2. Ejercicio 2

Agregar las dos clases Libro y Dvd que heredan de la clase Articulo.

Un libro posee un número ISBN, contiene cierto número de páginas y lo ha escrito un autor; un DVD tiene cierta duración y lo ha producido un realizador.

Agregar los atributos necesarios a las clases Libro y Dvd para obtener el nombre del autor o del realizador. Probar, a continuación, el funcionamiento de estas dos nuevas clases.

3. Ejercicio 3

Modificar las clases Libro y Dvd para tener disponible información relativa al autor o el realizador:

  • su apellido,

  • su nombre,

  • su fecha de nacimiento.

Pista: los autores y realizadores son personas.

4. Ejercicio 4

Modificar el código anterior para poder obtener rápidamente la lista de artículos relacionados con un autor o un realizador.

Correcciones

1. Ejercicio 1

La clase Articulo es relativamente simple. Las líneas 5 a 7 contienen la declaración de atributos que representan la información que vamos a almacenar en las instancias de la clase. Se declaran con la visibilidad private para garantizar que solo el código de la clase pueda acceder a ellas. A continuación se declaran los constructores (líneas 9 a 29). Las distintas versiones permiten crear instancias en función de la información disponible. Para evitar la duplicación de código, los constructores pueden invocarse mutuamente (líneas 16, 21, 27).

Si bien es posible utilizar directamente los atributos en los constructores, es preferible usar los métodos setXXX para acceder a ellos, de cara a aprovechar las eventuales verificaciones realizadas sobre los valores que se aplican a dichos atributos.

Para hacer que los atributos sean accesibles desde el exterior de la clase, cada uno debe disponer de los métodos getXXX y setXXX, que permiten obtener el valor del atributo o asignarle uno nuevo.

El método toString permite obtener una representación en forma de cadena de caracteres de la instancia de la clase.

El método main crea, a continuación, dos instancias de la clase Articulo, bien utilizando el constructor por defecto e inicializando a continuación los atributos uno a uno (líneas 9 a 12), o bien utilizando el constructor correspondiente a la lista de atributos disponibles (línea 14). Las dos instancias se muestran, a continuación, por la llamada de la función prueba, que permite definir el formato de representación o bien utilizar el método toString.

En este caso, el formato lo impone la clase Articulo.

/********************* Articulo **********************/   
1. package es.eni.editions.ejercicio1;   
2.    
3. public class Articulo    
4. {   
5.     private int referencia;   
6.     private String designacion;   
7.     private double precio;   
8.        
9.     public Articulo()   
10.       {   
11.            super();   ...