Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Introducción a la programación orientada a objetos La orientación a objetos es una forma natural de pensar en relación con el mundo y de escribir programas de computación. Mire a su alrededor. Por todas partes: ¡objetos! Personas, animales, plantas, automóviles, aviones, edificios, cortadoras de pastos, computadoras y demás. Cada una de ellos tiene ciertas características y se comporta de una manera determinada. Si los conocemos, es porque tenemos el concepto de lo que son. Conceptos persona, objetos persona. Los seres humanos pensamos en términos de objetos. Tenemos la capacidad maravillosa de la abstracción, que nos permite ver una imagen en pantalla como personas, aviones, árboles y montañas, en vez de puntos individuales de color. Todos estos objetos tienen algunas cosas en común. Todos tienen atributos, como tamaño, forma, color, peso y demás. Todos ellos exhiben algún comportamiento. Un automóvil acelera, frena, gira, etcétera. El objeto persona habla, ríe, estudia, baila, canta ... Los seres humanos aprenden lo relacionado con los objetos estudiando sus atributos y observando su comportamiento. Objetos diferentes pueden tener muchos atributos iguales y mostrar comportamientos similares. Se pueden hacer comparaciones, por ejemplo, entre bebes y adultos, entre personas y chimpancés. Automóviles, camiones, pequeños carros rojos y patines tienen mucho en común. La programación orientada a objetos (POO) hace modelos de los objetos del mundo real mediante sus contrapartes en software. Aprovecha las relaciones de clase, donde objetos de una cierta clase, como la clase de vehículos, tienen las mismas características. Aprovecha las relaciones de herencia, donde clases recién creadas de objetos se derivan heredando características de clases existentes, pero también poseyendo características propias de ellos mismas. Los bebes tienen muchas características de sus padres, pero ocasionalmente padres de baja estatura tienen hijos altos. La programación orientada a objetos nos proporciona una forma más natural e intuitiva de observar el proceso de programación, es decir haciendo modelos de objetos del mundo real, de sus atributos y de sus comportamientos. POO también hace modelos de la comunicación entre los objetos. De la misma forma que las personas se envían mensajes uno al otro los objetos también se comunican mediante mensajes. La POO encapsula datos (atributos) y funciones (comportamiento) en paquetes llamados objetos; los datos y las funciones de un objeto están muy unidos. Los objetos tienen la propiedad de ocultar la información. Esto significa que aunque los objetos puedan saber cómo comunicarse unos con otros mediante interfaces bien definidas, a los objetos por lo regular no se les está permitido saber cómo funcionan otros objetos. Los detalles de puesta en práctica quedan ocultos dentro de los objetos mismos. (Casi estamos diciendo que existe entre ellos el respeto a la intimidad...) A esto se le llama Encapsulamiento. ¿Qué es la Programación Orientada a Objetos? Es una técnica o estilo de programación que utiliza objetos como bloque esencial de construcción. Los programas se organizan como colecciones de objetos que colaboran entre sí enviándose mensajes. Solo se dispone de “objetos que colaboran entre sí”. Por lo tanto un programa orientado a objetos viene definido por la ecuación: Página 1 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Objetos + Mensajes = Programa Componentes básicos de la POO Objetos Es el elemento fundamental de la programación orientada a objetos. Es una entidad que posee atributos y métodos, los atributos definen el estado de mismo y los métodos definen su comportamiento. Cada objeto forma parte de una organización, no es un ente aislado, sino que forma parte de una organización jerárquica o de otro tipo. ¿Qué son objetos en POO? La respuesta es cualquier entidad del mundo real que se pueda imaginar: • • • • Objetos físicos ✓ Automóviles en una simulación de tráfico. ✓ Aviones en un sistema de control de tráfico aéreo. ✓ Componentes electrónicos en un programa de diseño de circuitos. ✓ Animales mamíferos. Elementos de interfaces gráficos de usuarios ✓ Ventanas. ✓ Objetos gráficos (líneas, rectángulos, círculos). ✓ Menús. Estructuras de datos ✓ Vectores. ✓ Listas. ✓ Arboles binarios. Tipos de datos definidos por el usuario ✓ Números complejos. ✓ Hora del día. ✓ Puntos de un plano. Como ejemplo de objeto, podemos decir que una ventana es un objeto que puede tener como atributos: nombre, alto, ancho, etc. y como métodos: crear la ventana, abrir la ventana, cerrar la ventana, mover la ventana, etc. Página 2 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Métodos Podemos definir un método como un programa procedimental escrito en cualquier lenguaje, que está asociado a un objeto determinado y cuya ejecución sólo puede desencadenarse a través de un mensaje recibido por éste o por sus descendientes. Mensajes Un mensaje es simplemente una petición de un objeto a otro para que éste se comporte de una determinada manera, ejecutando uno de sus métodos. La técnica de enviar mensajes se conoce como paso de mensajes. Los mensajes relacionan unos objetos con otros y con el mundo exterior. La figura 1. Representa un objeto A (emisor) que envía un mensaje Test al objeto B (receptor). Usando el ejemplo anterior de ventana, podríamos decir que algún objeto de Windows encargado de ejecutar aplicaciones, por ejemplo, envía un mensaje a nuestra ventana para que se abra. En este ejemplo el objeto emisor es un objeto de Windows y el objeto receptor es nuestra ventana, el mensaje es la petición de abrir la ventana y la respuesta es la ejecución del método abrir ventana. Página 3 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Clases Una clase es simplemente un modelo que se utiliza para describir uno o más objetos el mismo tipo. Cada vez que se construye un objeto de una clase, se crea una instancia de esa clase. Por consiguiente, los objetos son instancias de clases. En general, los términos objetos e instancias de una clase se pueden utilizar indistintamente. Una clase puede tener muchas instancias y cada una es un objeto independiente. Siguiendo con el ejemplo de ventana, el modelo o clase para todas las ventanas sería: Objetos de tipo ventana: Características de la POO ✓ Abstracción: La abstracción se define como la “extracción de las propiedades esenciales de un concepto”. Permite no preocuparse de los detalles no esenciales. Implica la identificación de los atributos y métodos de un objeto. Es la capacidad para encapsular y aislar la información de diseño y ejecución. ✓ Encapsulamiento: Toda la información relacionada con un objeto determinado está agrupada de alguna manera, pero el objeto en sí es como una caja negra cuya estructura interna permanece oculta, tanto para el usuario como para otros objetos diferentes, aunque formen parte de la misma jerarquía. La información contenida en el objeto será accesible sólo a través de la ejecución de los métodos adecuados. ✓ Herencia: La herencia es la propiedad que permite a los objetos construirse a partir de otros objetos. El concepto de herencia está presente en nuestras vidas diarias donde las clases se dividen en subclases. Página 4 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Así por ejemplo, las clases de animales se dividen en mamíferos, anfibios, insectos, pájaros, etc. La clase de vehículos se divide en automóviles, autobuses, camiones, motocicletas, etc. ✓ Polimorfismo: En un sentido literal, polimorfismo significa cualidad de tener más de una forma. En el contexto de POO, el polimorfismo se refiere al hecho que una misma operación puede tener diferente comportamiento en diferentes objetos. En otras palabras, diferentes objetos reaccionan al mismo mensaje de modo diferente. Por ejemplo, consideremos la operación sumar. En un lenguaje de programación el operador + representa la suma de dos números (x + y) de diferentes tipos: enteros, coma flotante, ... Además se puede definir la operación de sumar dos cadenas : concatenación mediante el operador suma. De modo similar, supongamos un número de figuras geométricas que responden todas al mensaje, dibujar. Cada objeto reacciona a este mensaje visualizando su figura en la pantalla de visualización. Obviamente, e l mecanismo real para visualizar los objetos difiere de una figura a otra, pero todas las figuras realizan esta tarea en respuesta al mismo mensaje. Otro ejemplo podría ser el siguiente: un usuario de un sistema tiene que imprimir un listado de sus clientes, el puede elegir imprimirlo en el monitor, en la impresora, en un archivo en disco o en una terminal remota. De esta forma el mensaje es imprimir el listado pero la respuesta la dará el objeto que el usuario desee, el monitor, la impresora, el archivo o la terminal remota. Cada uno responderá al mensaje imprimirListado() , claro que las acciones que se ejecuten(respuesta) monitor. imprimirListado() son distintas a las de archivo. imprimirListado() Como vimos anteriormente, el análisis de un problema es el paso más importante para resolver un problema, existen varias formas de plantear las soluciones; Si usaremos lenguajes de la llamada Vertiente Imperativa(El programador detalla minuciosamente las acciones que la computadora debe realizar) disponemos de dos paradigmas: Programación Estructurada y Orientada a Objetos. El primero se está dejando de usar, sin embargo aún quedan muchos sistemas resueltos bajo esta óptica que hay que mantener o actualizar. Y el segundo es una evolución del primero, es el que nosotros vamos a usar ya que es la actual realidad del mercado, es la que mejor rendimiento tiene, se está usando desde hace bastantes años y es la que tiene mayor soporte en cuanto a tecnologías de análisis, diseño y desarrollo de software. A continuación una breve comparación de estos dos paradigmas. Nos servirá para entender mejor como tendremos que resolver los problemas en el paradigma que adoptamos. Programación estructurada La programación estructurada tiende a ser orientada a la acción. Los programadores se concentran en escribir funciones, que son grupos de acciones que ejecutan alguna tarea común y que se agrupan para formar programas. La unidad fundamental de la programación es la función. Es cierto que los datos son importantes, pero la óptica es que los datos son materia prima para las acciones que las funciones ejecutan. Semánticamente las acciones son verbos. Los verbos en una especificación de sistema ayudan al programador a determinar el conjunto de funciones que juntas funcionarán para ponerlo en marcha. Página 5 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Programación orientada a objetos La programación orientada a objetos, como inicialmente dijimos, aprovecha la capacidad humana de conocer conceptos. Los humanos tenemos conocimiento concreto de conceptos generales, esto nos posibilitan interactuar con los demás. Quienes sean versados o especialistas en determinadas disciplinas, conocen conceptos específicos, no tan comunes. Pueden interactuar fácil y eficientemente con sus pares, no tanto con quienes no conocen, o tienen una idea vaga del significado de esos conceptos específicos. En POO, el concepto se implementa en clases (class). La clase es la unidad básica de programación. Es una unidad que contiene los atributos y todos los métodos necesarios a su tratamiento. Entonces cada clase contiene datos junto con un conjunto de métodos que manipula dichos datos. Los componentes de datos de una clase se llaman datos miembros o atributos. El comportamiento de la clase se implementa mediante funciones miembro o métodos. Una instancia, cada caso particular de una clase es un objeto. El foco de atención está sobre los objetos, en lugar de estarlo sobre las funciones. Son los sustantivos que en una especificación de sistema ayudan al programador a determinar el conjunto de clases, a partir de las cuales serán creados los objetos que funcionarán conjuntamente para poner en práctica el sistema. Es muy importante que a la hora de analizar un problema utilicemos sustantivos y no verbos. A continuación, resolveremos un problema bajo la óptica orientada a objetos: Enunciado: Dado el valor de los tres lados de un triángulo, calcular el perímetro. • Interpretación del problema (Análisis) En este caso tan sencillo es evidente que el dato de entrada serán los lados y el resultado el perímetro. • Abstracción ✓ Identificar el objeto: identificar la entidad que engloba al problema, en nuestro ejemplo es el triángulo. ✓ Identificar sus atributos: podemos decir que todo triángulo tiene como datos esenciales los tres lados, además, nuestro problema en particular necesitará el valor del perímetro, que es un datos calculable a partir de los tres lados y que puede figurar como atributo o no dependiendo si se quiere guardar su estado en el objeto. Como nuestro enunciado no nos restringe la forma de implementarlo vamos a definir como atributos los tres lados y el perímetro. • Estrategia: Identificar sus métodos: los métodos a elegir siempre dependerán de las operaciones que debemos realizar con los datos para obtener los resultados y exhibirlos, entonces podemos enumerar: ✓ Inicializar los atributos: Inicializar en 0, por ejemplo, los lados y el perímetro. ✓ Ingresar los lados: Se ingresa el valor de cada lado. ✓ Mostrar los lados: Mostrar el valor de los lados. Página 6 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II ✓ Calcular el perímetro: formula que devuelve el perímetro del triángulo. ✓ Mostrar el perímetro: Mostrar el valor del perímetro. Graficando el resultado: Lo que hasta ahora hemos visto es una introducción, pero es poco lo que podemos hacer sin herramientas, es hora de comenzar a conocerlas. Suponemos que UD tiene acceso a una computadora, la necesitará. Y en ella, además del software de uso habitual necesitaremos del lenguaje Java, que usaremos para codificar nuestros programas, y de un entorno de desarrollo, un IDE (Integrated Development Environment). Hablemos de ello. ¿Qué es JAVA? Java es un lenguaje de programación de alto nivel con el que se pueden escribir tanto programas convencionales como para Internet. Una de las ventajas significativas de Java sobre otros lenguajes de programación es que es independiente de la plataforma, tanto en código fuente como en binario. Esto quiere decir que el código producido por el compilador Java puede transportarse a cualquier plataforma (Intel, Sparc, Motorola, etc.) que tenga instalada una máquina virtual Java y ejecutarse. Pensando en Internet esta característica es crucial ya que esta red conecta computadoras muy distintas. En cambio, C++, por ejemplo, es independiente de la plataforma solo en código fuente, lo cual significa que cada plataforma diferente debe proporcionar el compilador adecuado para obtener el código máquina que tiene que ejecutarse. Según lo expuesto, Java incluye dos elementos: un compilador y un intérprete. El compilador produce un código de bytes que se almacena en un fichero para ser ejecutado por el intérprete Java denominado máquina virtual de Java. Página 7 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Los códigos de bytes de Java son un conjunto de instrucciones correspondientes a un lenguaje máquina que no es específico de ningún procesador, sino de la máquina virtual de Java. ¿Dónde se consigue esta máquina virtual? Hoy en día casi todas las compañías de sistemas operativos y de navegadores han implementado máquinas virtuales según las especificaciones publicadas por Sun Microsystems, propietario de Java, para que sean compatibles con el lenguaje Java. Para las aplicaciones de Internet (denominadas applets) la máquina virtual está incluida en el navegador y para las aplicaciones Java convencionales, puede venir con el sistema operativo, con el paquete Java, o bien puede obtenerla a través de Internet. ¿Por qué no se diseñó Java para que fuera un intérprete más entre los que hay en el mercado? La respuesta es porque la interpretación, si bien es cierto que proporciona independencia de la máquina, conlleva también un problema grave, y es la perdida de velocidad en la ejecución del programa. Por esta razón la solución fue diseñar un compilador que produjera un lenguaje que pudiera ser interpretado a velocidades, si no iguales, si cercanas a la de los programas nativos (programas en código máquina propio de cada computadora), logro conseguido mediante la máquina virtual de Java. Con todo, las aplicaciones todavía adolecen de una falta de rendimiento apreciable. Este es uno de los problemas que siempre se ha achacado a Java. Afortunadamente, la diferencia de rendimiento con respecto a aplicaciones equivalentes escritas en código máquina nativo ha ido disminuyendo hasta márgenes muy reducidos gracias a la utilización de compiladores JIT (Just In Time - compilación al instante). Un compilador JIT interacciona con la máquina virtual para convertir el código de bytes en código máquina nativo. Como consecuencia, se mejora la velocidad durante la ejecución. Sun sigue trabajando sobre este objetivo y prueba de ello son los resultados que se están obteniendo con el nuevo y potente motor de ejecución HotSpot (HotSpot Perfomance Engine) que ha diseñado, o por los microprocesadores específicos para la interpretación hardware de código de bytes. Características Hay muchas razones por las que Java es tan popular y útil. Aquí se resumen algunas características importantes: • Orientación a objetos: Java está totalmente orientado a objetos. Esto quiere decir que java trabaja con sus datos como si estos fueran objetos y que tienen interfaces a esos objetos. Soporta tres características de los lenguajes orientados a objetos: encapsulamiento, herencia y polimorfismo. Las plantillas de objetos son llamadas clases y tienen sus propias instancias. No hay funciones sueltas en un programa de Java. Todos los métodos se encuentran dentro de clases. • Simplicidad: la sintaxis de Java es similar a ANSI C y C++ y, por tanto, fácil de aprender; aunque es mucho más simple y pequeño que C++. Elimina encabezados de archivos, preprocesador, aritmética de apuntadores, herencia múltiple, sobrecarga de operadores, struct, union y plantillas. Página 8 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Java incorpora características muy útiles como el garbage collector (recolector de basura). No es necesario preocuparse de liberar memoria, el reciclador se encarga de ello, cuando entra en acción permite liberar bloques de memoria muy grandes, lo que reduce la fragmentación de la memoria. • Robustez: durante la compilación de un programa Java se comprueba la sintaxis y ciertas situaciones que con otros lenguajes compilados no se comprobaban, pudiendo dar lugar a resultados inesperados (variables sin valor inicial, asignaciones entre variables de distinto tipo, etc.). Posteriormente, durante la ejecución se vuelven a realizar otras comprobaciones, por lo que un programa escrito en Java es bastante robusto. • Multiplataforma: Java funciona con las principales plataformas de hardware y sistemas operativos. Java fue diseñado específicamente para ser “Write Once, Run Anywhere” (WORA), es decir, escribir (y compilar) un sola vez en una plataforma y ejecutar en cualquier otra, sin necesidad de tener que modificar el código fuente, ni siquiera de recompilar. En java, los tipos de datos primitivos siempre ocupan lo mismo, independientemente de la plataforma en la que se ejecuten. • Portabilidad: al ser multiplataforma, Java proporciona portabilidad en una amplia gama de procesadores y sistemas operativos. La portabilidad de los programas Java se consigue porque Java es un lenguaje interpretado, aunque también compilado para mejorar el rendimiento de la interpretación; por ello se dice que Java es mitad compilado, mitad interpretado. Cuando un programa Java se compila se genera un código intermedio independiente de la plataforma bytecode (código de bytes). Estos bytecodes serán los que se distribuyan para su ejecución, siendo interpretados por la Máquina Virtual Java (JVM). • Amigable para el trabajo en red: Java tiene elementos integrados para comunicación en red, applets Web, aplicaciones cliente-servidor, además de acceso remoto a bases de datos, métodos y programas. Los applets son pequeños programas escritos en lenguaje Java, diseñados para ser ejecutados desde internet, que podemos colocar en nuestro servidor, junto con el resto de archivos que componen un sitio Web (documentos HTML, ficheros de imagen, sonido, etc.) para lograr múltiples efectos con texto, imágenes, sonidos, etc. • Soporte a GUI: la caja de herramientas para la creación de ventanas abstractas (Abstract Windowing Toolkit) de Java simplifica y facilita la escritura de programas GUI (Graphic User Interface) orientados a eventos con muchos componentes de ventana. • Concurrente: Java permite el desarrollo de programas concurrentes o multi-hilo para conseguir un mejor rendimiento y aprovechamiento del procesador cuando es necesario realizar varias tareas al mismo tiempo. • Distribuido: Java tiene elementos integrados para la comunicación en red, applets Web, aplicaciones cliente-servidor, además de acceso remoto a bases de datos, métodos y programas. Página 9 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Software necesario Para el desarrollo de programas Java se requieren los siguientes programas: • Java Platform Standard Edition (Java SE o J2SE): es necesario disponer del kit de desarrollo de Sun Microsystems (ahora Oracle) para poder desarrollar y ejecutar programas utilizando el lenguaje de programación Java. Está compuesta por: ✓ JRE (Java Runtime Environment): es el entorno de ejecución JAVA, encargado de brindar los servicios necesarios para que un programa escrito en JAVA pueda ser ejecutado. Incluye Máquina Virtual Java (JMV), bibliotecas principales y otros componentes adicionales para ejecutar aplicaciones y applets escritos en Java. ✓ JDK (Java Dvelopment Kit): Un kit de desarrollo de software que se utiliza para escribir applets y aplicaciones con el lenguaje de programación Java. Incluye el JRE, conjunto de clases de API ( Application Programming Interface – Interface de Programación de Aplicaciones ) , compilador Java, Webstart y archivos adicionales necesarios para escribir applets y aplicaciones de Java. • Entorno de Desarrollo Integrado (IDE): Netbeans, Eclipse….: ✓ IDE NetBeans: el entorno de desarrollo integrado (IDE) NetBeans es un entorno gratuito para el desarrollo e programas Java y applets. Además NetBeans también facilita la tarea del desarrollo de aplicaciones empresariales, permitiendo la compilación, empaquetado, distribución y ejecución dentro del mismo entorno. El programa está disponible para las principales plataformas: Microsoft Windows, Linux. Mac OSX, y se puede descargar desde el enlace: https://netbeans.org/ . Antes de instalar el programa es necesario tener instalado el JDK de la plataforma Java SE. Se recomienda descargar NetBeans desde la página de Oracle, pues ya existe un instalador que ya integra tanto el JDK como el IDE de NetBeans. ✓ IDE Eclipse: Eclipse también es un entorno de desarrollo gratuito que da soporte a Java SE, así como a otros lenguajes por medio de plug-ins (C/C++, Phyton, PHP,…). Al igual que NetBeans está disponible para Microsoft Windows, Linux, Mac OS X y se puede descargar desde el enclace: https://eclipse.org/ Realización de un programa en JAVA Para desarrollar un programa hay que seguir los siguientes pasos: 1. 2. 3. 4. Editar el programa Compilarlo Ejecutarlo Depurarlo Página 10 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Cómo crear un programa Un programa puede ser una aplicación o un applet. En esta materia aprenderá principalmente a escribir aplicaciones Java. Empecemos con la creación de una aplicación sencilla: el clásico ejemplo de mostrar un mensaje de saludo. Vamos a estudiar detalladamente este ejemplo: • En primer lugar escribimos el código import javax.swing.JOptionPane ; para poder utilizar la clase JOptionPane y sus métodos dentro de nuestro programa. • El método public static void main ( String [] args ) de la línea 4 es el encargado de ejecutar el programa, es decir, representa el punto inicial de toda aplicación Java. Sin esta instrucción el programa no puede hacer nada. • El compilador por defecto importa el package java.lang, el cual contiene clases útiles de uso general, como la clase String, usada en este ejemplo. A continuación, declaramos la variable nombre que contendrá una cadena de caracteres, en Java este tipo de variables se declaran con la palabra reservada String. • En la línea 5 utilizamos el código JOptionPane.showMessageDialog(null, "Saludo"); para imprimir texto en pantalla, entre comillas dobles. • En la línea 7, se muestra un mensaje para que el usuario ingrese su nombre y almacenamos el nombre en la variable correspondiente. • Finalmente, en la línea 8, utilizamos la instrucción JOptionPane.showMessageDialog(null, "Hola " + nombre); para mostrar un texto al usuario con el nombre ingresado. Página 11 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Clase JOptionPane para la entrada y salida de datos La clase JOptionPane es una de las clases más utilizadas en Java por su versatilidad, ya que posee varios métodos para mostrar e introducir datos en nuestras aplicaciones utilizando Cuadros de Dialogo. Estos elementos permiten al programador realizar sus aplicaciones sin necesidad de utilizar Ventanas o JFrame resolviendo cualquier problema de manera más fácil y rápida. • Salida de datos: Método showMessageDialog(Component parentComponent, Object message) Este método crea una ventana que muestra un mensaje entregado en el parámetro message. El parámetro parentComponent es para indicar la ventana padre. Usaremos null en este parámetro. • Entrada de datos: Método String showInputDialog(Object message) Este método es una función que muestra una ventana con una caja de texto y dos botones: Aceptar y Cancelar. Si seleccionamos aceptar, recibiremos un String con el contenido de la caja de texto como retorno de la función. Si seleccionamos cancelar, recibiremos un null como resultado. Página 12 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Los programas Java se organizan en proyectos constituidos por una o varias clases. Cuando vamos a trabajar en un proyecto necesitamos abrirlo previamente, o crearlo si es nuevo. Las clases se graban en archivos .Java. Un archivo .java, conteniendo código origen (source) se puede: • Editar, el programador codifica una clase en Java. Puede ser una nueva o modificar una existente. Si es una clase existente, usando el IDE posicionamos cursor sobre el .java y abrir. Si es nueva, seleccionamos new, archivo java vacío (Por ejemplo). • Compilar, el compilador de Java traduce el programa Java a códigos de bytes, que es el lenguaje que entiende la JVM (Java Virtual Machina, Máquina Virtual Java) el intérprete de Java. Si el programa se compila correctamente se producirá un archivo llamado Proyecto1.class. Éste es el archivo que contiene los códigos de bytes que serán interpretados durante la fase de ejecución. • Cargar, antes de que un programa pueda ejecutarse, es necesario colocarlo en la memoria. Esto lo hace un cargador de clases que toma el archivo (o archivos) .class que contiene los códigos de bytes y lo(s) transfiere a la memoria. El archivo .class puede cargarse de un disco de su sistema o a través de una red. Esto ocurre cuando seleccione la opción run de su entorno de desarrollo. Llamamos al programa “Proyecto1” una aplicación. Las aplicaciones son programas que son ejecutados por la Máquina virtual de Java. • Verificar, antes de que JVM pueda ejecutar los códigos de bytes, éstos son verificados por el verificador de códigos de bytes. Esto asegura que los códigos de bytes son válidos y que no violan las restricciones de seguridad de Java. Java cumple reglas de seguridad muy estrictas porque los programas Java que llegan por la red podrían causar daños a los archivos y el sistema del usuario. • Ejecutar, por último la computadora, controlada por su CPU, interpreta del programa, un código de byte a la vez. Los programas casi nunca funcionan a la primera. Cada una de las fases anteriores puede fallar a causa de diversos tipos de errores. El programador regresaría a la fase de edición, haría las correcciones necesarias y pasaría otra vez por las demás fases para determinar si las correcciones surtieron el efecto que se esperaba. Gramática del lenguaje Java En general la gramática de java se parece a la del C/C++, vamos a ver los puntos más importantes para poder escribir un programa en Java. Comentarios En Java hay tres tipos de comentarios: // comentarios para una sola línea /* comentarios de una o más líneas */ Página 13 /** * Clase que imprime un saludo inicial * @author Claudia * @version 2 */ Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Los dos primeros tipos de comentarios son los que todo programador conoce y se utilizan del mismo modo. Los comentarios de documentación, colocados inmediatamente antes de una declaración (de variable o función), indican que ese comentario ha de ser colocado en la documentación que se genera automáticamente cuando se utiliza la herramienta de Java javadoc. Dichos comentarios sirven como descripción del elemento declarado permitiendo generar una documentación de nuestras clases escrita al mismo tiempo que se genera el código. Javadoc funciona por medio de marcas que ayudan al API reconocer las partes que queremos documentar y crear los archivos HTML. • • • • • • • • @author - El nombre del autor del proyecto por ejemplo pepito :) @version - La versión del proyecto @see - Añade una referencia a una clase, método o enlace web @param - Nombre de parámetro utilizado en un método incluido su significado @return - El resultado de un método incluido su descripción @exception - Nombre de la excepción mas una descripción @throws - Nombre de la excepción mas una descripción @deprecated - Añade una alerta al usuario de que el método que sigue a continuación ya no debe usarse y que será eliminado en versiones posteriores. Para generar el JavaDoc de un proyecto, deberá seleccionar el proyecto, clic con el botón derecho y escoger la opción “Generate JavaDoc” Página 14 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Obteniendo el siguiente archivo .html: Para visualizar las marcas no incluidas en el archivo JavaDoc generado, deberá seleccionar el proyecto y en sus propiedades, en la sección de documentación habilitar las marcas a mostrar: Página 15 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Identificadores Los identificadores nombran variables, funciones, clases y objetos; cualquier cosa que el programador necesite identificar o usar. En Java, un identificador comienza con una letra, un subrayado (_) o un símbolo de dólar ($). Los siguientes caracteres pueden ser letras o dígitos. Se distinguen las mayúsculas de las minúsculas y no hay longitud máxima. Serían identificadores válidos: identificador , nombre_usuario, Nombre_Usuario , _variable_del_sistema , $transaccion y su uso sería, por ejemplo: int contador_principal; char _lista_de_ficheros; float $cantidad_en_Ptas; Palabras clave Las siguientes son las palabras clave que están definidas en Java y que no se pueden utilizar como identificadores: abstract continue for new switch boolean default goto null synchronized break do if Byte double implements private threadsafe byvalue else import protected throw while case extends instanceof public transient catch false int return true package this super char final interface short try class finally long static void const float native Palabras reservadas Además, el lenguaje se reserva unas cuantas palabras más, pero que hasta ahora no tienen un cometido específico. Son: • • • • • • • • cast future generic inner Página 16 operator outer rest var Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Sentencias Simples Una sentencia simple es la unidad ejecutable más pequeña de un programa Java. Las sentencias controlan el flujo u orden de ejecució n. Una sentencia Java puede formarse a partir de una palabra clave (for, while, if...else, etc), expresiones, declaraciones o llamadas a métodos. Toda sentencia simple termina con un punto y coma (;). Por ejemplo: Sentencias Compuestas o Bloques Una sentencia compuesta o bloque, es una colección de sentencias simples incluidas entre llaves { } . Un bloque puede contener a otros bloques. Por ejemplo: Tipos de Datos Los tipos de datos en Java se clasifican en: tipos primitivos y tipos referenciados. Tipos primitivos Hay ocho tipos primitivos de datos que podemos clasificar en: tipos numéricos y el tipo boolean. A su vez, los tipos numéricos se clasifican en tipos enteros y tipos reales. • • Tipos enteros: byte, short, int, long y char. Tipos reales: float y double. Cada tipo primitivo tiene un rango diferente de valores positivos y negativos, excepto el boolean que solo tiene dos valores: true y false. El tipo de datos que se seleccione para declarar las variables de un determinado programa dependerá del rango y tipo de valores que vayan a almacenar cada una de ellas y de si estos son enteros o fraccionarios. Se les llama primitivos porque están integrados en el sistema y en realidad no son objetos, lo cual hace que su uso sea más eficiente. Más adelante veremos también que la biblioteca Java proporciona las clases: Byte, Character, Short, Integer, Long, Float, Double y Boolean, para encapsular cada uno de los tipos expuestos, proporcionando así una funcionalidad añadida para manipularlos. La siguiente tabla muestra los tipos primitivos: Página 17 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II TIPO DESCRIPCIÓN DEFAULT TAMAÑO EJEMPLOS boolean true o false false 1 bit true, false byte entero complemento de dos 0 8 bits 100, -50 char carácter unicode \u0000 16 bits ‘a’, ‘\u0041’, ‘\101’, ‘\\’ short entero complemento de dos 0 16 bits 10000,-20000 int entero complemento de dos 0 32 bits 100000,-2,-1,0,1,2,-200000 long entero complemento de dos 0 64 bits -2L,-1L,0L,1L,2L float coma flotante IEEE 754 0.0 32 bits 1.23e100f, -1.23e-100f, .3ef, 3.14f double coma flotante IEEE 754 0.0 64 bits 1.2345e300d, -1.2345e-300f, 1e1d Tipos referenciados Hay tres clases de tipos referenciados: clases, interfaces y arrays. Referencia a Objetos Una variable es un lugar en la memoria donde se guarda un dato. Para ser exacto, este lugar en la memoria es la Pila o Stack. En el caso de los datos primitivos, como en “int i = 5”, el número 5 se almacena en la pila. Cuando se crea un objeto en Java, como en “new Date()” , el objeto se guarda en una parte de la memoria llamada Heap. Cuando asignamos el objeto a una variable como en “fecha = new Date()”, lo que guardamos en fecha es la dirección de memoria Heap donde está el objeto. Ejemplo: Visualicemos como queda la memoria después de ejecutar las asignaciones anteriores: Página 18 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II En la Pila o Stack ,se guardan las 4 variables. − − “i1” e “i2” tienen copias independientes del valor 5. “fecha1” y “fecha2” almacenan un puntero al mismo objeto. Cualquier modificación dentro del objeto Date, se verá reflejada tanto en fecha1 como fecha2. Conversión entre tipos de datos Cuando Java tiene que evaluar una expresión en la que intervienen operandos de diferentes tipos, primero convierte, solo para realizar las operaciones solicitadas, los valores de los operandos al tipo del operando cuya precisión sea más alta. Cuando se trate de una asignación, convierte el valor de la derecha al tipo de la variable de la izquierda siempre que no haya pérdida de información. En otro caso, Java exige que la conversión se realice explícitamente. La figura siguiente resume los tipos colocados de izquierda a derecha de menos a más precisos; las flechas indican las conversiones implícitas permitidas: //Conversion implicita byte bDato = 1; short sDato = 0; int iDato = 0: long lDato = 0; float fDato = 0; double dDato = 0; sDato = bDato; iDato = sDato; lDato = i Dato; fDato = lDato; dDato = fDato + lDato -iDato * sDato / bDato; System.out.println(dDato); // resultado: 1.0 Java permite una conversión explicita (conversión forzada) del tipo de una expresión mediante una construcción denominada casting, que tiene la forma: (tipo) expresion Se debe colocar el tipo destino entre paréntesis, a la izquierda del valor que queremos convertir El casting se utiliza cuando Java no puede realizar automáticamente la conversión de tipo, generalmente dado que el receptor tiene menos espacio que el tipo de origen, por lo que se hace necesario un casting. int intValue= (int) floatValue; Cualquier valor de un tipo entero o real puede ser convertido a o desde cualquier tipo numérico. No se pueden realizar conversiones entre los tipos enteros o reales y el tipo Boolean. Por ejemplo: Página 19 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II // Conversion explicita (cast) byte bDato = 0; short sDato = 0; int iDato = 0; long lDato 0 ; float fDato = 0; double dDato = 2; fDato = (float)dDato; lDato = (long)fDato; iDato = (int)lDato; sDato = (short)iDato; bDato = (byte)(sDato + iDato -lDato * fDato / dDato); System.out.println(bDato); // resultado: 2 La expresión es convertida al tipo especificado si esa conversión esta permitida; en otro caso, se obtendrá un error. La utilización apropiada de construcciones cast garantiza una evaluación consistente, pero siempre que se pueda, es mejor evitarla ya que suprime la verificación de tipo proporcionada por el compilador y por consiguiente puede conducir a resultados inesperados, o cuando menos, a una pérdida de precisión en el resultado. Por ejemplo: float r; r = (float)Math.sgrt(10); // el resultado se redondea perdiendo precisión ya que sqrt //devuelve un valor de tipo double Variables En un programa informático, hay que manipular los datos. Estos son accesibles, en general, mediante la utilización de: • parámetros de métodos o de funciones; • variables locales; • variables globales; • atributos de objetos. Género de las variables En informática hay dos maneras de almacenar las variables en un método: • se almacena el valor de la variable; • se almacena la dirección donde se encuentra la variable. En Java: • los tipos elementales se manipulan directamente: se dice que se manipulan por valor; • los objetos se manipulan a través de su dirección: se dice que se manipulan por referencia. Asignaciones a variables Se asigna un valor a una variable mediante el signo = Variable = Constante | Expresión; Por ejemplo: Página 20 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II suma = suma + 1; precio = 1.05 * precio; Inicialización de las variables: En Java no se puede utilizar una variable sin haberla inicializado previamente. El compilador señala un error cuando se utiliza una variable sin haberla inicializado. Operadores Los operadores de Java son muy parecidos en estilo y funcionamiento a los de C. En la siguiente tabla aparecen los operadores que se utilizan en Java, por orden de precedencia: Separadores Sólo hay un par de secuencias con otros caracteres que pueden aparecer en el código Java; son los separadores simples, que van a definir la forma y función del código. Los separadores admitidos en Java son: () paréntesis Para contener listas de parámetros en la definición y llamada a métodos. También se utiliza para definir precedencia en expresiones, contener expresiones para control de flujo y rodear las conversiones de tipo {} - llaves Para contener los valores de matrices inicializadas automáticamente. También se utiliza para definir un bloque de código, para clases, métodos y ámbitos locales [ ] corchetes Para declarar tipos matriz. También se utiliza cuando se referencian valores de matriz ; punto y coma Separa sentencias , coma Separa identificadores consecutivos en una declaración de variables . punto Para separar nombres de paquete de subpaquetes y clases Página 21 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Estructuras de Control Las estructuras de control (secuencial/selectiva/iterativa) funcionan y tienen la misma sintaxis de C/C++ . Práctica 1- Realizar un programa que permita sumar dos números. 2- Realizar un programa que solicite el ingreso de cinco números y calcule su suma. 3- Realizar un programa que solicite el ingreso de dos números y presente el siguiente menú de opciones: Menú de Opciones 1-Suma 2-Resta 3-Multiplicacion 4-Division 5-Salir Página 22 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Adicional: Agregar la validación necesaria para evitar divisiones en cero. Página 23 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Clases Como ya dijimos, una clase es una implementación de un concepto, y entonces un modelo que se utiliza para describir a objetos similares. Las clases son lo más simple de Java. Todo en Java forma parte de una clase, es una clase o describe cómo funciona una clase. El conocimiento de las clases es fundamental para poder entender los programas Java. Todas las acciones de los programas Java se colocan dentro del bloque de una clase o un objeto. Todos los métodos se definen dentro del bloque de la clase, Java no soporta funciones o variables globales. Esto puede desconcertar a los programadores de C++, que pueden definir métodos y variables globales fuera del bloque de la clase. Así pues, el esqueleto de cualquier aplicación Java se basa en la definición de una clase, o más a menudo, varias, muchas. Todos los datos básicos, como los enteros, se deben declarar en las clases antes de hacer uso de ellos. En C la unidad fundamental son los archivos con código fuente, en Java son las clases. De hecho son pocas las sentencias que se pueden colocar fuera del bloque de una clase. La palabra clave import (equivalente al #include de C) puede colocarse al principio de un archivo, fuera del bloque de la clase. El compilador reemplazará esa sentencia con el contenido del archivo que se indique, que consistirá, como es de suponer, en más clases. Además de import, fuera de la clase podemos tener la palabra clave package y nada más… Una clase es un marco que permite crear objetos de su misma estructura. Estos objetos constan de: • • Variables de clase y de instancia, que son los descriptores de atributos y entidades de los objetos. Métodos, que definen las operaciones que pueden realizar esos objetos. En una aplicación un objeto se instancia a partir de una descripción de su clase: es dinámico, podemos tener una infinidad de objetos de esa una misma clase. Estructura General de una clase Una clase contiene elementos, llamados miembros, que pueden ser datos, llamados atributos y funciones que manipulan esos datos llamados métodos. Una clase se define con la palabra reservada class. La sintaxis de una clase es: Todo lo que está entre [ y ] es opcional. Como se ve, lo único obligatorio es class y el nombre de la clase. Página 24 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II public, final, abstract • • • • Definir una clase como pública (public) significa que puede ser usada por cualquier clase en cualquier paquete (package). Si no lo es, solamente puede ser utilizada por clases del mismo paquete (un paquete, básicamente, es un grupo de clases e interfaces relacionadas, como los paquetes de biblioteca incluidos con Java). Una clase final (final) es aquella que no puede tener clases que la hereden. Esto se utiliza básicamente por razones de seguridad (para que una clase no pueda ser reemplazada por otra que la herede), o por diseño de la aplicación. Una clase abstracta (abstract) es una clase que puede tener derivadas, pero no puede ser instanciada. Es literalmente abstracta. ¿Para qué sirve? Para modelar conceptos. Por ejemplo, la clase Number es una clase abstracta que representa cualquier tipo de números (y sus métodos no están implementados: son abstractos); las clases descendientes de ésta, como Integer o Float, sí implementan los métodos de la madre Number, y se pueden instanciar. Por todo lo dicho, una clase no puede ser final y abstract a la vez (ya que la clase abstract requiere descendientes). extends La instrucción extends indica de qué clase desciende la nuestra. Si se omite, Java asume que desciende de la superclase object. Cuando una clase desciende de otra, significa que hereda sus atributos y sus métodos. Esto quiere decir que, a menos que los redefinamos, sus métodos serán los mismos que los de la clase madre y podrán utilizarse en forma transparente, siempre y cuando no sean privados en la clase madre, o protegidos o propios del paquete para subclases de otros paquetes. Declaración y Definición • • La declaración lista los miembros de la clase. La definición, también llamada implementación, define las funciones de la clase. La declaración y la definición de la clase van juntas. Por ejemplo: Página 25 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II El cuerpo de la Clase El cuerpo de la clase, encerrado entre { y }, es la lista de atributos (variables) y métodos (funciones) que la constituyen. No es obligatorio, pero en general se listan primero los atributos y luego los métodos. Instancias de una clase - Objetos Los objetos de una clase son instancias de la misma. Se crean en tiempo de ejecución con la estructura definida en la clase. Para crear un objeto de una clase se usa la palabra reservada new. Por ejemplo si tenemos la siguiente clase: el objeto o instancia de la clase cliente es: El operador new reserva espacio en memoria para los miembros dato y devuelve una referencia que se guarda en la variable comprador de tipo Cliente que denominamos ahora objeto. Dicha sentencia, crea un objeto denominado comprador de la clase Cliente. Acceso a los miembros Desde un objeto se puede acceder a los miembros mediante la siguiente sintaxis objeto.miembro; Por ejemplo, podemos acceder al método setImporte, para cambiar el importe de la deuda del objeto comprador. Página 26 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Si el cliente comprador, por ejemplo, tenía inicialmente un importe de 0, mediante esta sentencia se lo cambiamos a 100. Desde un objeto llamamos a las funciones miembro para realizar una determinada tarea. Por ejemplo, desde el cliente comprador llamamos a la función getImporte() para obtener el importe de dicho cliente. La función miembro getImporte() devuelve un número, que guardaremos en una variable adeuda, para luego usar este dato. float adeudado=0; adeudado=comprador.getImporte(); System.out.println(“Lo adeudado es: ”+ adeudado); Como veremos más adelante, no siempre es posible acceder a los miembros, el acceso dependerá de los controles de acceso a los mismos. Ciclo de vida de los objetos Cuando se ejecuta un programa orientado a objetos ocurren tres sucesos. a) Los objetos se crean a medida que se necesitan. b) Los mensajes se mueven de un objeto a otro (o del usuario a un objeto) a medida que el programa procesa información o responde a la entrada del usuario. c) Cuando los objetos ya no se necesitan, se borran y se libera la memoria, dicha tarea la realiza el recolector de basura (garbage collecto) Declaración de los Miembros de una Clase Los datos de una clase se denominan atributos y las funciones de una clase se denominan métodos. Los miembros tienen ciertas restricciones en el modo en que se puede manipular los mismos dentro y fuera de la clase, a esto se le llama control de acceso a una clase o visibilidad. Con estas restricciones se logra la encapsulación que, como vimos en la introducción, consiste en separar los aspectos externos del objeto, a los cuales pueden acceder otros objetos, de los detalles de implementación del mismo, que quedan ocultos para los demás. La encapsulación se basa en la noción de servicios prestados; una clase proporciona un cierto número de servicios y los usuarios de esta clase no tienen que conocer la forma como se prestan estos servicios. Hay que distinguir pues en la descripción de la clase dos partes: Página 27 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II • • la parte pública, accesible por las otras clases; la parte privada, accesible únicamente por los métodos de la clase. Se recomienda poner los atributos de una clase en la parte privada, para respetar el concepto de encapsulamiento. Modificadores de acceso a miembros de clases Java proporciona varios niveles de encapsulamiento que vamos a examinar a continuación: Hemos representado en este dibujo una clase Madre alrededor de la cual gravitan otras clases: • • • sus hijas HijaQuerida e HijaIndigna, la segunda de las cuales se encuentra en otro paquete; estas dos clases heredan de Madre. la herencia se explica en detalle algo más adelante, pero retenga que las clases HijaQuerida e HijaIndigna se parecen mucho a la clase Madre. Los paquetes se detallan igualmente algo más adelante; retenga que un paquete o package es un conjunto de clases relacionadas con un mismo tema destinada para su uso por terceros, de manera análoga a como otros lenguajes utilizan las librerías. sus colegas, que no tienen relación de parentesco pero están en el mismo paquete; una clase Extranjera, sin ninguna relación con la clase Madre. En el esquema anterior, así como en los siguientes, la flecha simboliza la relación de herencia. En los párrafos siguientes vamos a examinar sucesivamente los diferentes tipos de protección que Java ofrece a los atributos y a los métodos. Observemos ya desde ahora que hay cuatro tipos de protección posibles y que, en todos los casos, la protección va sintácticamente al principio de definición, como en los dos ejemplos siguientes, donde private y public definen los niveles de protección: Los niveles de encapsulamiento que ofrece JAVA son: Página 28 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II • Private: La protección más fuerte que puede dar a los atributos o a un método es la protección private. Esta protección impide a los objetos de otras clases acceder a los atributos o a los métodos de la clase considerada. En el dibujo siguiente, un muro rodea la clase Madre e impide a las otras clases acceder a aquellos de sus atributos o métodos declarados como private. Insistimos en el hecho de que la protección no se aplica a la clase globalmente, sino a algunos de sus atributos o métodos, según la sintaxis siguiente: • Protected: permite restringir el acceso a las subclases y a las clases del mismo paquete. • Friendly: El tipo de protección predeterminado se llama friendly. En Java si no se indica explícitamente ningún nivel de protección para un atributo o un método, el compilador considera que lo ha declarado friendly. No tiene por qué indicar esta protección explícitamente. Además, friendly no es una palabra clave reconocida. Esta protección autoriza el acceso a las clases del mismo paquete, pero no incluye a las subclases. Página 29 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Los miembros con este tipo de acceso pueden ser accedidos por todas las clases que se encuentren en el paquete donde se encuentre también definida la clase. Para recordar: ✓ Friendly es el tipo de protección asumido por defecto. ✓ Un paquete se define por la palabra reservada package. ✓ Las clases se codifican en archivos .java ✓ Varios archivos pueden pertenecer al mismo paquete. ✓ Un archivo solo pertenece a un paquete. Solo se permite una cláusula package por archivo. ✓ Los archivos que no tienen cláusulas package pertenecen al paquete unnamed. • Public: El último tipo de protección es public. Un atributo o un método calificado así es accesible para todo el mundo. ¿Un caso excepcional? No. Muchas clases son universales y proporcionan servicios al exterior de su paquete: las librerías matemáticas, gráficas, de sistema, etc., están destinadas a ser utilizadas por cualquier clase. Por el contrario, una parte de estas clases está protegida, a fin de garantizar la integridad del objeto. Se suele decir que los miembros públicos conforman la interfaz de la clase con el usuario. Atributos de una Clase • • • • • • • • Todas las variables se declaran dentro del cuerpo de la clase o dentro de un método. Las variables declaradas dentro de un método son locales a él. las variables declaradas en el cuerpo de la clase se dice que son miembros de ella y son accesibles por todos los métodos de la clase. Se puede acceder a todos los atributos de la clase de la cual desciende. Esto lo veremos con mayor detalle cuando estudiemos herencia. Los atributos miembros de la clase pueden ser atributos de clase o atributos de instancia: ✓ Atributos de clase: si se usa la palabra clave static: en ese caso la variable es única para todas las instancias (objetos) de la clase (ocupa un único lugar en memoria). ✓ Atributos de instancia: no se usa static, el sistema crea un lugar nuevo para esa variable con cada instancia (o sea que es independiente para cada objeto). Los atributos pueden ser: ✓ tipos básicos. (no son clases) ✓ clases e interfases (clases de tipos básicos, clases propias, de terceros, etc.) La lista de atributos sigue el mismo formato de C/C++ se define primero el tipo y luego el nombre del atributo y, finalmente, un ";". Por ejemplo: La declaración sigue siempre el mismo esquema: Página 30 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II El modificador de acceso puede ser alguno de los que vimos anteriormente (private, protected, public, etc). static sirve para definir un atributo como de clase, o sea, único para todos los objetos de ella. final, como en las clases, determina que un atributo no pueda ser sobreescrito o redefinido, es decir que no se trata de una variable, sino de una constante. transient, denomina atributos que no se graban cuando se archiva un objeto, o sea que no forman parte del estado permanente de éste. volatile se utiliza con variables modificadas en forma asincrónica por objetos en diferentes threads (literalmente "hilos", tareas que se ejecutan en paralelo). Básicamente, esto implica que distintas tareas pueden intentar modificar la variable de manera simultánea, y volatile asegura que se vuelva a leer la variable (por si fue modificada) cada vez que se la va a usar. Métodos de una clase Un método es una función que se ejecuta sobre un objeto. No se puede ejecutar un método sin precisar el objeto sobre el que se aplica (salvo una excepción que veremos más adelante). Los métodos de una clase definen las operaciones que un usuario puede realizar con los atributos de la clase. Desde el punto de vista de la POO, el conjunto de todas las funciones definen el conjunto de mensajes a los que los objetos de las citadas clases pueden responder. Declaración y definición Los métodos, como las clases, tienen una declaración y un cuerpo. La declaración es del tipo: Las variables declaradas en el cuerpo del método son locales a dicho método y por definición solamente son accesibles dentro del mismo. El modificador de acceso es la palabra clave que modifica el nivel de protección predeterminado del método, puede ser alguno de los que vimos anteriormente (private,protected, public, etc). Página 31 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II El tipoDevuelto especifica qué tipo de valor retorna el método. Éste puede ser cualquier tipo primitivo o referenciado. Para indicar que no se devuelve nada, se utiliza la palabra reservada void. El resultado de un método es devuelto a la sentencia que lo invocó, por medio de la siguiente sentencia: En el caso de que el método no retorne un valor (void ), se puede omitir o especificar simplemente return. Por ejemplo: La lista de parámetros de un método son las variables que reciben los valores de los argumentos especificados cuando se invoca al mismo. Consiste en una lista de cero, uno o más identificadores con sus tipos, separados por comas. Estos parámetros pueden ser de cualquiera de los tipos válidos. El resto de la declaración • • • • • • Los métodos estáticos (static) son, como los atributos, métodos de clase: si el método no es static, es un método de instancia. El significado es el mismo que para los atributos: un método static es compartido por todas las instancias de la clase. Los métodos abstractos ( abstract) son aquellos de los que se da la declaración pero no la implementación (o sea que consiste sólo en el encabezamiento). Cualquier clase que contenga al menos un método abstracto (o cuya clase madre contenga al menos un método abstracto que no esté implementado en la hija) es una clase abstracta. Un método es final (final) cuando no puede ser redefinido por ningún descendiente de la clase. Los métodos native son aquellos que se implementan en otro lenguaje propio dela máquina (por ejemplo, C o C++). Sun aconseja utilizarlas bajo riesgo propio, ya que, en realidad, son ajenas al lenguaje. Pero existe la posibilidad de usar viejas bibliotecas que uno armó y no tiene ganas de reescribir, ¡a costa de perder portabilidad! Los métodos synchronized permiten sincronizar varios threads para el caso en que dos o más accedan concurrentemente a los mismos datos. Finalmente, la cláusula throws sirve para indicar que la clase genera determinadas excepciones. El cuerpo de los métodos En Java dentro de los métodos pueden incluirse: • • • Declaración de variables locales Asignaciones a variables Operaciones matemáticas Página 32 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II • • • Llamados a otros métodos Estructuras de control Excepciones (try, catch, que veremos más adelante) Declaración de variables locales Las variables locales en un método se declaran igual que en C/C++: Por ejemplo: Las variables pueden inicializarse al momento de su creación. El objeto actual (puntero this) Nunca se puede llamar una función miembro de una clase a menos que se asocie con un objeto (una instancia de la clase). ¿Cómo sabe una función miembro cuál es la instancia de una clase (el objeto específico) asociada con ella? El método utilizado por Java es añadir un argumento extra oculto a las funciones miembro. Este argumento es un puntero al objeto de la clase que los enlaza con la función asociada y recibe un nombre especial denominado this. Dentro de una función miembro, this apunta al objeto asociado con la invocación de la función miembro. Normalmente, el programador no necesita preocuparse por este puntero, ya que el lenguaje realiza la operación automáticamente transparente a las funciones miembro que la utilizan. Las referencias a los miembros del objeto asociado a la función se realiza con el prefijo this y el operador de acceso punto “.”. Si tomamos como ejemplo la siguiente clase: Página 33 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Cuando escribimos en el método setImporte: para asignar un valor a importe, no tuvimos necesidad de indicar a qué objeto pertenecía. Cuando no se pone el objeto antes del atributo, se asume que la variable es un miembro del objeto, o es una variable local o parámetro. Si los nombres colisionan, como podría ser en los siguientes métodos: usamos this para indicar al objeto actual. Esta palabra reserva da siempre está apuntando al objeto actual, y puede usarse como en este caso, para resolver una ambigüedad. Métodos Especiales Métodos set y get Los Sets y Gets son la forma de acceder a atributos de una clase. Generalmente, se usan con los atributos privados, ya que a los públicos se puede acceder directamente sin tener que usar estos métodos • • Get: Devuelve el valor de una variable Método Set: Modifica el valor de una variable Página 34 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Métodos Sobrecargados Tradicionalmente, un método o una función realizan una tarea específica para la que están programados. Java soporta la sobrecarga de métodos, lo que le permite definir versiones de éstos con el mismo nombre en una clase, siempre y cuando las versiones tengan diferentes firmas. Una firma incluye el nombre del método, el número, el orden y los tipos de sus parámetros formales. Como ejemplo simple, considere el reestablecímiento del saldo de cuenta de un objeto Account, esta clase (Account) ya tiene un método. que se utiliza para recuperar el saldo de la cuenta. Con la sobrecarga podemos definir un método: que fija el saldo en una cantidad específica. El mismo método recuperará o establecerá el saldo, dependiendo de que se proporcione un argumento; ¡es muy útil! Tenga en cuenta que, sólo ocurre la sobrecarga, cuando se utiliza varias veces el mismo nombre de método dentro de una clase. No hay un límite práctico para las versiones que es posible apilar en el mismo nombre de método. Resolución de llamada a un método Cuando se hace una llamada a un método sobrecargado Java deduce automáticamente, a partir de los argumentos reales, la versión correcta del método que habrá de invocar. A esta actividad se le Página 35 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II denomina resolución de llamada, Java la realiza al seleccionar un método entre los accesibles que son aplicables. Un método es aplicable si toma el mismo número de parámetros que los argumentos dados y cada uno de éstos puede transformarse por conversión de invocación de método al tipo del parámetro. El compilador realiza la resolución de llamada de método al comparar el número y tipo de los argumentos reales con firmas de todos los métodos accesibles y elige un método aplicable que es el más específico. En resumen, las funciones sobrecargadas tienen el mismo nombre, pero deben tener un número diferente de argumentos o diferentes tipos de argumentos, o ambos. Por ejemplo: Ejemplo: Supongamos que tenemos una clase Media, que calcula la media de dos y tres números, enteros y reales. Para esto tendremos las siguientes funciones: Entonces: Página 36 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Métodos constructores Para cada clase, pueden definirse uno o más métodos particulares: son los constructores. Un constructor es una función especial que sirve para construir o inicializar objetos. En general: • Tienen el mismo nombre de la clase que inicializa. • No devuelven valores. • Pueden admitir parámetros como cualquier otra función. • Pueden existir más de un constructor, e incluso no existir. • Si no se define ningún constructor de una clase, el compilador generará un constructor por defecto. • Se llaman en el momento de la creación del objeto. Página 37 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II A continuación probamos la clase con el siguiente ejemplo: Cuando, desde una aplicación u otro objeto, se crea una instancia instrucción: de la clase Contador, mediante la el compilador busca un método con el mismo nombre de la clase y que se corresponda con la llamada en cuanto al tipo y número de parámetros. Dicho método se llama Constructor, y una clase puede tener más de un constructor (no así un objeto instanciado, ya que, una vez que fue creado, no puede "recrearse" a sí mismo). En tiempo de compilación o ejecución, según corresponda, al encontrarse dicha instrucción, se reserva espacio para el objeto instanciado y se crea su estructura y en tiempo de ejecución se llama al método constructor. Si hay varios constructores, estos difieren unos de otros por los parámetros que se les pasa mediante new(). Los constructores no tienen tipo de retorno. Atención, si por error definimos un constructor que tenga un tipo de retomo, el compilador lo considerará como un método normal. En ese caso tendremos la impresión de que el constructor no se llama en el momento de la creación del objeto. Tipos de constructores • Constructor por defecto: El constructor por defecto es un constructor que no acepta argumentos. Por ejemplo: • Constructor con argumentos: El constructor con argumentos, como su nombre lo indica posee argumentos. Por ejemplo: Página 38 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II • Constructor copiador: Un constructor que crea un objeto a partir de uno existente se llama constructor copiador o de copias. Es un constructor que toma como único parámetro otro objeto del mismo tipo. El constructor de copia tiene sólo un argumento: una referencia a un objeto de la misma clase. Por ejemplo: Ejercicios Resueltos 1. Se dispone de un listado de notas y asistencia de los alumnos de un curso determinado. La información con la que se cuenta es: legajo, apellido y nombre, nota1, nota2 y porcentaje de asistencia. Se pide: a) Realizar el diagrama de clases b) Listado de alumnos aprobados (promedio mayor o igual a 4) ordenado en forma decreciente por el promedio c) Listado de alumnos desaprobados ordenado en forma decreciente por el promedio d) Cantidad de alumnos regulares ( asistencia>=70 y aprobado) e) Cantidad de alumnos libres ( asistencia<70 o desaprobado) f) Listado de alumnos ordenado por el apellido. Clase Alumno: Página 39 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Página 40 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Relación entre Clases Una aplicación orientada a objetos es una colección de objetos, algunos jerárquicos, que colaboran entre sí para dar una funcionalidad global. Cada objeto debe asumir una parte de las responsabilidades y delegar otras a los objetos colaboradores. Existirá un objeto que asume las funciones de la aplicación principal, será el encargado de crear las instancias oportunas y tener un único punto de entrada (main). Cabe hacernos una pregunta fundamental, ¿en cuántos objetos debemos descomponer la aplicación? Si realizamos objetos muy pequeños, cada uno de ellos será fácil de desarrollar y mantener, pero resultará difícil la integración. Si realizamos objetos grandes, la integración será fácil, pero el desarrollo de los objetos complicado. Se debe buscar un equilibrio. En definitiva, y sin adentrar más en la estructuración de las clases de una aplicación, nuestra aplicación tendrá un conjunto de clases que están relacionadas entre ellas. Se considera que existe una relación entre clases si sus objetos colaboran, es decir, se mandan mensajes. Tenemos, principalmente, tres tipos de relaciones entre clases: asociación (uso), agregación/composición, y herencia. Relación de Asociación Es una asociación que se establece cuando dos clases tienen una dependencia de utilización, es decir, una clase utiliza atributos y/o métodos de otra para funcionar. Ejemplo: Ejemplo: Relación de asociación entre la clase película y actor: Página 41 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Relación de Agregación/Composición: Muchas veces una determinada entidad existe como conjunción de otras entidades, como un conglomerado de ellas. La orientación al objeto recoge este tipo de relaciones como dos conceptos: la agregación y la composición: En este tipo de relaciones un objeto componente se integra en un objeto compuesto. • Relación de agregación: Se dice que la clase A tiene una relación de agregación con la clase B, si un objeto de la clase A delega funcionalidad en los objetos de la clase B. El ciclo de vida de ambos no coincide. La clase A delega parte de su funcionalidad, pero no crea el objeto B. Varios objetos pueden estar asociados con el objeto B. Al objeto A, le deben pasar la referencia del objeto B. Es una relación duradera entre cliente (A) y servidor (B), en la vida del cliente. • Relación de composición: Se dice que existe una relación de composición entre la clase A y la clase B, si la clase A contiene un objeto de la clase B, y delega parte de sus funciones en la clase B. Los ciclos de vida de los objetos de A y B coinciden. El objeto A es el encargado de crear la instancia de B y de almacenarla, siendo su visibilidad privada. Cuando se destruye A, también se destruye B. Por ejemplo, se pretende realizar una clase llamada Agenda y para ello se apoya en la clase Lista, es decir, dentro de la clase Agenda se crea una instancia de la clase Lista, y algunas de las funcionalidades que aporta la clase Agenda se realizan con los métodos de la clase Lista. Página 42 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Herencia La herencia es una propiedad esencial de la Programación Orientada a Objetos que consiste en la creación de nuevas clases a partir de otras ya existentes. Java permite heredar a las clases características y conductas de una o varias clases denominadas base. Las clases que heredan de clases base se denominan derivadas, estas a su vez pueden ser clases bases para otras clases derivadas. Se establece así una clasificación jerárquica, similar a la existente en Biología con los animales y las plantas. La herencia ofrece una ventaja importante, permite la reutilización del código. Una vez que una clase ha sido depurada y probada, el código fuente de dicha clase no necesita modificarse. Su funcionalidad se puede cambiar derivando una nueva clase que herede la funcionalidad de la clase base y le añada otros comportamientos. Reutilizando el código existente, el programador ahorra tiempo y dinero, ya que solamente tiene que verificar la nueva conducta que proporciona la clase derivadas. En la programación orientada a objetos, la herencia permite que una clase herede las características y el comportamiento de otra clase (sus métodos y atributos) y a continuación, modificar este comportamiento según sean las necesidades. Esto permite tener varias clases con un comportamiento similar en ciertas situaciones (por ejemplo al llamar a ciertos métodos) y un comportamiento específico en otras. Como se muestra en la figura: Las distintas clases de un programa se organizan mediante la jerarquía de clases: Clases bases Son clases que sirven de modelos para otras, no pueden tener el especificador final ya que una clase final es aquella que no puede tener clases que la hereden. Por ejemplo: Página 43 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Clases derivadas Las clases heredadas se llaman clases derivadas, clases hijas o subclases. Las características de las clases derivadas son: • • • • • • • Puede a su vez ser una clase base, dando lugar a una jerarquía de clases. Hereda todos los miembros de la clase base, pero solo podrá acceder a aquellos que los especificadores de acceso de la clase base lo permitan. Puede añadir a los miembros heredados, sus propios atributos y métodos. Los miembros heredados por una clase derivada, pueden a su vez ser heredados por más clases derivadas de ella. Las clases derivadas solo pueden acceder a los miembros públicos (public), protegidos (protected) de la clase base, como si fueran miembros de ella misma. No tiene acceso a los miembros privados de la clase base. Los siguientes elementos de la clase base no se heredan: ✓ constructores ✓ funciones y datos estáticos de la clase Declaración de una clase derivada La declaración de una clase derivada tiene la siguiente sintaxis: La instrucción extends indica de qué clase desciende la nuestra. Si se omite, Java asume que desciende de la superclase object. La implementación en Java sería: Página 44 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Cuando una clase hereda de otra, la clase hija hereda los atributos y los métodos de la clase padre pero existen ciertas restricciones en esta herencia: • • • • • Los atributos y los métodos con modo de acceso private no se heredan Se heredan los atributos y los métodos con modo de acceso public y protected No se hereda un atributo de una clase padre si en la clase hija se define un atributo con el mismo nombre que el atributo de la clase padre. No se hereda un método si esta sobrecargado No se heredan los constructores de la clase base o madre. Por lo tanto en el constructor de la clase derivada, en la primera línea del mismo, hay que invocar al constructor de la clase base con la palabra super y la cantidad de parámetros que requiera el constructor, esto es así porque se debe crear la clase base y por último la clase derivada. Para referenciar a los miembros de la clase base se utiliza la palabra reservada super, generalmente esta se usa si los miembros de la clase base se llaman de la misma forma que los de la clase derivada, sino, no hace falta usar la palabra super. Redefinición de métodos Al crear una clase que hereda de otra se pueden definir nuevos atributos y métodos o se puede modificar el comportamiento de los objetos de la clase redefiniendo los métodos de la clase padre. La redefinición se refiere a la posibilidad de proporcionar nuevos métodos con el mismo nombre que tienen los métodos de la clase padre, per con diferente comportamiento. Esto permite que el entorno y comportamiento de una clase sea heredado por otra y solamente se modifiquen aquellos métodos que sean necesarios para su comportamiento específico. Página 45 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Dará el siguiente resultado: Los objetos de la clase Padre utilizan el método de la clase Padre, los de la clase Hija el método redefinido en la clase Hija y los de la clase Nieta utilizan el método de la clase Hija, porque este método no ha sido redefinido en la clase Nieta. Sobrecarga de Métodos La sobrecarga es definir dos o más métodos con el mismo nombre, pero con parámetros diferentes por cantidad o tipo. El objetivo de la sobrecarga es reducir el número de identificadores distintos para una misma acción pero con matices que la diferencian. La sobrecarga se puede realizar tanto en métodos generales, como en constructores. Ejemplo de sobrecarga a los constructores de la clase Punto: Página 46 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Operador instanceof Se puede consultar si un objeto pertenece a una clase mediante el operador instanceof Conversión de tipos. Casting Java admite la conversión de tipos con ciertas limitaciones. Consideremos una jerarquía de herencia como la que vemos en el siguiente diagrama de clases, sobre el que vamos a analizar las posibilidades de conversión de tipos de distintas formas. • Conversión hacia arriba: se trataría por ejemplo de poner lo que está a un nivel inferior en un nivel superior, por ejemplo poner un alumno como persona. Persona1=Alu1 Ponemos lo que está abajo (Alumno) arriba (como persona). Esto es posible, pero dado que lo que está abajo generalmente contiene más campos y métodos que lo que está arriba, perderemos parte de la información. Sobre el objeto persona1 ya no podremos invocar los métodos propios de los alumnos • Conversión hacia abajo: Se trataría de poner lo que está arriba abajo, por ejemplo poner una Persona como Alumno. Esto no siempre es posible. El supertipo admite cualquier forma (es polimórfico) de los subtipos: si el supertipo almacena el subtipo al que queremos realizar la conversión, será posible usando lo que se denomina “Enmascaramiento de tipos” o “Hacer Casting” (cast significa “moldear”). Si el supertipo no almacena el subtipo al que queremos convertirlo, la operación no es posible y saltará un error. Ejemplo: Página 47 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Persona p; Alumno a = new Alumno (); a=p // error El compilador no puede determinar si p almacena un alumno o profesor u otro tipo de persona, y arroja un error. La forma de forzar al compilador a que “comprenda” que p está almacenando un alumno y por tanto puede asignarse a una variable que apunta a un alumno se llama “hacer casting”. Escribiríamos lo siguiente: a = (Alumno) p; Modificador de acceso: final • Si lo aplicamos a una clase, no se permite que existan subclases. • Si lo aplicamos a un método, no se permite que subclases redefinan el método. Polimorfismo En Java, hay ciertos conceptos que se van a usar para aplicar polimorfismo, ellos son: Clases abstractas Son clases genéricas, sirven para agrupar clases del mismo género, no se pueden instanciar, es decir, no se pueden crear objetos a partir de ellas, ya que representan conceptos tan generales que no se puede definir como será la implementación de la misma. Es por eso que dichas clases llevan métodos que se llaman abstractos, que no tienen implementación. En Java una clase abstracta debe tener al menos un método abstracto. Métodos abstractos Métodos que no tienen implementación, se utilizan para recibir los mensajes en común, No tienen implementación porque en el nivel donde se definen no hay información suficiente para implementarlos. En los próximos niveles de la jerarquía se pueden implementar, para ello deben ser redefinidos en niveles posteriores. Página 48 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Sintaxis: Ejemplo de aplicación: Clase Figura: Clase Triangulo: Página 49 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Clase Cuadrado: Clase Aplicación Página 50 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Página 51 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Excepciones Las excepciones son el medio que ofrecen algunos lenguajes de programación para tratar situaciones anómalas que pueden suceder cuando ejecutamos un programa. Algunos casos de situaciones anómalas que se pueden citar, son, por ejemplo, invocar a un método sobre un objeto “null”, intentar dividir un número por “0”, intentar abrir un fichero que no existe para leerlo, quedarnos sin memoria en la JVM al ejecutar (por ejemplo, debido a un bucle infinito), intentar crear un fichero en una carpeta en la que no hay permisos de escritura, tratar de recuperar información de Internet cuando no se dispone de conexión, o simplemente sufrir un apagón eléctrico al ejecutar nuestro código. Como se puede observar en los ejemplos anteriores, las excepciones no son inherentes a los lenguajes de POO, pero sí que lo son a Java como lenguaje de programación (también se pueden encontrar excepciones en otros lenguajes). Hay que tener en cuenta que muchos de los métodos de la propia librería de Java hacen uso de excepciones, e incluso los programas que hemos desarrollado hasta ahora nos han permitido observar algunas de ellas (como, por ejemplo, la muy común NullPointerException). Por este motivo, cualquier programador en Java tiene que ser capaz de crear, lanzar y gestionar excepciones de una forma adecuada. Definición: Una excepción es un evento excepcional que ocurre durante la ejecución del programa y que interrumpe el flujo normal de las sentencias. Si una operación no puede completarse debido a un error, el programa deberá: • • volver a un estado estable y permitir otras operaciones. intentar guardar el trabajo y finalizar. Esto es difícil debido a que generalmente, el código que detecta el error no es el que puede realizar dichas tareas. El que detecta el error debe informar al que pueda manejarlo. Como casi todo lo demás en Java, las excepciones son objetos (que se crean cuando ocurre una situación anómala). Se lanzan para que otra parte del código las capture y las trate. Una excepción es una situación anómala que puede provocar que el programa no funcione de forma correcta o termine de forma inesperada. Ejemplos de situaciones que provocan una excepción: • No hay memoria disponible para asignar • Acceso a un elemento de un array fuera de rango • Leer por teclado un dato de un tipo distinto al esperado • Error al abrir un fichero • División por cero • Problemas de Hardware Si la excepción no se trata, el manejador de excepciones realiza lo siguiente: • Muestra la descripción de la excepción. • Muestra la traza de la pila de llamadas. • Provoca el final del programa. Página 52 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Ejemplos que provocan excepciones: Las excepciones se pueden lanzar: • • Automáticamente, cuando el sistema detecta un error Explícitamente, cuando el programador lo establezca Analicemos algunos conceptos: • • • • Lanzar: la excepción se lanza para avisar de que hay un error Propagar: la excepción se propaga de un bloque al siguiente hasta que se trata Tratar: ejecutar las instrucciones de un manejador de excepción Manejador: Instrucciones que se escriben para resolver un error Página 53 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Jerarquía de excepciones En Java, todas las excepciones están representadas por clases. Todas las clases de excepción se derivan de una clase llamada Throwable. Por lo tanto, cuando se produce una excepción en un programa, se genera un objeto de algún tipo de clase de excepción. Hay dos subclases directas de Throwable: Exception y Error: • • Las excepciones de tipo Error están relacionadas con errores que ocurren en la Máquina Virtual de Java y no en el programa. Este tipo de excepciones escapan al control del programador y, por lo general, el programa no se ocupará de ellas. Por lo tanto, este tipo de excepciones no se describirán. Los errores que resultan de la actividad del programa están representados por subclases de Exception. Por ejemplo, dividir por cero, límite de matriz y errores de archivo se ubican en esta categoría. En general, el programa debe manejar excepciones de estos tipos. Una subclase importante de Exception es RuntimeException, que se usa para representar varios tipos comunes de errores en tiempo de ejecución. Las clases predefinidas están en el paquete java.lang Página 54 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Exception • • Es la clase base de aquellas excepciones que puede lanzar un programa, por lo que es la clase que más interesa al programador. Las excepciones comprobadas/verificadas son objetos de la clase java.lang.exception o sus subclases (excepto la java.lang.RuntimeException y sus subclases). Las excepciones comprobadas se "verifican" en el momento de la compilación. Eso significa que el programador debe capturar o lanzar estas excepciones, o de lo contrario la compilación no sería exitosa (causando un error del compilador). Por ejemplo, la IOException y sus subclases son excepciones comprobadas, y cuando el programador está tratando de acceder o modificar un archivo, el compilador verifica que el programador se encargue de todas las posibles IOExceptions RuntimeException • • • Junto con sus subclases representan excepciones en tiempo de ejecución que no necesitan ser capturadas obligatoriamente, por lo tanto, se trata de excepciones no comprobadas. Ejemplos de estas excepciones son: hacer una referencia a un puntero null, acceder fuera de los límites de un array. Generalmente estas tienen que ver más con errores por parte del programador Java. Cuando este tipo de excepción sucede, se debe tratar de mantener el programa ejecutándose. Este tipo de excepciones indican un problema de diseño o implementación, por lo regular un programa que funcione bien no genera este tipo de excepciones, por lo que no es recomendable gestionarlos. De esta forma Java permite que la captura de estas excepciones sea algo opcional Las excepciones no comprobadas pertenecen a la clase Error y a sus clases derivadas y a la clase RuntimeException y sus clases derivadas. ¿Qué ocurre cuando se produce una excepción? Cuando ocurre una excepción: • • • • • La Máquina Virtual Java crea un objeto excepción y lo lanza. El objeto excepción creado contiene información sobre el error. La ejecución normal del programa se detiene. El sistema busca en el método donde se ha producido la excepción un manejador de excepciones que capture ese objeto y trate la excepción. Si el método no contiene un manejador para la excepción se busca en el método que llamó a este y así sucesivamente en toda la pila de llamadas. Cuando se encuentra un manejador apropiado se le pasa la excepción. Un manejador de excepciones es considerado apropiado si el tipo de objeto excepción lanzado es compatible al tipo que puede manejar. Si no se encuentra un manejador adecuado la Máquina Virtual Java muestra el error y acaba el programa. Manejo de Excepciones El manejo de excepciones proporciona una separación entre el código básico y el código que maneja los errores, haciéndolo más legible. Página 55 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Un programa que trate las excepciones debe realizar los siguientes pasos: 1. Se intenta ( try ) ejecutar un bloque de código. 2. Si se produce una circunstancia excepcional se lanza (throw) una excepción. En caso contrario el programa sigue su curso normal. 3. Si se ha lanzado una excepción, la ejecución del programa es desviada al manejador de excepciones donde la excepción se captura ( catch ) y se decide qué hacer al respecto. El esquema general en Java es: Bloque try: En el bloque try se encuentran las instrucciones que pueden lanzar una excepción. Solamente se pueden capturar las excepciones lanzadas dentro de un bloque try. Una excepción se puede lanzar de forma automática o mediante la palabra reservada throw. Cuando se lanza la excepción se transfiere la ejecución del programa desde el punto donde se lanza la excepción a otro punto donde se captura la excepción. Bloque catch: Es el bloque de código donde se captura la excepción. El bloque catch es el manejador o handler de la excepción. Aquí se decide qué hacer con la excepción capturada. Puede haber varios bloques catch relacionados con un bloque try. Una vez finalizado un bloque catch la ejecución no vuelve al punto donde se lanzó la excepción. La ejecución continúa por la primera instrucción a continuación de los bloques catch. Bloque finally: Es opcional. Debe aparecer a continuación de los bloques catch. También puede aparecer a continuación de un bloque try si no hay bloques catch. Página 56 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II La ejecución de sus instrucciones queda garantizada independientemente de que el bloque try acabe o no su ejecución incluso en estos casos: • Aunque el bloque try tenga una sentencia return, continue o break, se ejecutará el bloque finally • Cuando se haya lanzado una excepción que ha sido capturada por un bloque catch. El finally se ejecuta después del catch correspondiente. • Si se ha lanzado una excepción que no ha sido capturada, se ejecuta el finally antes de acabar el programa. Un bloque finally se usa para dejar un estado consistente después de ejecutar el bloque try. Un ejemplo de uso de bloques finally puede ser cuando estamos tratando con ficheros y se produce una excepción. Podemos escribir un bloque finally para cerrar el fichero. Este bloque se ejecutará siempre y se liberarán los recursos ocupados por el fichero. Ejemplo: Validar la división en cero. Página 57 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Interfaces Gráficas de Usuario (GUI) Hasta el momento desarrollamos programas que usan la consola para interactuar con el usuario. Esa forma de interfaz de usuario es muy simple y nos ha permitido centrarnos en todo aquello que tiene que ver tan sólo con la programación orientada a objetos con el lenguaje Java, sin tener que tratar al mismo tiempo con ventanas, botones y otros elementos similares. Las interfaces gráficas de usuario (GUI) ofrecen al usuario ventanas, cuadros de diálogo, barras de herramientas, botones, listas desplegables y muchos otros elementos gráficos. Las aplicaciones son conducidas por eventos y se desarrollan haciendo uso de las clases que para ello nos ofrece la API de Java. Java es un lenguaje de programación que actualmente se encuentra bajo el paraguas de la multinacional Oracle. Cuando se instala el software Java, instala un paquete completo llamado JDK el cual, además de la máquina virtual de Java y el compilador, incluye también lo que se conoce como API. La API de Java (Application Programming Interface) es una interfaz de programación de aplicaciones que consiste en un conjunto de librerías de código Java compilado o clases ofrecidas por la compañía multinacional ya listas para que sean usadas por los desarrolladores. Estas “bibliotecas de clases” son utilizadas en la gran mayoría de lenguajes orientados a objetos, facilitando así el trabajo con dichos lenguajes de programación. La API de Java presenta una inmensa cantidad y variedad de paquetes y clases, cada uno de ellos destinados a una función determinada. La API de Java proporciona dos bibliotecas de clases para crear interfaces gráficas de usuario: AWT y Swing. Tanto Swing como AWT forman parte de una colección de clases llamada JFC (Java Foundation Classes) que incluyen paquetes dedicados a la programación de interfaces gráficos (así como a la producción multimedia). Uno de los problemas frecuentes de la programación clásica era como programar interfaces de usuario, ya que esto implicaba tener que utilizar las API propias del Sistema Operativo y esto provocaba que el código no fuera transportable a otros sistemas. AWT (Abstract Window Toolkit ) fue la primera solución a este problema propuesta por Java. AWT está formada por un conjunto de clases que no dependen del sistema operativo, pero que proponen una serie de clases para la programación de GUIs. Las clases AWT se desarrollaron usando código nativo (o sea, código asociado a una plataforma concreta). Eso dificultaba la portabilidad de las aplicaciones. Al usar código nativo, para poder conservar la portabilidad era necesario restringir la funcionalidad a los mínimos comunes a todas las plataformas donde se pretendía usar AWT. Como consecuencia, AWT es una librería con una funcionalidad muy pobre. La estructura básica de la librería gira en torno a componentes y contenedores. Los contenedores contienen componentes y son componentes a su vez, de forma que los eventos pueden tratarse tanto en contenedores como en componentes. Más tarde, cuando apareció Java 2 surgió una librería más robusta, versátil y flexible: Swing. AWT aún sigue estando disponible, de hecho se usa por los componentes de Swing. Página 58 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Principales componentes AWT AWT es adecuada para interfaces gráficas sencillas, pero no para proyectos más complejos. Entonces: • • AWT: es una biblioteca pesada, presenta componentes pesados, que en cada plataforma sólo pueden tener una representación determinada. Está disponible desde la versión 1.1 del JDK como java.awt. Swing: es una biblioteca ligera, presenta componentes ligeros, que pueden tomar diferente aspecto y comportamiento pues lo toman de una biblioteca de clases. Está disponible desde la versión 1.2 del JDK como javax.swing La idea de pesada o ligera, está relacionada con la dependencia de Java con el sistema operativo, para visualizar y gestionar los elementos de la GUI En el caso de AWT, la creación, visualización y gestión de los elementos gráficos depende del SO. Es el propio SO quien dibuja y gestiona la interacción sobre los elementos. En el caso de Swing, es Java quien visualiza y gestiona la interacción del usuario sobre los elementos de la interfaz gráfica. Ejemplo de una aplicación en Windows con AWT Página 59 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Ejemplo de una aplicación en Windows con Swing Como puede observarse, al utilizar AWT el aspecto de los componentes depende del SO sobre el que se ejecute la aplicación. AWT sigue siendo imprescindible, ya que todos los componentes Swing se construyen haciendo uso de clases de AWT. AWT fue la primera forma de construir las ventanas en Java, pero: • • • limitaba la portabilidad, restringía la funcionalidad y requería demasiados recursos. Swing Swing es una librería de Java para la generación del GUI en aplicaciones. Swing se apoya sobre AWT y añade JComponents. La arquitectura de los componentes de Swing facilita la personalización de apariencia y comportamiento, si lo comparamos con los componentes AWT. Página 60 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Componentes de Swing Página 61 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Página 62 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Página 63 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Página 64 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Por cada componente AWT (excepto Canvas) existe un componente Swing equivalente, cuyo nombre empieza por J, que permite más funcionalidad siendo menos pesado. Así, por ejemplo, para el componente AWT Button existe el equivalente Swing JButton, que permite como funcionalidad adicional la de crear botones con distintas formas (rectangulares, circulares, etc), incluir imágenes en el botón, tener distintas representaciones para un mismo botón según esté seleccionado, o bajo el cursor, etc. La razón por la que no existe JCanvas es que los paneles de la clase JPanel ya soportan todo lo que el componente Canvas de AWT soportaba. No se consideró necesario añadir un componente Swing JCanvas por separado. Algunas características más de Swing, podemos mencionar: • • • • Es independiente de la arquitectura (metodología no nativa propia de Java) Proporciona todo lo necesario para la creación de entornos gráficos, tales como diseño de menús, botones, cuadros de texto, manipulación de eventos, etc. Los componentes Swing no necesitan una ventana propia del sistema operativo cada uno, sino que son visualizados dentro de la ventana que los contiene mediante métodos gráficos, por lo que requieren bastantes menos recursos. Las clases Swing están completamente escritas en Java, con lo que la portabilidad es total, a la vez que no hay obligación de restringir la funcionalidad a los mínimos comunes de todas las plataformas Página 65 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II • • Por ello las clases Swing aportan una considerable gama de funciones que haciendo uso de la funcionalidad básica propia de AWT aumentan las posibilidades de diseño de interfaces gráficas. Aunque todos los componentes Swing derivan de componentes AWT y de hecho se pueden mezclar en una misma aplicación componentes de ambos tipos, se desaconseja hacerlo. Es preferible desarrollar aplicaciones enteramente Swing, que requieren menos recursos y son más portables. Eventos Los Eventos son las acciones sobre el programa. Normalmente, llamamos evento a cualquier interacción que realiza el usuario con la aplicación, como puede ser: • • • • • • • pulsar un botón con el ratón, hacer doble clic, pulsar y arrastrar, pulsar una combinación de teclas en el teclado, pasar el ratón por encima de un componente, salir el puntero de ratón de un componente, abrir una ventana, etc. Programación guiada por eventos Imagina la ventana de cualquier aplicación, por ejemplo, la de un procesador de textos. En esa ventana aparecen multitud de elementos gráficos interactivos, de forma que no es posible que el programador haya previsto todas las posibles entradas que se pueden producir por parte del usuario en cada momento. Con el control de flujo de programa de la programación imperativa, el programador tendría que estar continuamente leyendo las entradas (de teclado, o ratón, etc) y comprobar para cada entrada o interacción producida por el usuario, de cual se trata de entre todas las posibles, usando estructuras de flujo condicional (if then‐else, switch) para ejecutar el código conveniente en cada caso. Si piensas que para cada opción del menú, para cada botón o etiqueta, para cada lista desplegable, y por tanto para cada componente de la ventana, incluyendo la propia ventana, habría que comprobar todos y cada uno de los eventos posibles, nos damos cuenta de que las posibilidades son casi infinitas, y desde luego impredecibles. Por tanto, de ese modo es imposible solucionar el problema. Para abordar el problema de tratar correctamente las interacciones del usuario con la interfaz gráfica de la aplicación hay que cambiar de estrategia, y la programación guiada por eventos es una buena solución, veamos cómo funciona el modelo de gestión de eventos. Modelo de gestión de eventos Hoy en día, la mayoría de los sistemas operativos utilizan interfaces gráficas de usuario. Este tipo de sistemas operativos están continuamente monitorizando el entorno para capturar y tratar los eventos que se producen. El sistema operativo informa de estos eventos a los programas que se están ejecutando y entonces cada programa decide, según lo que se haya programado, qué hace para dar respuesta a esos eventos. Página 66 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Cada vez que el usuario realiza una determinada acción sobre una aplicación que estamos programando en Java, un clic sobre el ratón, presionar una tecla, etc, se produce un evento que el sistema operativo transmite a Java. Java crea un objeto de una determinada clase de evento, y este evento se transmite a un determinado método para que lo gestione. El modelo de eventos de Java está basado en delegación, es decir, la responsabilidad de gestionar un evento que ocurre en un objeto fuente la tiene otro objeto oyente. Fuente: La Fuente del evento (event sources) es el objeto en el que ocurre un evento y la fuente es responsable de enviar información sobre el evento al controlador de eventos. Ejemplos: − Botón sobre el que se realiza un clic. − Campo de texto que pierde el foco. − Campo de texto sobre el que se presiona una tecla. − Ventana que se cierra. − Etc. Oyente/Escuchador/Listener: El oyente no es más que el controlador de eventos responsable de realizar una acción cuando ocurre un evento. En Java, un oyente es un objeto que espera un evento. Una vez que ocurre el evento, el oyente procesa el evento. El requisito es registrar al oyente con el objeto para que cuando ocurra un evento, el oyente pueda procesarlo. Entonces en Java Swing, cada vez que el usuario interactúa con la aplicación se dispara un evento. Para que un componente determinado reaccione frente a un evento, debe poseer un "escuchador" (Listener) con, al menos, un método determinado que se ejecutará al escuchar un evento en particular, por ejemplo, en el siguiente código se dispone de un botón que al ser presionado imprime en un mensaje. Ejemplo: a) Creamos un proyecto nuevo con un JFrame, en el cual incorporamos los controles: Jlabel, JTextField, JButtom. También asignamos un nombre a los 2 últimos controles. Página 67 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II b) Agregamos la funcionalidad al botón, hacemos doble clic sobre el botón y de manera automática NetBeans genera el siguiente código Escribimos la funcionalidad deseada, en este ejemplo, recuperamos el nombre ingresado en el componente JTextField y mostramos un mensaje de saludo. La aplicación en ejecución es: Se puede observar que hay asociado un escuchador de eventos (Listener), es decir, un ActionListener al botón. Esto fue generado automáticamente por NetBeans. Página 68 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II El escuchador es simplemente un programa que permanece activo, en ejecución en segundo plano, de forma paralela a la aplicación. Se encarga exclusivamente de comprobar si se ha producido algún evento del tipo que él sabe escuchar sobre el componente al que se ha añadido. En el caso del botón de acción, el ActionListener se encarga de comprobar si se ha producido algún evento del tipo ActionEvent (evento de acción, como realizar un clic) sobre el botón. En el momento que el escuhador “esucha” o intercepta un evento de ese tipo, lo captura, y pasa el control del flujo de nuestra aplicación al Controlador del componente al que está asociado. El controlador no es más que el código que el programador ha escrito para que se ejecute cuando se produce exactamente ese evento sobre ese componente. Este código recibe del listener además del control, un parámetro que es un objeto Evento del tipo del evento escuchado por el oyente. En el caso del botón de acción, se transfiere el control al método actionPerformed() definido por el programador, pasándole como parámetro el objeto evento del tipo ActionEvent que se ha producido. El método actionPerformed() contiene todas las sentencias que deben ejecutarse. Cuando el usuario interactúa sobre diversos componentes gráficos, éstos generan eventos. La siguiente tabla muestra los eventos que algunos componentes pueden generar y cuándo los genera. Acción Pulsar un botón Cambio del texto Pulsar Enter en un campo de texto Selección de un nuevo elemento Selección de elemento(s) Objeto JButton JTextComponent Tipo de Evento ActionEvent TextEvent JTextField ActionEvent JCombobox ItemEvent ActionEvent ListSelectionEvent JList Página 69 Universidad Tecnológica Nacional – Facultad Regional Tierra del Fuego Tecnicatura Superior en Programación – Programación II Pulsar una casilla de verificación JCheckBox ItemEvent ActionEvent Pulsar un botón de radio JRadioButton Selección de una opción de menú JMenuItem ItemEvent ActionEvent ActionEvent Mover la barra de desplazamiento JScrollBar AdjustmentEvent Abrir, cerrar, minimizar, maximizar o cerrar la ventana JWindow WindowEvent A continuación, se listan algunas interfaces que deben implementarse cuando para procesar algunos de estos eventos. Algunas interfaces y sus métodos son: Interfaz ActionListener Escucha eventos de tipo ActionEvent KeyListener Escucha eventos de MouseListener Escucha eventos (botones) de MouseMotionListener Escucha eventos de acción movimiento Método actionPerformed(ActionEvent) teclado del del ratón ratón keyPressed(KeyEvent) keyReleased(KeyEvent) keyTyped(KeyEvent) mouseClicked(MouseEvent) mouseEntered(MouseEvent) mouseExited(MouseEvent) mousePressed(MouseEvent) mouseReleased(MouseEvent) mouseDragged(MouseEvent) mouseMoved(MouseEvent) Página 70