Download Gracias… A Dios por la vida misma, por haberme dado la

Document related concepts
no text concepts found
Transcript
Agradecimientos
Gracias…
A Dios por la vida misma, por haberme dado la capacidad de pensar y porque me
ha permitido llegar sano a este momento.
A mis padres por haberme dado la vida, porque gran parte de lo que soy se lo
debo a ellos y porque todas sus enseñanzas han sido la base para llegar hasta
aquí.
A todos mis hermanos porque muchos de sus actos me han servido como
ejemplo para terminar este proceso, por su apoyo incondicional y porque siempre
han creído en mi.
A mi asesora por su sabiduría, asesoría y paciencia durante todo el proceso.
A mis revisores por su disposición, porque su valioso aporte ayudo a realizar un
trabajo mejor y mas completo.
A mis compañeros y amigos que han creído en mi.
Contenido tematico
INDICE
CONTENIDO DE FIGURAS ................................................................................................. 5
INTRODUCCION ................................................................................................................ 6
UNIDAD I. ARREGLOS UNIDIMENSIONALES Y MULTIDIMENSIONALES ......................... 7
1.1 Arreglos Unidimensionales (Listas) .................................................................................... 8
1.1.1 Conceptos básicos..................................................................................................... 8
1.1.2 Operaciones............................................................................................................ 11
1.1.3 Aplicaciones............................................................................................................ 15
1.2 Arreglos Bidimensionales ................................................................................................ 17
1.2.1 Conceptos básicos.................................................................................................. 17
1.2.2 Operaciones............................................................................................................ 19
1.2.3 Aplicaciones............................................................................................................ 26
1.3 Arreglos multidimensionales ........................................................................................... 29
1.3.1 Conceptos básicos................................................................................................... 29
1.3.2 Aplicaciones............................................................................................................ 30
1.4 Ejercicios resueltos......................................................................................................... 32
1.5 Ejercicios propuestos...................................................................................................... 34
UNIDAD II. MÉTODOS Y MENSAJES ............................................................................... 36
2.1 Atributos Const y Static .................................................................................................. 37
2.2 Concepto de método ...................................................................................................... 37
2.3 Declaración de Métodos ................................................................................................. 38
2.4 Llamadas a Métodos ...................................................................................................... 39
2.5 Tipos de Métodos........................................................................................................... 40
2.5.1 Métodos Estáticos o de Clase ................................................................................... 40
2.5.2 Métodos Normales .................................................................................................. 43
2.6 Referencia this .............................................................................................................. 44
2.7 Forma de Pasar Argumentos........................................................................................... 45
2.8 Devolver un valor desde un método ................................................................................ 48
2.9 Estructura del Código ..................................................................................................... 51
2.10 Ejercicios Resueltos:..................................................................................................... 51
2.11 Ejercicios propuestos:................................................................................................... 54
UNIDAD III. CONSTRUCTOR, DESTRUCTOR (RECOLECTOR DE BASURA)...................... 56
3.1 Concepto de método constructor .................................................................................... 57
3.2 Recolector de basura (garbage collector)......................................................................... 57
3.3 Declaración de métodos constructores ............................................................................ 59
3.4 Aplicaciones de constructores y destructores (Recolectores de basura) ............................. 60
3.5 Tipos de Métodos Constructores y Destructores (Recolectores de Basura) ......................... 63
3.6 Ejercicios propuestos...................................................................................................... 69
UNIDAD IV. SOBRECARGA .............................................................................................. 70
4.1 Conversión de Tipos....................................................................................................... 71
4.2 Sobrecarga de Métodos .................................................................................................. 76
4.3 Sobrecarga de Operadores ............................................................................................ 83
4.4. Ejercicios resueltos........................................................................................................ 84
4.5 Ejercicios Propuestos...................................................................................................... 87
UNIDAD V. HERENCIA..................................................................................................... 88
5.1 Introducción a la Herencia.............................................................................................. 89
5.2 Herencia Simple............................................................................................................. 90
5.3 Herencia Múltiple ........................................................................................................... 94
5.4 Clase Base y Clase Derivada .......................................................................................... 94
5.4.1 Definición de la Clase Base ..................................................................................... 94
5.4.2 Definición de Clase Derivada.................................................................................... 95
Programación orientada a objetos en Java
Contenido tematico
5.5 Parte Protegida.............................................................................................................. 96
5.5.1 Propósito de la Parte Protegida ................................................................................ 96
5.6 Redefinición de los miembros de las clases derivadas....................................................... 97
5.7 Clases Virtuales y Visibilidad ........................................................................................... 98
5.8 Constructores en Clases Derivadas.................................................................................. 98
5.9 Aplicaciones................................................................................................................... 99
5.10 Ejercicios propuestos...................................................................................................110
UNIDAD VI. POLIMORFISMO Y REUTILIZACION ......................................................... 112
6.1 Concepto de polimorfismo .............................................................................................113
6.2 Clases abstractas ..........................................................................................................116
6.2.1 Definición ..............................................................................................................116
6.2.2 Redefinición...........................................................................................................118
6.3 Definición de una Interfaz .............................................................................................120
6.4 Implementación de la Definición de una Interfaz.............................................................121
6.5 Reutilización de la definición de una Interfaz ..................................................................123
6.6 Definición y Creación de Paquetes..................................................................................129
6.7 Reutilización de las clases de un Paquete / Librería .........................................................132
6.8 Clases Genéricas (Plantillas) .........................................................................................134
6.9 Ejercicios Resueltos.......................................................................................................134
6.10 Ejercicios Propuestos...................................................................................................139
UNIDAD VII. EXCEPCIONES.......................................................................................... 140
7.1 Definición .....................................................................................................................141
7.1.1 ¿Qué son las Excepciones? .....................................................................................141
7.1.2 Clases de Excepciones Predefinidas por el Lenguaje .................................................142
7.1.3 Propagación de Excepciones ...................................................................................146
7.2 Gestión de Excepciones .................................................................................................147
7.2.1 Manejo de Excepciones ..........................................................................................148
7.2.1 Lanzamiento de Excepciones ..................................................................................152
7.3 Excepciones Definidas por el Usuario .............................................................................155
7.3.1 Clase Base de las Excepciones ................................................................................155
7.3.2. Creación de una Clase Derivada del Tipo Excepción.................................................157
7.3.3 Manejo de una Excepción Definida por el Usuario.....................................................159
7.4 Ejercicios resueltos........................................................................................................160
7.5 Ejercicios propuestos: ...................................................................................................163
UNIDAD 8.FLUJOS Y ARCHIVOS ................................................................................... 164
8.1 Definición de archivos de texto y Archivos Binarios .........................................................165
8.2 Operaciones Básicas en Archivos de Texto y Binario........................................................166
8.2.1 Crear.....................................................................................................................166
8.2.2 Abrir......................................................................................................................166
8.2.3 Cerrar....................................................................................................................167
8.2.4 Lectura y Escritura .................................................................................................167
8.2.5 Recorrer ................................................................................................................177
8.3 Aplicaciones..................................................................................................................178
8.4 Ejercicios propuestos.....................................................................................................183
CONCLUSIONES ............................................................................................................ 184
ANEXO I. INTRODUCCIÓN AL LENGUAJE JAVA ............................................................ 185
1.1 Introducción .................................................................................................................186
1.2 Características de Java ..................................................................................................186
1.2.1 Simple ...................................................................................................................186
1.2.2 Orientado a Objetos ...............................................................................................187
1.2.3 Distribuido .............................................................................................................187
1.2.4 Robusto.................................................................................................................187
1.2.5 Seguro ..................................................................................................................187
Programación orientada a objetos en Java
3
Contenido tematico
1.2.6 Portable.................................................................................................................187
1.2.7 Arquitectura Neutral ...............................................................................................187
1.2.8 Rendimiento medio ................................................................................................188
1.2.9 Multithread ............................................................................................................188
1.3 Java frente a los demás lenguajes..................................................................................188
1.4 Como Compilar y Ejecutar Programas en Java ................................................................190
1.4.1 Javac.....................................................................................................................190
1.4.2 Java ......................................................................................................................190
1.4.3 Appletviewer..........................................................................................................190
1.5 Estructuras de Datos Básicas en Java .............................................................................191
1.5.1 Tipos de Datos.......................................................................................................191
1.5.2 Enteros..................................................................................................................191
1.5.3 Tipos de Datos Enteros en Java ..............................................................................192
1.5.4 Tipos de Datos Reales en Java................................................................................192
1.5.5 Caracteres .............................................................................................................192
1.5.6 Boolean .................................................................................................................193
1.5.7 Variables ...............................................................................................................193
1.6 Entornos de Desarrollo de Java......................................................................................194
1.6.1 Bluej .....................................................................................................................194
1.6.2 Jcreator .................................................................................................................194
1.6.3 Jbuilder .................................................................................................................195
1.6.4 Netbeans ...............................................................................................................195
1.6.5 Eclipse...................................................................................................................195
ANEXO II. EL ENTORNO DE DESARROLLO ECLIPSE ..................................................... 197
2.1. ¿Que es Eclipse? ..........................................................................................................197
2.2. Trabajando con Eclipse ................................................................................................197
2.2.1. Creación de un proyecto........................................................................................197
2.2.2. Creando clases......................................................................................................198
2.2.3. Ejecutando el programa ........................................................................................199
2.2.4. Depuración de programas......................................................................................199
2.2.5. Otras herramientas interesantes. ...........................................................................200
BIBLIOGRAFIA .............................................................................................................. 207
Programación orientada a objetos en Java
4
Indice de figuras
CONTENIDO DE FIGURAS
Figura 1: Arreglo de 12 elementos ............................................................................................ 11
Figura 2: Ordenamiento de los elementos de un arreglo usando el método de la burbuja ............ 12
Figura 3: Proceso completo del ordenamiento del arreglo .......................................................... 13
Figura 4: Ilustración de los arreglos bidimensionales.................................................................. 17
Figura 5: Ilustración de arreglos bidimensionales (2). ................................................................ 18
Figura 6: Un arreglo de tres dimensiones (4 x 5 x 3).................................................................. 29
Figura 7: Las 36 posibles sumas de los dados............................................................................ 35
Figura 8: El recolector de basura de Java funciona determinando los objetos que son alcanzables.58
Figura 9: Clase bicicleta ........................................................................................................... 90
Figura 10: Ilustración del polimorfismo. ...................................................................................113
Figura 11: Polimorfismo y reutilización .....................................................................................114
Figura 12 Ilustración de la herencia .........................................................................................115
Figura 13 Jerarquía de las clases de excepciones......................................................................142
Figura 14: Propagación de excepciones....................................................................................146
Figura 15 Manejo de Excepciones. ...........................................................................................148
Figura 16: Clase base de la clase Throwable. ...........................................................................156
Figura 17: Primera pantalla de Eclipse .....................................................................................200
Figura 18: Selección del tipo de proyecto en Eclipse .................................................................201
Figura 19: Datos sobre el proyecto en Eclipse ..........................................................................201
Figura 20: Creación de una clase en Eclipse .............................................................................202
Figura 21: Creación de un fichero vació en Eclipse....................................................................202
Figura 22: La perspectiva Java con las vistas mostrando una clase en Eclipse ............................203
Figura 23: Configuración para ejecutar la aplicación: proyecto y clase con el main en Eclipse......203
Figura 24: Argumentos para enviar al programa y argumentos para enviar a la Maquina Virtual en
Eclipse ...................................................................................................................................204
Figura 25: Consola con el resultado de la ejecución en Eclipse. .................................................204
Figura 26: Barra de Herramientas de Eclipse. ...........................................................................205
Figura 27: La perspectiva debug en Eclipse. .............................................................................205
Figura 28: La perspectiva debug en acción en Elipse.................................................................206
Figura 29: Asistente de código (pulsando Ctrl + espacio) en Eclipse. .........................................206
Programación orientada a objetos en Java
Introducción
INTRODUCCION
Actualmente una de las áreas más candentes en la industria y en el ámbito
académico es la orientación a objetos. La orientación a objetos promete mejoras de
amplio alcance en la forma de diseño, desarrollo y mantenimiento del software ofreciendo
una solución a largo plazo a los problemas y preocupaciones que han existido desde el
comienzo en el desarrollo de software: la falta de portabilidad del código y reusabilidad,
código que es difícil de modificar, ciclos de desarrollo largos y técnicas de codificación no
intuitivas.
Un lenguaje orientado a objetos ataca estos problemas. Tiene tres características
básicas: debe estar basado en objetos, basado en clases y capaz de tener herencia de
clases. Muchos lenguajes cumplen uno o dos de estos puntos; muchos menos cumplen los
tres. La barrera más difícil de sortear es usualmente la herencia.
En un principio eran muy pocos los lenguajes de programación que atacaban los
tres problemas anteriores. Como una solución a eso, nace Java. Java es un lenguaje de
programación con el que se puede realizar cualquier tipo de programa. En la actualidad es
un lenguaje muy extendido y cada vez cobra más importancia tanto en el ámbito de
Internet como en la informática en general. Está desarrollado por la compañía Sun
Microsystems con gran dedicación y siempre enfocado a cubrir las necesidades
tecnológicas más punteras.
Una de las principales características por las que Java se ha hecho muy famoso es
que es un lenguaje independiente de la plataforma. Eso quiere decir que si hacemos un
programa en Java podrá funcionar en cualquier ordenador del mercado. Es una ventaja
significativa para los desarrolladores de software.
Actualmente Java se utiliza en un amplio abanico de posibilidades y casi cualquier
cosa que se puede hacer en cualquier lenguaje se puede hacer también en Java y muchas
veces con grandes ventajas.
El presente material es un libro de texto que sirve como herramienta importante de
apoyo para la materia de Programación orientada a objetos (POO) basada en el lenguaje
de programación java.
Dicho material se compone de ocho unidades, más dos anexos; una de
introducción al lenguaje de programación java y la otra de Eclipse uno de los entornos de
desarrollo mas usados en dicho lenguaje. Además cada una de las unidades contiene un
apartado de ejercicios resueltos y ejercicios propuestos para que el lector pueda practicar
los conocimientos adquiridos.
Cada uno de los temas de las unidades se desarrolló en base a dos o más autores
para que el lector pueda comparar y elegir el enfoque que considere más apropiado de
acuerdo a su opinión personal.
Programación orientada a objetos en Java
6
Unidad I. Arreglos unidimensionales y multidimensionales
UNIDAD I. ARREGLOS UNIDIMENSIONALES Y
MULTIDIMENSIONALES
Conceptos básicos, operaciones y aplicaciones con arreglos
Programación orientada a objetos en Java
7
Unidad I. Arreglos unidimensionales y multidimensionales
Unidad 1. Arreglo Unidimensional Y Multidimensional
1.1 Arreglos Unidimensionales (Listas1)
1.1.1 Conceptos básicos
Definición de un arreglo unidimensional (vectores)
En java, un arreglo unidimensional es un grupo de variables (llamadas elementos o
componentes) que contienen valores del mismo tipo. Los arreglos son objetos, por lo que
se consideran como tipos de referencia. Los elementos de un arreglo en java pueden ser
tipos primitivos2 o de referencias (incluyendo arreglos). Para hacer referencia a un
elemento específico en un arreglo se debe especificar el nombre de la referencia al arreglo
y el número de la posición del elemento en el arreglo. El número de posición del elemento
se conoce formalmente como el índice o subíndice del elemento en el arreglo. Todos los
elementos de un arreglo deben ser del mismo tipo.
Declaración y creación de arreglos Unidimensionales
Para crear un arreglo, antes hay que crear una variable de arreglo del tipo deseado. La
forma general de un arreglo unidimensional es:
Tipo nombre-de-variable[ ];
Los objetos arreglo ocupan espacio en memoria. Todos los objetos en java deben de
crearse con la palabra clave new 3. El programador especifica el tipo de cada elemento y el
número de elementos que se requieren para el arreglo.
La siguiente declaración crea 12 elementos para el arreglo de enteros de nombre c:
int c[] = new int[12];
Esta tarea también puede realizarse en dos pasos, como se muestra a continuación:
int c[];
//declara la variable arreglo
c = new int [12]; //crea el arreglo
Al crear un arreglo cada uno de sus elementos recibe un valor predeterminado de
cero para los elementos numéricos de tipos primitivos, falso para los elementos boléanos y
nulo para las referencias (cualquier tipo no primitivo).
Vectores
Tipo primitivo son las variables propias del lenguaje, p. e. char, int, boolean, y float.
3
El operador new se utiliza en Java para la creación de objetos.
1
2
Programación orientada a objetos en Java
8
Unidad I. Arreglos unidimensionales y multidimensionales
En la tabla 1.1.1, se muestra los diferentes valores de inicialización para cada uno
de los tipos de variable:
Tipo de elemento
byte
Valor inicial
0
int
0
float
0.0f
char
‘\u0000’
referencia a objeto
nulo
short
0
long
0L
double
0.0d
boolean
falso
Tabla 1.1 Diferentes valores de inicialización para cada tipo de variable
Si se quiere inicializar un arreglo de valores diferente a los que se muestran en la tabla
anterior, se puede combinar, la declaración, construcción e inicialización en un sólo paso.
La siguiente línea de código inicializa un arreglo de 5 flotantes:
float[] diametros = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f};
Se pueden crear varios arreglos en una sola declaración. La siguiente declaración de
un arreglo String reserva 100 elementos para b y 27 para x:
String b[] = new String [100], x[] = new String [27];
Al declararse un arreglo, su tipo y los corchetes pueden combinarse al principio de
las declaraciones para indicar que todos los identificadores en la declaración son
referencias a arreglos. Por ejemplo:
double[] arreglo1, arreglo2;
En la línea anterior se declara el arreglo1 y arreglo2 como referencias a arreglos de
valores double. Como se vio anteriormente, la declaración y creación del arreglo pueden
combinarse en la declaración. La siguiente declaración reserva 10 elementos para el
arreglo1 y 20 para el arreglo2 de tipo double:
double[] arreglo1 = new double[10], arreglo2 = new double[20];
Programación orientada a objetos en Java
9
Unidad I. Arreglos unidimensionales y multidimensionales
Un programa puede declarar arreglos de cualquier tipo. Todo elemento de un
arreglo de tipo primitivo es una variable del tipo declarado del arreglo. Por ejemplo, cada
uno de los elementos de un arreglo int es una variable int. En un arreglo que sea de tipo
de referencia, cada elemento del arreglo es una referencia a un objeto del tipo declarado
de ese arreglo. Cada uno de los elementos de un arreglo String es una referencia a un
objeto String.
En la figura 1 se muestra una representación lógica de un arreglo de enteros
llamado c, este arreglo contiene 12 elementos (es decir variables). Un programa puede
hacer referencia a cualquiera de estos elementos mediante una expresión de acceso a un
arreglo que incluye el nombre del arreglo, seguido por el índice del elemento especifico
encerrado entre corchetes ([]). El primer elemento en cualquier arreglo tiene el índice cero
(lo que se denomina como elemento cero) 4. Por lo tanto, el primer elemento del arreglo c
es c[0], el segundo elemento es c[1], el séptimo elemento del arreglo es c[6] y, en
general, el i-esimo elemento del arreglo c es[c-i]. Los nombres de los arreglos siguen las
mismas convenciones, que los demás nombres de las variables.
Un índice debe ser un entero positivo o una expresión entera que pueda
promoverse a un int. Si un programa utiliza una expresión como índice, el programa
evalúa la expresión para determinar el índice. Por ejemplo supóngase que la variable a es
5 y que b es 6, entonces la instrucción: C [ a + b ] += 2; suma 2 al elemento c[11] del
arreglo. Obsérvese que el nombre del arreglo con subíndice es una expresión de acceso al
arreglo. Dichas expresiones pueden utilizarse en el lado izquierdo de una asignación, para
colocar un nuevo valor en un elemento del arreglo.
4
En Java todos los Arreglos siempre empiezan con en el subíndice 0.
Programación orientada a objetos en Java
10
Unidad I. Arreglos unidimensionales y multidimensionales
Figura 1: Arreglo de 12 elementos
1.1.2 Operaciones
Ejemplo: Imprimir Elementos del Arreglo
Para imprimir, se recorre el arreglo con un ciclo for desde la posición 0 hasta a.length5 - 1.
Además, se imprime la palabra "Arreglo" y luego se subraya. Por lo tanto con el ciclo, se
imprime cada elemento almacenado en a[i].
Código 1.2.1. Imprime los valores de un arreglo de 10 elementos.
Ordenar Elementos del Arreglo
5
Esta propiedad contiene el tamaño del arreglo.
Programación orientada a objetos en Java
11
Unidad I. Arreglos unidimensionales y multidimensionales
Para ordenar el arreglo, se usará el algoritmo de la burbuja 6 que consiste en ir
comparando el elemento i con i + 1 del arreglo, para ordenar en forma ascendente.
Si se encuentra que a[i] es mayor que a[i+1], se intercambian dichos elementos.
Código 1.1.2.2. Ordena los elementos de un arreglo y después los imprime
ya ordenados
Por ejemplo, al ejecutar el ciclo for(i = 0 ...) se encuentra que hay que cambiar de
posición los elementos "Peru" y "Bolivia". Para realizar este cambio, se lleva a cabo las tres
instrucciones que muestra en la figura 2.
Figura 2: Ordenamiento de los elementos de un arreglo usando el método de la burbuja
Ahora bien, además se tiene que aplicar el ciclo for, tantas veces como elementos tenga el
arreglo, ya que en el peor caso los elementos podrían estar ordenados en forma
descendente. Es para eso que se implementa el ciclo for con el índice k.
En la figura 3, se muestra el estado del arreglo, y los valores de los índices i y k.
6
También conocido como bubblesort
Programación orientada a objetos en Java
12
Unidad I. Arreglos unidimensionales y multidimensionales
Figura 3: Proceso completo del ordenamiento del arreglo
Comparación de Strings7
Para comparar Strings (lexicográficamente) no se puede usar el operador de igualdad 8
==. Para comparar dos strings se ocupa el método int compareTo(String str) de la clase
String de la siguiente manera :
Funcionamiento de la función compare
Sean a y b objetos de tipo String.
La instrucción: a.compareTo(b)
1) retorna un valor menor que cero si a es menor que b
2) retorna un valor mayor que cero si a es mayor que b
3) retorna 0 (cero) si b es igual que a
En el siguiente ejemplo, se recorre el arreglo, comparando el String pasado como
parámetro con cada a[i]. Inicializa una variable p en -1, asumiendo que el String no se va
7
8
Cadenas
El operador = = sólo se utiliza para la comparación de números
Programación orientada a objetos en Java
13
Unidad I. Arreglos unidimensionales y multidimensionales
a encontrar. Si durante el ciclo se encuentra, se asigna a p la posición correspondiente (i)
y se ejecuta la instrucción break9 para no seguir buscando.
Código 1.1.2.3. Función que busca un carácter en una cadena, retorna -1
si no la encuentra o la posición si la encuentra.
Contar los elementos del Arreglo
El método char charAt(int indice) de la clase String, retorna el
caracter ( de tipo char) i-ésimo de un string.
String temp = "DEA"
temp.charAt(0) --> 'D'
temp.charAt(1) --> 'E'
temp.charAt(2) --> 'A'
temp.length( ) --> 3 (número de caracteres)
Para recorrer la cadena carácter por carácter se usa:
for(i = 0; i < temp.length( ) ; i++ )
Realizando la comparación (temp.charAt(i) == c) se va verificando si se cumple la
condición.
Si esto ocurre, el contador cont se incrementa en 1.
Ahora, como hay que recorrer todo el arreglo en busca del carácter, se recorre el arreglo
con un ciclo for(k = 0...), y dentro de este ciclo, se asigna a temp, el valor de a[k].
9
La sentencia break se utiliza para finalizar un ciclo.
Programación orientada a objetos en Java
14
Unidad I. Arreglos unidimensionales y multidimensionales
Código 1.1.2.4. Función que cuenta las veces que un carácter se encuentra
en una cadena.
1.1.3 Aplicaciones
Ejemplo 1
Ejemplo de una declaración de un arreglo unidimensional. En un arreglo llamado “arreglo”
se almacena cantidad de días que tienen los doce meses del año.
Código 1.1.3.1.declaración e inicialización de un arreglo.
Cuando se ejecuta el programa, imprime el número de días de abril. Ya se menciono que
los índices de arreglo en Java comienzan con cero, de manera que el número de días del
mes de abril es month_days[3] = 30.
La declaración de una variable arreglo se puede combinar con la reserva de
memoria para el propio arreglo, como se ve aquí.
Programación orientada a objetos en Java
15
Unidad I. Arreglos unidimensionales y multidimensionales
int dias_mes[] = new int[12];
Esta es la forma de declarar arreglos en Java. Los arreglos también pueden
inicializarse cuando se declaran. Un inicializador de arreglo es una lista de expresiones
entre llaves y separadas por comas, que separan los valores de los elementos del arreglo.
Automáticamente se creará un arreglo suficientemente grande para contener el número
de elementos que se haya especificado en el inicializador del arreglo. No es necesario
utilizar new.
Ejemplo 2. Versión mejorada del programa anterior:
Código 1.1.3.2. Versión mejorada del programa anterior.
Al ejecutar este programa, se listara misma salida que la que se genero la versión
anterior.
Java comprueba estrictamente que no se almacenan o se reverencien valores que
están fuera del rango del arreglo de forma accidental10. El sistema de interpretación de
Java, revisa el valor de cada índice dentro de dias_mes para asegurarse de que están
comprendidos entre 0 y 11. Si se intenta acceder a los elementos que están fuera de
rango del arreglo (números negativos o número mayores al rango del arreglo) se
provocará un error en el momento de la ejecución.
Ejemplo 3. Aquí se tiene otro ejemplo que utiliza un arreglo unidimensional, y donde se
calcula la media de un conjunto de números.
Código 1.1.3.3. Calcula e imprime la media de cinco valores.
10
Es una de las características por las que Java sobresale con respecto a otros lenguajes de programación.
Programación orientada a objetos en Java
16
Unidad I. Arreglos unidimensionales y multidimensionales
Al ejecutarse el programa anterior arrojara el valor promedio de los cinco números
contenidos en el arreglo números.
1.2 Arreglos Bidimensionales
1.2.1 Conceptos básicos
Definición de Arreglos Bidimensionales
Se define como un conjunto de datos del mismo tipo organizados en dos o más
columnas y uno o más renglones, es decir es una matriz o una tabla. Los arreglos con dos
dimensiones se utilizan a menudo para representar tablas de valores, que constan de
información ordenada en filas y columnas. Para identificar un elemento especifico de una
tabla, se deben especificar los índices. Por convención, el primer índice indica la fila del
elemento y el segundo, su columna. En Java los arreglos bidimensionales son arreglos de
arreglos. Como era de esperarse, se parecen y actúan como los arreglos
multidimensionales.
Cuando un arreglo tiene dos dimensiones, hay mas en lo que se tiene que pensar.
Considérese esta declaración e inicialización:
int[][] mints = new int[3][4]
Es natural asumir que mints contiene 12 enteros e imaginarlos organizados dentro
de columnas y renglones, como se muestran en la tabla 1.2.1.
1
91
2001
2
92
2002
3
93
2003
4
94
2004
Tabla 1.2.1. Manera incorrecta de pensar acerca de arreglos
multidimensionales.
Realmente la tabla, esta desencaminada, mints es realmente un arreglo con tres
elementos. Cada elemento es una referencia a un arreglo conteniendo 4 enteros, como se
muestra en la figura 4.
Figura 4: Ilustración de los arreglos bidimensionales.
Programación orientada a objetos en Java
17
Unidad I. Arreglos unidimensionales y multidimensionales
Los arreglos subordinados en una bidimensión no tienen que ser todos de la misma
longitud. Es posible crear un arreglo como el que se muestra en la figura 5.
Figura 5: Ilustración de arreglos bidimensionales (2).
La figura 5 muestra un arreglo donde hay elementos de un arreglo de 3 enteros,
un arreglo de 4 enteros y un arreglo de 2 enteros. Tal arreglo puede ser creado con la
declaracíon:
int[][] mints = { {1, 2, 3}, {91,92,93,94}, {2001, 2002} };
int[] reemplazo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
myInts[1] = reemplazo;
Declaración y Creación de Arreglos Bidimensionales
Un arreglo bidimensional llamado b con dos filas y dos columnas, podría declararse
e inicializarse con inicializadores de arreglos anidados, como se muestra a continuación:
int b[][] = { {1 , 2}, {3 , 4}};
Los valores inicializadores se agrupan por filas entre corchetes. Por lo tanto, 1 y 2
inicializan b[0][0] y b[0][1]; 3 y 4 inicializan b[1][0] y b[1][1]. El compilador determina el
número de filas contando el número de inicializadores de arreglos anidados11 en el
inicializador del arreglo. El compilador determina el número de columnas en una fila
contando los valores inicializadores en el inicializador del arreglo para esa fila.
En java los arreglos bidimensionales se mantienen como arreglos de arreglos
unidimensionales. Por lo tanto el arreglo b en la declaración anterior en realidad esta
compuesto de tres arreglos unidimensionales separados. El arreglo b en si es un arreglo
unidimensional que contiene dos elementos. Cada elemento es una referencia a un arreglo
unidimensional de variables int.
11
Representados por conjuntos de llaves dentro de las llaves externas.
Programación orientada a objetos en Java
18
Unidad I. Arreglos unidimensionales y multidimensionales
Arreglos bidimensionales con filas de distintas longitudes
La forma en que java representa los arreglos Bidimensionales los hace bastante flexibles.
De hecho, las longitudes de las filas en el arreglo b no tienen que ser iguales. Por
ejemplo:
int b[][] = { { 1, 2 }, { 3, 4, 5 } };
En la línea anterior se crea el arreglo entero b con dos elementos (los cuales se
determinan según el número de inicializadores anidados) que representan las filas del
arreglo bidimensional. Cada elemento de b es una referencia a un arreglo unidimensional
de variables int. El arreglo int de la fila 0 es una arreglo unidimensional con dos elementos
(1 y 2), y el arreglo int de la fila 1 es un arreglo unidimensional con tres elementos (3, 4 y
5).
Creación de arreglos bidimensionales mediante expresiones de creación
de arreglos
Un arreglo bidimensional con el mismo número de columnas en cada fila puede
crearse mediante una expresión de creación de arreglos. Por ejemplo, en las siguientes
líneas se declararán el arreglo b y se asignarán una referencia a un arreglo de tres por
cuatro:
Int b[][];
B = new int [2] [ ];
b [ 0 ] = new int [ 5 ];
b [ 1] = new int [ 3 ];
//crea 2 filas
//crear 5 columnas para la fila 0
// crear 3 columnas para la fila 1
Estas instrucciones crean un arreglo bidimensional con dos filas. La fila 0 tiene 5 columnas
y la fila 1 tiene 3 columnas.
1.2.2 Operaciones
Mostrar un vector
Ejemplo
Para mostrar un vector en pantalla, se hace mediante un ciclo que se ejecutará n veces,
donde n es el numero de elementos que tiene el vector. El ejemplo que sigue, se declara
un vector String de 10 elementos. El programa contiene dos ciclos, en el primero se
inicializa el vector con los valores de cadena 0, cadena 1, cadena 2 y así sucesivamente
hasta llegar a cadena 9. en el segundo ciclo se manda a pantalla los 10 valores que
contiene el vector.
Programación orientada a objetos en Java
19
Unidad I. Arreglos unidimensionales y multidimensionales
Código 1.2.2.1. Inicializa e imprime los elementos de un arreglo.
Mostrar una matríz
Mostrar una matriz en la pantalla de texto es difícil, ya que Java no dispone de una
función que sitúe el cursor de texto en una posición de la pantalla, como lo hace la función
gotoxy disponible en los lenguajes C/C++. La única alternativa que queda es mostrar los
elementos de una fila unos a continuación de los otros separados por un tabulador,
después otra fila y así hasta mostrar todos los elementos de la matriz.
En el siguiente ejemplo se muestra en pantalla una matriz de 2 x 3; primero se inicializa la
matriz en la línea int [][]a ={{1,2,3},{10,20,30}};. Se separan los elementos de una fila
mediante el carácter tabulador '\t', Cuando se acaba una fila se inserta un retorno de carro
'\n' y se continua con la siguiente fila, y así sucesivamente.
Código 1.2.2.3. Inicializa e imprime los elementos de un arreglo
bidimensional de 3 x 3.
Programación orientada a objetos en Java
20
Unidad I. Arreglos unidimensionales y multidimensionales
Se muestra en pantalla la matriz mediante la línea: System.out.print("\t" +a[i][j]);
Copia de una matriz dada
Para realizar una copia se ha de implementar la interface 12 Cloneable, y redefinir la
función miembro clone de la clase base Object. El primer paso es la llamada a la función
clone de la clase base Object.
Código 1.2.2.4 Función que realiza la copia de una matriz dada usando la
función “clone” de la clase matriz.
Para obtener una copia a de una matriz d se escribe.
Matriz a = (Matriz)d.clone();
La promoción (casting) es necesaria ya que clone devuelve una referencia a un objeto de
la clase base Object.
Traza de una matriz
Se denomina traza de una matriz cuadrada a la suma de los elementos de su diagonal
principal.
12
En el capitulo VI se explica de manera detallada el uso de una interface.
Programación orientada a objetos en Java
21
Unidad I. Arreglos unidimensionales y multidimensionales
Código 1.2.2.5. Imprime los elementos de la diagonal de un arreglo
bidimensional de 2 x 2.
Para obtener la traza de la matriz a de la sección anterior se escribe
Traza=obj1.Traza();
Ejemplo
Suma de dos matrices cuadradas
Cuando se suman dos matrices de las mismas dimensiones
Se obtiene otra matriz c en la que sus elementos cij son la suma de los correspondientes
elementos de las matrices a y b, es decir
C[i][j]=a[i][j]+b[i][j]
Para sumar dos matrices, se define una función miembro estática denominada suma.
Dentro de la función, se crea una matriz temporal resultado, con la misma dimensión de
las matrices que intervienen en la operación, y se guardan en sus elementos el resultado
de la suma de las matrices a y b. Finalmente, la función suma devuelve la matriz
resultado.
Programación orientada a objetos en Java
22
Unidad I. Arreglos unidimensionales y multidimensionales
Código 1.2.2.6. Función que recibe de parámetros dos matrices
bidimensionales y hace la suma de sus elementos.
La función que suma dos matrices se llama de la siguiente manera:
double[][] a1={{1, 2, 3},{4,5,6},{7,8,9}};
Matriz a=new Matriz(a1);
double[][] b1={{1, 0, -1},{2,1,3},{-1, 0, 2}};
Matriz b=new Matriz(b1);
Matriz re=Matriz.suma(a, b);
System.out.println("matriz "+re);
Producto de dos matrices
La regla para multiplicar dos matrices es bastante más complicada que para sumar dos
matrices de las mismas dimensiones. En general, se pueden multiplicar dos matrices de
dimensiones m x n y n x q, dando como resultado una matriz de dimensiones m x q.
Los elementos c[i][j] se obtienen multiplicando los elementos a[i][k] de la fila i por los
elementos a[k][j] de la columna j, y sumando los resultados.
La codificación se realiza empleando un triple ciclo for, guardando en los elementos de la
matriz local resultado la suma de los productos de la fórmula anterior.
Programación orientada a objetos en Java
23
Unidad I. Arreglos unidimensionales y multidimensionales
Código 1.2.2.7. Función que recibe de parámetros dos matrices
bidimensionales y arroja el producto de sus elementos.
Otras variantes de la operación producto son:
El producto de un escalar (número real) por una matriz que da como resultado otra matriz
cuyos elementos están todos multiplicados por dicho escalar. Se define también la
operación conmutativa.
Código 1.2.2.8. Función que realiza el producto de dos matrices
utilizando el productor escalar.
Al multiplicar una matriz cuadrada de dimensión n, por un vector columna de la misma
dimensión se obtiene otro vector columna. Cada elemento del vector resultante se obtiene
multiplicando los elementos de una fila de la matriz por los correspondientes elementos
del vector columna y se suman los resultados. La codificación de esta función producto es
la siguiente:
Programación orientada a objetos en Java
24
Unidad I. Arreglos unidimensionales y multidimensionales
Al multiplicar un vector fila por una matriz cuadrada de la misma dimensión se obtiene
otro vector fila. El código es semejante al de la función producto definida previamente.
Matriz Traspuesta
Una matriz traspuesta de otra matriz es aquella que tiene los mismos elementos pero
dispuestos en forma distinta. Las columnas de la matriz original se transforman en filas de
la matriz traspuesta. La definición de la función estática traspuesta no reviste dificultad
alguna.
Código 1.2.2.8. Función que realiza la matriz traspuesta de una matriz
dada.
Programación orientada a objetos en Java
25
Unidad I. Arreglos unidimensionales y multidimensionales
Para hallar la matriz traspuesta de la matriz a se escribe
double[][] a1={{1, 2, 3},{4,5,6},{7,8,9}};
Matriz a=new Matriz(a1);
Matriz tras=Matriz.traspuesta(a);
System.out.println("matriz traspuesta"+tras);
1.2.3 Aplicaciones
Ejemplo 1
El siguiente programa se crea un arreglo bidimensional de 4 x 5 ,se enumera cada uno de
los elementos del arreglo de izquierda a derecha y de arriba abajo, y se muestran estos
valores:
Código 1.2.3.1. Inicialización e impresión de un arreglo bidimensional de
4 x 5.
Este programa generará la siguiente salida:
01234
56789
10 11 12 13 14
15 16 17 18 19
Programación orientada a objetos en Java
26
Unidad I. Arreglos unidimensionales y multidimensionales
Cuando se reserva memoria para un arreglo bidimensional13, se puede únicamente
especificar la memoria para la primera dimensión, la del extremo izquierdo. El espacio
para las dimensiones restantes puede reservarse de manera separada.
Ejemplo 2: El siguiente código reserva memoria para la primera dimensión de dosD
cuando se declara. El espacio para la segunda dimensión se reserva manualmente.
Int dosD[][] = new int[4][];
dosD[0] = new int[5];
dosD[1] = new int[5];
dosD[2] = new int[5];
dosD[3] = new int[5];
En este caso no resulta ventajoso reserva espacio para la segunda dimensión de
forma individual, pero en otros casos, puede que sí lo sea. Por ejemplo, cuando se reserva
memoria para dos dimensiones de forma separada, no es necesario reservar el mismo
número de elementos para cada dimensión. Como se ha dicho, dado que los arreglos
bidimensionales son arreglos de arreglos, la longitud de cada arreglo se puede establecer
de forma independiente. Como ejemplo, véase el siguiente programa, que crea un arreglo
bidimensional en que los tamaños de la segunda dimensión no son iguales14:
Código 1.2.3.2. Reserva memoria para la primera dimensión de dosD cuando
se declara. El espacio para la segunda dimensión se reserva manualmente.
13
14
Siempre se reserva usando el operador new.
Arreglos irregulares.
Programación orientada a objetos en Java
27
Unidad I. Arreglos unidimensionales y multidimensionales
Este programa genera la siguiente salida:
0
12
345
6789
El arreglo creado con este programa tiene en el siguiente aspecto;
[0][0]
[1[0]
[2[0]
[3[0]
[1[1]
[2[1]
[3[1]
[2][2]
[3][2]
[3][3]
El uso de arreglos bidimensionales irregulares puede no ser apropiado para muchas
aplicaciones porque funciona de manera contraria a lo que la gente espera encontrarse en
un arreglo bidimensional. Con todo, este tipo de arreglos puede utilizare de forma efectiva
en algunas situaciones. Por ejemplo, si se necesita un arreglo bidimensional muy grande
de escasos elementos (es decir, en la que no se vayan a utilizarse todos los elementos),
un arreglo irregular puede ser la solución ideal.
Es posible inicializar arreglos bidimensionales, para hacerlo, simplemente hay que
introducir entre llaves el inicializador de cada dimensión. El siguiente programa crea un
arreglo en la que cada elemento contiene el producto de la fila y los índices de la columna.
Obsérvese también que pueden usarse tanto expresiones como valores literales en los
inicializadores del arreglo.
Código 1.2.3.3. Inicialización e impresión de un arreglo bidimensional
irregular
Cuando se ejecute este programa se obtendrá la siguiente salida:
Programación orientada a objetos en Java
28
Unidad I. Arreglos unidimensionales y multidimensionales
0.0
0.0
0.0
0.0
0.0
1.0
2.0
3.0
0.0
2.0
4.0
6.0
0.0
3.0
6.0
9.0
Como puede apreciarse, cada fila en el arreglo se inicializa según se ha especificado en las
listas de inicialización.
1.3 Arreglos multidimensionales
1.3.1 Conceptos básicos
Java proporciona la posibilidad de almacenar varias dimensiones, aunque raramente los
datos del mundo real requieren más de dos o tres dimensiones. El medio mas fácil de
dibujar un arreglo de tres dimensiones es dibujar un cubo, tal como se muestra en la
figura 6.
Figura 6: Un arreglo de tres dimensiones (4 x 5 x 3).
Un arreglo tridimensional se puede considerar como un conjunto de arreglos
bidimensionales combinados juntos, para formar, en profundidad, una tercera dimensión.
El cubo se construye con filas15, columnas16 y planos17. Por consiguiente, un elemento
dado se localiza especificando su plano, fila y columna. Una definición de un arreglo
tridimensional equipos es:
int equipos[] [] [] = new int [3] [15] [10];
un ejemplo típico de un arreglo de tres dimensiones es el modelo libro, en el que cada
pagina del libro es un arreglo bidimensional construido por filas y columnas. Así por
15
16
17
Dimensión vertical.
Dimensión horizontal.
Dimensión en profundidad.
Programación orientada a objetos en Java
29
Unidad I. Arreglos unidimensionales y multidimensionales
ejemplo, cada pagina tiene cuarenta y cinco líneas que forman las filas del arreglo y
ochenta caracteres por línea, que forman las columnas del arreglo. Por consiguiente si el
libro tiene quinientas paginas, existirán quinientos planos y el número de elementos será
500 x 80 x 45 = 1,800,000.
1.3.2 Aplicaciones
El arreglo libro tiene tres dimensiones [PAGINA] [LINEAS] [COLUMNAS], que definen el
tamaño del arreglo. El tipo de datos del arreglo es char, ya que los elementos, son
caracteres.
¿Cómo se puede acceder a la información del libro? El método más fácil es mediante ciclos
anidados. Dado que el libro se compone de un conjunto de páginas, el ciclo mas externo
será el ciclo de pagina, y el ciclo de columna será el ciclo mas interno. Esto significa que el
ciclo de filas se insertará entre los ciclos de páginas y columnas. El código siguiente
permite procesar el arreglo:
Código 1.3.2.1 Ilustración de acceso al arreglo libro de tres dimensiones
mediante ciclos for anidados.
Programación orientada a objetos en Java
30
Unidad I. Arreglos unidimensionales y multidimensionales
Código 1.3.2.2 Determina si una matriz es simétrica. Si lo es, genera
números aleatorios de 0 a 7. El programa itera hasta encontrar una raíz
simétrica.
Programación orientada a objetos en Java
31
Unidad I. Arreglos unidimensionales y multidimensionales
1.4 Ejercicios resueltos
1.4.1 Declare un arreglo x de 10 elementos e inicialícelo con valores del 1 al 10 y Muestre
el séptimo valor del arreglo.
1.4.2. Declare un arreglo de flotantes de 70 elementos y muestre la suma de todos los
elementos.
1.4.3 Declare un arreglo entero de 8 elementos y ordénelo usando el método de la
burbuja.
Programación orientada a objetos en Java
32
Unidad I. Arreglos unidimensionales y multidimensionales
1.4.4. Declare un arreglo bidimensional de 11 x 11 y imprima las tablas de multiplicar del
0 al 10.
Programación orientada a objetos en Java
33
Unidad I. Arreglos unidimensionales y multidimensionales
1.5 Ejercicios propuestos
1.5.1 Determinar e imprimir los valores menor y mayor contenidos en el arreglo w con 99
elementos de punto flotante.
1.5.2 Diseñe un programa que guarde los 10 números dígitos y luego los imprima en
forma ascendente y descendente. Usando, para ello, un arreglo de una dimensión.
1.5.3 En un arreglo se ha almacenado el número total de toneladas de cereales
cosechadas durante cada mes del año anterior. Se desea la siguiente información:
a) El promedio anual de toneladas cosechadas.
b) ¿Cuántos meses tuvieron una cosecha superior al promedio anual?
c) ¿Cuántos meses tuvieron una cosecha inferior al promedio anual?.
Escriba un programa que proporciones estos datos.
1.5.4 Crear un vector de n elementos. Visualizarlo luego de desplazar los elementos una
posición de tal forma que el último elemento ocupe la primera posición, el primero la
segunda y así sucesivamente.
1.5.5 Diseñe una matriz en Java, de 6*6 elementos, y luego muestre, la suma de sus filas,
y columnas por separado.
1.5.6 Se desea saber la suma y la multiplicación de dos matrices A y B, cada una con m*n
elementos.
1.5.7 Realice una búsqueda binaria en un arreglo unidimensional. Una búsqueda binaria,
es de la siguinte forma: se lee el valor que se desea buscar, se compara la primera
posición, si son iguales, fin de la búsqueda; de lo contrario, compararlo con la posición
dos, y así sucesivamente, si se llega al final del arreglo y no se encontró el valor, se debe
indicar con una leyenda. Pero si se encuentra, se debe especificar la posición, que ese
valor ocupa en el arreglo.
1.5.8 Etiquete los elementos del arreglo bidimensional ventas de 3 X 5, para indicar el
orden en el que se establecen en cero, mediante el siguiente fragmento de programa.
for (int fila = 0; fila < ventas.length; fila++)
for( int col = 0; col > ventas[fila].length; col++)
ventas[fila][col]=0;
1.5.9 Escriba un programa para simular el tiro de dos dados. El programa debe utilizar
Math.random una vez para tirar el primer dado, y de nuevo para tirar el segundo dado.
Después debe calcularse la suma de los dos valores que variar del 2 al 7, siendo 7 la suma
más frecuente. En la figura 7 se muestran las 36 posibles combinaciones de los dos dados.
El programa debe tirar los dados 36,000 veces. Utilice una arreglo unidimensional para
registrar el número de veces que aparezca cada una de las posibles sumas.
Programación orientada a objetos en Java
34
Unidad I. Arreglos unidimensionales y multidimensionales
Figura 7: Las 36 posibles sumas de los dados.
1.5.10 El juego del ahorcado se juega con dos personas (o una persona y una
computadora). Un jugador selecciona una palabra y el otro jugador trata de adivinar la
palabra adivinando letras individuales. Diseñar un programa para jugar el ahorcado.
Sugerencia: Almacenar una lista de palabras en un array y seleccionar palabras
aleatoriamente.
Programación orientada a objetos en Java
35
Unidad II. Métodos y mensajes
UNIDAD II. MÉTODOS Y MENSAJES
Concepto, Declaración, Tipos y Ejemplos de Métodos, Formas de pasar
Argumentos y Estructura de Código.
Programación orientada a objetos en Java
36
Unidad II. Métodos y mensajes
UNIDAD 2. MÉTODOS Y MENSAJES
2.1 Atributos Const y Static
Nota: El Atributo const no se utiliza en este lenguaje (java)
Atributo Static18
Si se declara un atributo static, todas las instancias de esa clase comparten ese
atributo, si lo cambia en una de ellas, todas ven el cambio en su propio atributo. El
atributo pertenece a la clase, no a los objetos creados a partir de ella. El atributo static es
atributo único para todos los objetos de la clase, estos son llamados también atributos de
clase.
El que un atributo sea común a todos los objetos de la clase se plasma en que sólo
habrá una copia del atributo global a todos los objetos de la clase
Ejemplos:
static int a = 5, b = 4;
En el ejemplo anterior se declaran tres variables (a y b). Las variables a y b son
estáticas para toda la clase.
2.2 Concepto de método
Los métodos son funciones que pueden ser llamadas dentro de la clase o por otras
clases, por lo tanto los métodos son funciones definidas dentro de una clase. Salvo los
métodos static o de clase, se aplican siempre a un objeto de la clase por medio del
operador punto (.). Dicho objeto es su argumento implícito. Los métodos pueden además
tener otros argumentos explícitos que van entre paréntesis.
En general un método es:
•
•
•
18
Un bloque de código que tiene un nombre
Recibe unos parámetros o argumentos (opcionalmente)
Contiene sentencias o instrucciones para realizar algo (opcionalmente) y devuelve
un valor de algún tipo conocido (opcionalmente).
Atributo Estático
Programación orientada a objetos en Java
37
Unidad II. Métodos y mensajes
2.3 Declaración de Métodos
Una declaración de método proporciona mucha información sobre el método al
compilador, al sistema en tiempo de ejecución y a otras clases y objetos.
Junto con el nombre del método, la declaración lleva información como el tipo de
retorno del método, el número y el tipo de los argumentos necesarios, y qué otras clases y
objetos pueden llamar al método.
Los únicos elementos necesarios para una declaración de método son:
• El nombre
• El tipo de retorno del método
Por ejemplo, el código siguiente declara un método llamado estaVacio() en la clase Pila
que devuelve un valor booleano19.
Código 2.3.1 Declaración de un método que devuelve un valor boleano.
En el código siguiente se declara un método llamado suma que devuelve la suma de dos
valores. El método recibe de parámetros dos valores enteros:
Código 2.3.2 Llamada a un método llamado suma que recibe dos valores como
parámetros y retorna un entero con la suma de los dos valores.
19
Los valores boléanos (boolean) solo aceptan dos valores, falso o verdadero.
Programación orientada a objetos en Java
38
Unidad II. Métodos y mensajes
2.4 Llamadas a Métodos
Para ejecutar o mandar llamar a un método sólo es necesario poner el nombre del
objeto seguido por un punto y el nombre del método seguido de ( ). Si el método recibe
algún valor como parámetro, dicho valor se debe especificar (entre paréntesis) a la hora
de llamar al método.
Los métodos pueden ser invocados o llamados de cualquier método de la clase,
incluido él mismo.
Además, si el método recibe parámetros, cuando se invoca, hay que pasar un valor a cada
argumento, a través de una variable o un valor constante. En Java, la acción de pasar
valores a parámetros de tipo primitivo (int, double, boolean, char..) se denomina paso de
parámetros por valor. En éste caso, los argumentos que los reciben, no pueden ser
modificados por la función.
En caso que el parámetro sea de tipo Clase o arreglo, lo que se está haciendo es un paso
de parámetros por referencia 20, y en este caso, los parámetros si pueden ser modificados
por el método.
En el paso de parámetro por referencia se pasa el valor como parámetro y cualquier cambio al
valor en el método afecta directamente a la variable.
20
Programación orientada a objetos en Java
39
Unidad II. Métodos y mensajes
Código 2.4.1 Llamada a un método que determina si un número es par o
impar.
Los métodos se invocan con su nombre, y pasando la lista de argumentos entre
paréntesis. El par de argumentos se usa como si fuera una variable del Tipo devuelto por
el método.
Por ejemplo:
char x;
x = mayor(2,3);
Se llama a los métodos dentro de una instancia de una clase utilizando el operador punto
(.). La forma general de una llamada:
referencia_a_objeto . nombre_de_método ( lista_de_parámetros );
Aquí, referencia_a_objeto es cualquier variable que se refiere a un objeto,
nombre_de_método es el nombre de un método de la clase con la que se declaró
referencia_a_objeto y lista_de_parámetros es una lista de valores o expresiones separados
por comas que coinciden en número y tipo con cualquiera de los métodos declarados
como nombre_de_método en la clase. En caso de que el método no reciba parámetros, en
“lista argumentos” no se escribe nada.
En este caso, se podría llamar al método init sobre cualquier objeto Point.
Point p = new Point();
p.init();
2.5 Tipos de Métodos
2.5.1 Métodos Estáticos o de Clase
Se cargan en memoria en tiempo de compilación y no a medida que se ejecutan
las líneas de código del programa. Van precedidos del modificador static. Para invocar a
un método estático no se necesita crear un objeto de la clase en la que se define.
Si se invoca desde la clase en la que se encuentra definido, basta con escribir su
nombre. Si se le invoca desde una clase distinta, debe anteponerse a su nombre, el de la
clase
en
que
se
encuentra
seguido
del
operador
punto
(.)
<NombreClase>.metodoEstatico()
Suelen emplearse para realizar operaciones comunes a todos los objetos de la
clase. No afectan a los estados de los mismos21. Por ejemplo, si se necesita un método
para contabilizar el número de objetos creados de una clase, tiene sentido que sea
21
A los valores de sus variables de instancia.
Programación orientada a objetos en Java
40
Unidad II. Métodos y mensajes
estático ya que su función (aumentar el valor de una variable entera) se realizaría
independientemente del objeto empleado para invocarle.
No es conveniente usar muchos métodos estáticos, pues si bien se aumenta la rapidez de
ejecución, se pierde flexibilidad, no se hace un uso efectivo de la memoria y no se trabaja
según los principios de la Programación Orientada a Objetos.
A veces se desea crear un método que se utiliza fuera del contexto de cualquier
instancia. Todo lo que se tiene que hacer es declarar estos métodos como static. Los
métodos estáticos sólo pueden llamar a otros métodos static directamente, y no se
pueden referir a this o super 22 de ninguna manera. Las variables también se pueden
declarar como static, pero debe ser consciente que es equivalente a declararlas como
variables globales, que son accesibles desde cualquier fragmento de código. Se puede
declarar un bloque static que se ejecuta una sola vez si se necesitan realizar cálculos para
inializar las variables static.
Ejemplos de Métodos Estáticos
Ejemplo 1:
Código 2.5.1.1 El ejemplo muestra una clase que tiene un método static,
algunas variables static y un bloque de inicialización static.
Esta es la salida del programa.
bloque static inicializado
x = 42
22
Estos dos conceptos (this y super) se explican en los temas posteriores.
Programación orientada a objetos en Java
41
Unidad II. Métodos y mensajes
a=3
b = 12
Ejemplo 2:
Código 2.5.1.2 La funcionalidad de un método varía en función de si es
invocado por el objeto hucha 1 o por hucha 2, no tendría sentido
considerarlo estático.
Código 2.5.1.3 La funcionalidad del método es la misma,
independientemente del objeto empleado para invocarlo. Sí tiene sentido
declararlo estático.
Programación orientada a objetos en Java
42
Unidad II. Métodos y mensajes
Ejemplo 3:
Código 2.5.1.4 Programa que calcula la raíz cuadrada de 100 y con un
retardo de 3 segundos calcula el valor de 2 a la 8 potencia.
2.5.2 Métodos Normales
Los métodos son funciones definidas dentro de una clase. Salvo los métodos static
o de clase, se aplican siempre a un objeto de la clase por medio del operador punto (.).
Dicho objeto es su argumento implícito. Los métodos pueden además tener otros
argumentos explícitos que van entre paréntesis, a continuación del nombre del método.
La primera línea de la definición de un método se llama declaración o header; el
código comprendido entre las llaves {…} es el cuerpo o body del método. Considérese el
siguiente método tomado de la clase Circulo 23:
Código 2.5.2.1 Demuestra encabezado y cuerpo de un método.
El header consta del cualificador de acceso (public, en este caso), del tipo del valor
de retorno (Circulo en este ejemplo, void si no tiene), del nombre de la función y de una
lista de argumentos explícitos entre paréntesis, separados por comas. Si no hay
argumentos explícitos se dejan los paréntesis vacíos.
23
Es una subclase no abstracta de la clase abstracta ObjetoGrafico
Programación orientada a objetos en Java
43
Unidad II. Métodos y mensajes
Los métodos tienen visibilidad directa de las variables miembro del objeto que es
su argumento implícito, es decir, pueden acceder a ellas sin cualificarlas con un nombre de
objeto y el operador punto (.). De todas formas, también se puede acceder a ellas
mediante la referencia this, de modo discrecional o si alguna variable local o argumento
las oculta.
El valor de retorno puede ser un valor de un tipo primitivo o una referencia. En
cualquier caso no puede haber más que un único valor de retorno (que puede ser un
objeto o un array). Se puede devolver también una referencia a un objeto por medio de
un nombre de interface. El objeto devuelto debe pertenecer a una clase que implemente
esa interface.
Se puede devolver como valor de retorno un objeto de la misma clase que el
método o de una sub-clase, pero nunca de una super-clase. Los métodos pueden definir
variables locales. Su visibilidad llega desde la definición al final del bloque en el que han
sido definidas. No hace falta inicializar las variables locales en el punto en que se definen,
pero el compilador no permite utilizarlas sin haberles dado un valor. A diferencia de las
variables miembro, las variables locales no se inicializan por defecto.
Si en el header del método se incluye la palabra native (Ej: public native void
miMetodo();) no hay que incluir el código o implementación del método. Este código
deberá estar en una librería dinámica (Dynamic Link Library o DLL 24). Es la forma de
poder utilizar conjuntamente funciones realizadas en otros lenguajes desde código escrito
en Java.
Un método también puede declararse como synchronized (Ej: public synchronized
double miMetodoSynch(){...}). Estos métodos tienen la particularidad de que sobre un
objeto no pueden ejecutarse simultáneamente dos métodos que estén sincronizados
2.6 Referencia this
25
Java incluye un valor de referencia especial llamado this, que se utiliza dentro de
cualquier método para referirse al objeto actual. El valor this se refiere al objeto sobre el
que ha sido llamado el método actual. Se puede utilizar this siempre que se requiera una
referencia a un objeto del tipo de una clase actual. Si hay dos objetos que utilicen el
mismo código, seleccionados a través de otras instancias, cada uno tiene su propio valor
único de this.
Normalmente, dentro del cuerpo de un método de un objeto se puede referir
directamente a las variables miembros del objeto. Sin embargo, algunas veces no se
querrá tener ambigüedad sobre el nombre de la variable miembro y uno de los
argumentos del método que tengan el mismo nombre.
Estas librerías son archivos de funciones compiladas normalmente en lenguajes distintos de Java
(C, C++, Fortran, etc.)
25
En español “este”.
24
Programación orientada a objetos en Java
44
Unidad II. Métodos y mensajes
Por ejemplo, el siguiente constructor de la clase HSBColor inicializa alguna variable
miembro de un objeto de acuerdo a los argumentos pasados al constructor. Cada
argumento del constructor tiene el mismo nombre que la variable del objeto cuyo valor
contiene el argumento.
Código 2.6.1. Programa que ejemplifica el uso de referencia this.
Se debe utilizar this en este constructor para evitar la ambigüedad entre el
argumento luminosidad y la variable miembro luminosidad (y así con el resto de los
argumentos). Escribir luminosidad = luminosidad; no tendría sentido. Los nombres de
argumentos tienen mayor precedencia y ocultan a los nombres de las variables miembro
con el mismo nombre. Para referirse a la variable miembro se debe hacer explícitamente a
través del objeto actual--this.
También se puede utilizar this para llamar a uno de los métodos del objeto actual. Esto
sólo es necesario si existe alguna ambigüedad con el nombre del método y se utiliza para
intentar hacer el código más claro.
2.7 Forma de Pasar Argumentos
En el paso de parámetros a funciones hay dos aproximaciones clásicas: el paso
por valor y paso por referencia.
En el paso por valor se realiza una copia de los valores que se pasan, trabajando
dentro de la función con la copia. Es por ello que cualquier cambio que sufran dentro, no
repercute fuera de la función.
En el paso por referencia no se realiza dicha copia, por lo que las modificaciones de
dentro de las funciones afectan a los parámetros y esos cambios permanecen al final de la
función.
En Java el paso por parámetro es por valor, aunque los efectos son de paso por referencia
cuando los argumentos son objetos. ¿cómo sucede eso? Pues es muy fácil, si una función
tiene como argumento un tipo primitivo (int, float, etc...), en Java se realiza una copia
para la función y cualquier cambio a dicho argumento no afecta a la variable original. Este
paso de parámetros en Java está orientado a utilizar el valor de la variable para otros
cálculos.
Programación orientada a objetos en Java
45
Unidad II. Métodos y mensajes
En el caso de los objetos es distinto. En realidad lo que sucede es que en Java
siempre se tienen referencias a los objetos. Por eso al pasar a una función como
argumento un objeto, se pasa la referencia al mismo, es decir, aunque se hace una copia
para el paso por valor, como lo que se copia es una referencia, los cambios al objeto
referenciado sí son visibles y afectan fuera de la función.
La única excepción es la clase String , cuyos objetos no son mutables. Cualquier
modificación de un objeto String lleva aparejada la creación de una nueva instancia del
objeto. Si se desea el mismo comportamiento para el paso de parámetros del resto de
objetos, se tiene que recurrir al objeto StringBuffer 26.
Algunos métodos no necesitan parámetros, pero la mayoría sí. Los parámetros
permiten generalizar un método. Es decir, un método con parámetros puede operar sobre
una gran variedad de datos y/o utilizarse en un gran número de situaciones diferentes.
Para ilustrar este punto se utilizará un ejemplo muy sencillo.
Código 2.7.1 Función que devuelve el cuadrado del número 10.
Efectivamente, este método devuelve el cuadrado de 10, pero su utilización es muy
limitada. Con todo, si se modifica el método de manera que tome un parámetro, como se
ve a continuación, se consigue que Cuadrado2() sea mucho más útil.
Código 2.7.2 función que devuelve el cuadrado de cualquier valor que se
llame con el.
Es decir Cuadrado2() ahora es un método de propósito general que puede calcular el
cuadrado de cualquier número entero, no sólo de 10.
Verificar el ejemplo:
La clase StringBuffer dispone de muchos métodos para modificar el contenido de los objetos
StringBuffer.
26
Programación orientada a objetos en Java
46
Unidad II. Métodos y mensajes
En la primera llamada a Cuadrado2(), el valor 5 se pasa al parámetro i. en la
segunda llamada, i recibe el valor 9. En la tercera, se pasa el valor de y, que en este
ejemplo es 2. Como muestran estos ejemplos, Cuadrado2() es capaz de devolver el
cuadrado de cualquier dato que se pase al método.
Es importante tener una idea precisa de lo que significan los términos parámetro y
argumento. Un parámetro es una variable, definida por un método, que recibe un valor
cuando se llama al método. Por ejemplo, en Cuadrado2(), i es un parámetro. Un
argumento es un valor que se pasa a un método cuando se le llama. Por ejemplo
Cuadrado2(100) pasa por 100 como argumento. Dentro de Cuadrado2(), el parámetro i
recibe ese valor.
Ejemplos de Llamadas a Métodos y Paso de Argumentos
En el siguiente ejemplo, se llama a un método de la misma clase simplemente con
el nombre del método y los parámetros entre paréntesis, como se ve en el ejemplo:
Programación orientada a objetos en Java
47
Unidad II. Métodos y mensajes
Código 2.7.3 programa que ejemplifica la llamada a métodos y el paso de
argumentos.
2.8 Devolver un valor desde un método
Java necesita que un método declare el tipo de dato del valor que devuelve. Si un
método no devuelve ningún valor, debe ser declarado para devolver void 27. Los métodos
pueden devolver tipos de datos primitivos o tipos de datos de referencia. En el siguiente
ejemplo, el método estaVacio() de la clase Pila devuelve un tipo de dato primitivo, un
valor booleano.
27
Nulo
Programación orientada a objetos en Java
48
Unidad II. Métodos y mensajes
Código 2.8.1 función que devuelve un valor boleano (falso o verdadero).
Sin embargo, el método pop de la clase PILA devuelve un tipo de dato de referencia: un
objeto.
Código 2.8.2 función que devuelve un tipo se dato de referencia.
Los métodos utilizan el operador return para devolver un valor. Todo método que no sea
declarado como void debe contener una sentencia return.
El tipo de dato del valor devuelto por la sentencia return debe corresponder con el
tipo de dato que el método tiene que devolver; no se puede devolver un objeto desde un
método que fue declarado para devolver un entero.
Programación orientada a objetos en Java
49
Unidad II. Métodos y mensajes
Cuando se devuelva un objeto, el tipo de dato del objeto devuelto debe ser una
subclase o la clase exacta indicada. Cuando se devuelva un tipo interface 28, el objeto
retornado debe implementar el interface especificado.
Definición de métodos que no retornan datos
Existen métodos que no devuelven datos. En este caso se estaría definiendo un
procedimiento, la sintaxis es muy similar a la de muchos lenguajes de programación
estructurados:
Ejemplo:
Código 2.8.3 Función que no devuelve valor y visualiza un numero
complejo.
En el ejemplo anterior se ha definido una clase que representa a un número complejo, la
cual tiene un método que visualiza los valores real e imaginario del número.
Declaración de un Método que no Devuelve Valores
Donde la palabra reservada return indica que la ejecución del método ha concluido y
establece el valor de retorno 29.
Concepto ampliamente explicado en la unidad 6, subtema 6.3.
En realidad los métodos que no retornan datos son un caso especial de los métodos que retornan
datos pero se retorna un tipo de dato void el cual es un valor nulo.
28
29
Programación orientada a objetos en Java
50
Unidad II. Métodos y mensajes
2.9 Estructura del Código
Generalmente la estructura de un método es la siguiente:
<modificadores de acceso> <tipo de dato de retorno> <nombre del
método>(tipo1 arg1,tipo2 arg2,...){
Cuerpo del método;
}
Explicación de cada uno de los componentes de un método:
Nombre del método: el que desee el programador.
Número y tipo de argumentos asociados al método (tipo1 arg1,tipo2 arg2,...):
constituye su firma. Los argumentos pueden ser tanto variables primitivas como variables
referenciadas. Las variables primitivas se emplean para almacenar números, caracteres o
valores lógicos, mientras que las referenciadas están asociadas a objetos de clases.
Tipo de dato de retorno o tipo de dato que devuelve el método:
Dato asociado a una variable primitiva.
Dato asociado a una variable referenciada.
void. Es lo que debe ponerse cuando el método no devuelve nada y, por ejemplo,
simplemente muestra por consola un mensaje. Es el caso del método "void
mostrarMensaje()".
Modificadores de acceso: public, private, protected y sin modificador. Sirven para
fijar el grado de accesibilidad de un método. Además de los de acceso, se tienen otros
como static, synchronized, final, abstract, etc. que afectan de un determinado modo al
método.
2.10 Ejercicios Resueltos:
2.10.1 Implementar un programa que sume tres números utilizando un método estático.
Programación orientada a objetos en Java
51
Unidad II. Métodos y mensajes
2.10.2 Implementar un programa que determine los 100 primeros números palíndromos
(son los números que se leen igual de izquierda derecha que de derecha a izquierda) a
partir de un número ingresado por teclado en adelante, usando un método para invertir
los números.
Programación orientada a objetos en Java
52
Unidad II. Métodos y mensajes
2.10.3. Se quiere determinar cuantos y cuales números perfectos y pares, existen entre a
y b.
Nota : Un numero perfecto es aquel que la suma de sus divisores sea igual al numero.
Ej --> 6 : 1 + 2 + 3
2.1.0.4Se desea saber el valor de la siguiente sumatoria:
s = SUMATORIA x^2 - y : desde a hasta b
Siendo x : numero primo e y = numero múltiplo de 5 o 7
Programación orientada a objetos en Java
53
Unidad II. Métodos y mensajes
2.11 Ejercicios propuestos:
2.11.1 Escribir un método que tenga un argumento de tipo entero y que devuelva la letra
P. si el número es positivo, y la letra N, si es cero o negativo.
2.11.2 Escribir un método lógico de dos argumentos enteros, que devuelva true si uno
divide al otro y false en caso contrario.
2.11.3 Escribir un método que convierta una temperatura dada en grados Celsius a grados
Fahrenheit. La formula de conversión es:
F = 9/5 C + 32
Programación orientada a objetos en Java
54
Unidad II. Métodos y mensajes
2.11.4 Crear un programa que contenga un método y que muestre por consola el número
de veces que aparece la letra "a" en una cadena, la cual será dada desde el teclado.
2.11.5 Escribir un método lógico que determine si un carácter es uno de los dígitos de 0 a
9.
2.11.6 escribir un método lógico que determine si un carácter es una vocal.
2.11.7 Escribir un método Redondeo que acepte un valor real cantidad y un valor entero
decimales y devuelva el valor cantidad redondeado al número especificado de decimales.
(Por ejemplo, Redondeo (20.5632.2) devuelve 20.56.
2.11.8 Escribir un método que acepte un número de día, mes y año y lo visualice en el
formato. dd/mm/aa
2.11.9 Escribir un mètodo que lea un entero positivo y a continuación visualice sus
factores primos.
2.11.10 Escribir un programa que permita al usuario elegir el cálculo del área de cualquier
de las figuras geométricas: Círculo, cuadrado, rectángulo o triangulo, mediante métodos.
Programación orientada a objetos en Java
55
Unidad III. Constructor, Destructor (Recolector de basura)
UNIDAD III. CONSTRUCTOR, DESTRUCTOR
(RECOLECTOR DE BASURA)
Concepto, Declaración, Tipos y Aplicaciones de Constructores y
Destructores (Recolectores de Basura)
Programación orientada a objetos en Java
56
Unidad III. Constructor, Destructor (Recolector de basura)
UNIDAD III. CONSTRUCTOR, DESTRUCTOR (RECOLECTOR DE BASURA)
3.1 Concepto de método constructor
Un Constructor es un método especial en Java empleado para inicializar valores en
Instancias de objetos, a través de este tipo de métodos es posible generar diversos tipos
de instancias para la clase en cuestión; la principal característica de este tipo de métodos
es que llevan el mismo nombre de la clase. Los constructores tienen el mismo nombre que
la clase, no retornan ningún valor y no pueden ser heredados. Un método constructor
inicializa las variables de instancia de una clase.
Cuando se crea el objeto de una clase, new llama al método constructor de la clase
para llevar acabo la inicialización. Un método constructor debe tener el mismo nombre que
el de su clase30. Una clase puede contener constructores sobrecargados, los cuales
permiten a los objetos de esa clase inicializarse de distintas maneras.
Cuando un programa crea la instancia de un objeto de cierta clase, el programa
puede proporcionar inicializadores (argumentos) entre paréntesis, a la derecha del nombre
de la clase. Estos inicializadores se pasan como argumentos al constructor de la clase.
Se requiere que toda clase tenga al menos un constructor. Por lo tanto, si no se
declaran constructores para una clase, el compilador crea un constructor predeterminado
que no toma argumentos. El constructor predeterminado para una clase llama al
constructor sin argumentos para su superclase (la clase que extiende).
3.2 Recolector de basura (garbage collector)31
Muchos otros lenguajes orientados a objetos necesitan que se siga la pista de los
objetos que se han creado y luego se destruyan cuando no se necesiten. Escribir código
para manejar la memoria de esta es forma es aburrido y propenso a errores.
En el lenguaje de programación Java no existen los destructores, en lugar de eso,
el entorno de ejecución de Java tiene un recolector de basura que periódicamente libera la
memoria ocupada por los objetos que no se van a necesitar más. Java permite crear
tantos objetos como se quiera (sólo limitados por los que el sistema pueda manejar) pero
nunca tienen que ser destruidos. El entorno de ejecución Java borra los objetos cuando
determina que no se van a utilizar más. Este proceso es conocido como recolección de
basura.
El recolector de basura de Java es un barredor de marcas que escanea
dinámicamente la memoria de Java buscando objetos, marcando aquellos que han sido
referenciados. Después de investigar todos los posibles paths de los objetos, los que no
30
31
Incluyendo las mismas letras mayúsculas y minúsculas.
Los destructores no existen en Java
Programación orientada a objetos en Java
57
Unidad III. Constructor, Destructor (Recolector de basura)
están marcados (esto es, no han sido referenciados) se les conoce como basura y son
eliminados.
Un objeto es ilegible para la recolección de basura cuando no existen más
referencias a ese objeto. Las referencias que se mantienen en una variable desaparecen
de forma natural cuando la variable sale de su ámbito. O cuando se borra explícitamente
un objeto referencia mediante la selección de un valor cuyo tipo de dato es una referencia
a null.
El colector de basura funciona en un thread (hilo) de baja prioridad y funciona
tanto síncrona como asíncronamente dependiendo de la situación y del sistema en el que
se esté ejecutando el entorno Java.
El recolector de basura se ejecuta síncronamente cuando el sistema funciona fuera
de memoria o en respuesta a una petición de un programa Java. Un programa Java le
puede pedir al recolector de basura que se ejecute en cualquier momento mediante una
llamada a System.gc(). Aunque pedir que se ejecute el recolector de basura no garantiza
que los objetos sean recolectados.
La recolección de basura en Java funciona identificando objetos que son
alcanzables por la máquina virtual de Java, como se muestra en la siguiente figura 8. De
forma periódica32, la máquina virtual invoca al recolector de basura (GC)33. En la ejecución
del programa, algunos objetos referencian a otros, creando un grafo dirigido. El recolector
de basura examina todos los objetos en memoria y ve si son alcanzables desde el objeto
raíz, es decir, si hay un camino en el grafo desde ese objeto raíz a cada objeto. Con esta
información, el recolector de basura marca los objetos como alcanzables o no y libera
todos los objetos que no son alcanzables.
Figura 8: El recolector de basura de Java funciona determinando los objetos que son alcanzables.
32
33
Por ejemplo, cuando la cantidad usada de memoria sobrepasa un cierto límite.
Garbage Collector
Programación orientada a objetos en Java
58
Unidad III. Constructor, Destructor (Recolector de basura)
3.3 Declaración de métodos constructores
Los métodos constructores tienen las siguientes características especiales:
•
•
•
•
•
Se llama igual que la clase.
No devuelve nada, ni siquiera void.
Pueden existir varios, pero siguiendo las reglas de la sobrecarga de funciones.
De entre los que existan, tan sólo uno se ejecutará al crear un objeto de la clase.
Dentro del código de un constructor generalmente suele existir inicializaciones de
variables y objetos, para conseguir que el objeto sea creado con dichos valores
iniciales.
Sintaxis:
Declaración de constructores:
<modificadordeVisibilidad> <NombredelaClase> ( <argumentos> ) {
< declaraciones>
}
Donde el modificadorvisibilidad es el tipo de modificador de acceso del constructor.
El nombre de la clase como su nombre lo indica será el nombre del constructor. Se debe
recordar que el constructor y la clase deben tener el mismo nombre. Los parámetros son
las variables que reciben como parámetros el método constructor. Cabe mencionar que el
constructor al ser método inicializador de variables, no devuelve ningún valor de retorno.
Cuando se declaren constructores para las clases, se pueden utilizar los
especificadores de acceso normales para especificar si otros objetos pueden crear
ejemplares de su clase.
private
Niguna otra clase puede crear un objeto de su clase.
La clase puede contener métodos públicos y esos métodos pueden construir un
objeto y devolverlo, pero nada más.
protected
public
Sólo las subclases de la clase pueden crear ejemplares de ella.
Cualquiera puede crear un ejemplar de la clase.
package-access
Nadie externo al paquete puede construir un ejemplar de su clase. Visibilidad por
omisión.
Esto es muy útil si se quiere que las clases que se tengan en un paquete puedan crear
ejemplares de la clase pero no se quiere que lo haga nadie más.
Programación orientada a objetos en Java
59
Unidad III. Constructor, Destructor (Recolector de basura)
Ejemplo:
Código 3.3.1 Declaración de dos constructores. El primero no recibe
argumentos y el segundo constructor recibe un valor entero de argumento.
En este ejemplo se tiene la clase “clase1”, la cual tiene dos constructores, uno no recibe
ningún parámetro e inicializa la variable “y” en 1. El otro constructor recibe de aegumento
la variable “par” que se utiliza para inicializar la variable “y”.
Ejemplo 2
Código 3.3.2 Declaración de dos constructores. El primero inicializa x e
y en 0 y el segundo inicializa los valores x e y con los argumentos
pasados a la función A.
En el ejemplo anterior se tiene a la clase “A”, que tiene dos constructores, el primero
inicializa las variables x e y en cero. Y el segundo constructor inicializa x e y con los
valores pasados por los parámetros a y b.
3.4 Aplicaciones de constructores y destructores
(Recolectores de basura)
Ejemplo 1
Se puede tener cualquier número de constructores, todos los cuales tienen el mismo
nombre. Al igual que otros métodos sobrecargados, los constructores se diferencian unos
de otros en el número y tipo de sus argumentos.
Programación orientada a objetos en Java
60
Unidad III. Constructor, Destructor (Recolector de basura)
Se considerará la clase Rectangle del paquete java.awt 34 que proporciona varios
constructores diferentes, todos llamados Rectangle(), pero cada uno con número o tipo
diferentes de argumentos a partir de los cuales se puede crear un nuevo objeto Rectangle.
Aquí están las firmas de los constructores de la clase java.awt.Rectangle.
public Rectangle()
public Rectangle(int width, int height)
public Rectangle(int x, int y, int width, int height)
public Rectangle(Dimension size)
public Rectangle(Point location)
public Rectangle(Point location, Dimension size)
El primer constructor de Rectangle inicializa un nuevo Rectangle con algunos
valores por defecto razonables, el segundo constructor inicializa el nuevo Rectangle con la
altura y anchura especificadas, el tercer constructor inicializa el nuevo Rectangle en la
posición especificada y con la altura y anchura especificadas, etc.
Típicamente, un constructor utiliza sus argumentos para inicializar el estado del nuevo
objeto. Entonces, cuando se crea un objeto, se debe elegir el constructor cuyos
argumentos reflejen mejor cómo se quiere inicializar el objeto.
Basándose en el número y tipos de los parámetros que se pasan al constructor, el
compilador determina cual de ellos utilizar, Así el compilador sabe que cuando se escribe:
new Rectangle(0, 0, 100, 200);
El compilador utilizará el constructor que requiere cuatro argumentos enteros, y cuando se
escribe:
new Rectangle(miObjetoPoint, miObjetoDimension);
Utilizará el constructor que requiere como argumentos un objeto Point y un objeto
Dimension.
Ejemplo 2.
El constructor para esta subclase de Thread, un hilo que realiza animación,
selecciona algunos valores por defecto como la velocidad de cuadro, el número de
imágenes y carga las propias imágenes.
34
AWT es el acrónimo del X Window Toolkit para Java.
Programación orientada a objetos en Java
61
Unidad III. Constructor, Destructor (Recolector de basura)
Código 3.3.1 declaración de constructores.
Obsérvese cómo el cuerpo de un constructor es igual que el cuerpo de cualquier otro
método -- contiene declaraciones de variables locales, ciclos, y otras sentencias. Sin
embargo, hay una línea en el constructor de Animacion que no se verá en un método
normal--la segunda línea.
super("Animacion");
Esta línea invoca al constructor proporcionado por la superclase de Animacion-Thread. Este constructor particular de Thread acepta una cadena que contiene el nombre
del Thread. Frecuentemente un constructor se aprovechará del código de inicialización
escrito para la superclase de la clase.
En realidad, algunas clases deben llamar al constructor de su superclase para que
el objeto trabaje de forma apropiada. Típicamente, llamar al constructor de la superclase
es lo primero que se hace en el constructor de la subclase: un objeto debe realizar
primero la inicialización de nivel superior.
Ejemplo 3.
A continuación se tiene a una clase árboles, la cual contiene cuatro constructores que
inicializan los valores de manera diferente.
El primer constructor solo imprime la cadena “un árbol genérico”
El segundo constructor recibe de parámetro el tipo de árbol y lo imprime
Programación orientada a objetos en Java
62
Unidad III. Constructor, Destructor (Recolector de basura)
El tercer constructor recibe de parámetro la altura del árbol y la imprime
El cuarto constructor recibe los dos parámetros, el tipo de árbol y la altura del árbol
Código 3.3.2 Declaración de diferentes constructores que inicializan
valores de forma diferente.
3.5 Tipos de Métodos Constructores y Destructores
(Recolectores de Basura)
Constructores Implícitos
Cuando se escriben clases, no es obligatorio declarar constructores porque Java
proporcionar constructores. El constructor por defecto, el constructor que no necesita
argumentos, lo proporciona automáticamente el sistema para todas las clases. A este tipo
de constructores se les llama constructores implícitos, porque se crea internamente en el
lenguaje Java.
Si no se declaran constructores automáticamente Java invoca al constructor implícito de la
clase, al que ya tiene por defecto.
Ejemplo: //constructor implícito
Aquí se tiene a una Clase de Diseño llamada Bicicleta:
Programación orientada a objetos en Java
63
Unidad III. Constructor, Destructor (Recolector de basura)
Esta es la implementación de la Clase Bicicleta
Código 3.4.1 Ilustración de constructores implícitos.
Y ahora se crea una instancia de la clase Bicicleta desde cualquier otro Objeto
Bicicleta b1 = new Bicicleta();
Se puede observar que la Clase Bicicleta no tiene ningún Constructor. En estos casos
se dice que la Clase tiene un Constructor implícito y que el entorno de ejecución Java sólo
utilizará el Constructor por defecto.
Constructores Explícitos
Los constructores explícitos son aquellos constructores que el programador declara. Cabe
mencionar que los constructores también se pueden sobrecargas como los métodos
normales.
Métodos de Constructores Sobrecargados
Los métodos de constructores de una clase pueden sobrecargarse. Los métodos
constructores sobrecargados permiten a los objetos de una clase inicializarse de distintas
Programación orientada a objetos en Java
64
Unidad III. Constructor, Destructor (Recolector de basura)
formas. Para sobrecargar métodos constructores simplemente hay que proporcionar varias
declaraciones del método constructor con distintas listas de parámetros.
Estos Constructores sobrecargados
•
•
Permiten crear Objetos pasándoles diferentes valores
Estarán incluidos tanto en el código de la Clase como en las Clases de diseño de un
Diagrama de Clases de diseño UML 35.
Ejemplo 1: //constructor sobrecargado
Aquí se tiene una Clase de Diseño llamada Bicicleta con un Constructor sobrecargado.
Esta es la implementación de la Clase Bicicleta
Código 3.4.2 Clase Bicicleta con sobrecarga de constructores.
35
Lenguaje Unificado de Modelado
Programación orientada a objetos en Java
65
Unidad III. Constructor, Destructor (Recolector de basura)
Este constructor sin argumentos tiene que estar escrito dentro de la Clase aunque no
tenga contenido. Si no se hace así el compilador se quejará cuando desde otro Objeto se
quiera crear una instancia de tipo Bicicleta con un Constructor sin argumentos
Y ahora se crean dos instancias de la clase Bicicleta desde cualquier otro Objeto teniendo
en cuenta que en estos momentos la Clase Bicicleta tiene declarado e inicializado de forma
explícita un Constructor sobrecargado.
Bicicleta b1 = new Bicicleta();
Bicicleta b2 = new Bicicleta("Cannondale");
Bicicleta b1 = new Bicicleta();
En este caso el entorno de ejecución Java utiliza:
El Constructor por defecto que realiza lo siguiente
- Inicializa la variable de instancia matricula a su valor por defecto que en este caso por
ser una Clase lo inicializa a valor null.
- Y obtiene una referencia al nuevo Objeto que se guarda en la variable de referencia b1
Bicicleta b2 = new Bicicleta("Cannondale");
En este caso el entorno de ejecución Java utiliza
Primeramente el Constructor por defecto que realiza lo siguiente:
-
Inicializa la variable de instancia matricula a su valor por defecto que en este caso
por ser una Clase lo inicializa a valor null
Y seguidamente el Constructor sobrecargado con un argumento de tipo String que
realiza lo siguiente: Inicializa la variable de instancia marca en este caso con el
valor "Cannondale" y obtiene una referencia al nuevo objeto que se guarda en la
variable de referencia b2
Ejemplo2.
En este ejemplo se declaran dos constructores de la clase point, el primero recibe dos
parámetros y establece las coordenadas x e y con dichos parámetros. Y el segundo
constructor establece en -1 los valores de x e y.
Programación orientada a objetos en Java
66
Unidad III. Constructor, Destructor (Recolector de basura)
Código 3.4.3 Constructores sobrecargados de la clase Punto. Uno que
recibe de parámetros dos valores enteros y el otro no recibe ningún
parámetro.
Primero se crea un objeto Point que llama al segundo constructor. En pantalla apareceran
los valores de x = -1 e y = -1.
Después se crea un segundo objeto que manda llamar al primer constructor. En pantalla
aparecerá los valores de x = 4 e y = 16.
Nota:
Se recomienda siempre declarar un Constructor sin argumentos independientemente de si
la clase tiene otro Constructor con argumentos por dos motivos
-
-
Primero, la mayoría de los asistentes de los entornos de desarrollo Java al crear la
plantilla de las Clases realizan las declaraciones de los Constructores sin
argumentos, simplemente se ahorra tener que borrar el código correspondiente a
la declaración del Constructor sin argumentos.
Segundo, el programador se asegura de posibles errores de compilación si en un
futuro desde otro Objeto decido además de crear una instancia de una Clase con
su Constructor sobrecargado, también crear una instancia de esa misma Clase con
un Constructor sin argumentos
Programación orientada a objetos en Java
67
Unidad III. Constructor, Destructor (Recolector de basura)
Tipos de Recolectores de Basura (Garbage Collectors)
Java utiliza un modelo de memoria conocido como "administración automática del
almacenamiento"36 en el que el sistema en tiempo de ejecución de Java mantiene un
seguimiento de los objetos. En el momento que no están siendo referenciados por alguien,
automáticamente se libera la memoria asociada con ellos. Existen muchas maneras de
implementar recolectores de basura, entre ellas se tienen:
•
•
36
37
Contabilizar referencias. La máquina virtual Java asocia un contador a cada
instancia de un objeto, donde se refleja el número de referencias hacia él. Cuando
este contador es 0, la memoria asociada al objeto es susceptible de ser liberada.
Aún cuando este algoritmo es muy sencillo y de bajo costo (en términos
computacionales), presenta problemas con estructuras de datos circulares.
Marcar e intercambiar37. Este es el esquema más común para implementar el
manejo de almacenamiento automático. Consiste en almacenar los objetos en un
montículo (heap) de un tamaño considerable y marcar periódicamente
(generalmente mediante un bit en un campo que se utiliza para este fin) los
objetos que no tengan ninguna referencia hacia ellos. Adicionalmente existe un
montón alterno, donde los objetos que no han sido marcados, son movidos
periódicamente. Una vez en el montículo alterno, el recolector de basura se
encarga de actualizar las referencias de los objetos a sus nuevas localidades. De
esta manera se genera un nuevo montículo, que contiene únicamente objetos que
están siendo utilizados.
Automatic Storage Managment.
Mark-and-sweep.
Programación orientada a objetos en Java
68
Unidad III. Constructor, Destructor (Recolector de basura)
3.6 Ejercicios propuestos
3.5.1 Realice un programa para realizar sumas de uno, dos, tres, cuatro o cinco dígitos
implementando constructores para inicializar los valores según sea el caso.
3.5.2 Realice un programa que calcule el área de cualquier triangulo, usando
constructores para asignar valores a las formulas.
3.5.3 Implemente un programa que calcule la serie de fibonacci entre dos rangos dados
previamente desde el teclado (variables ri y rf). Use un constructor para asignar valores a
ri y rf.
3.5.3
Escribir un programa que convierta un número romano (en forma de cadena de
caracteres) en número arabigo, utilizando al menos un constructor explicito.
3.5.4
Escribir un programa que usando métodos y un constructor encuentre el valor
mayor, el valor menor, y la suma de n números de entrada.
3.5.5
Escribir un método que calcule cuantos puntos de coordenadas enteras existen
dentro de un triangulo del que se conocen las coordenadas de sus tres vértices.
Use constructores.
3.5.6
Escriba un programa que utilice un método llamado CículoArea, que pida al usuario
la radio de un círculo e imprima el área de ese círculo. Declare al menos un
constructor explicito.
3.5.7
El máximo común divisor de dos enteros es el entero más grande que puede dividir
a cada uno de dos números. Escriba un método que devuelva el máximo común
divisor de dos números enteros. Use constructores.
3.5.8
Las computadoras están tomando un papel cada vez más importante en la
educación. Escriba un programa que ayude a un estudiante de escuela primaria,
para que aprenda a multiplicar. Use el método Math.random para producir dos
números enteros positivos de un dígito. El programa debe entonces mostrar una
pregunta en la barra de estado, como:
¿Cuánto es 6 x 7 ?
El estudiante debe escribir la respuesta, si es correcta el programa manda un mensaje de
“Muy bien” y si es incorrecta “Vuélvalo a intentar”. Use constructores.
3.5.10. Escribir un programa recursivo que calcule los N primero números naturales. Use
constructores.
Programación orientada a objetos en Java
69
Unidad IV. Sobrecarga
UNIDAD IV. SOBRECARGA
Conversión de Tipos y Sobrecarga de Métodos
Programación orientada a objetos en Java
70
Unidad IV. Sobrecarga
UNIDAD IV. SOBRECARGA
4.1 Conversión de Tipos
En Java es posible transformar el tipo de una variable u objeto en otro diferente al
original con el que fue declarado. Este proceso se denomina "conversión", "moldeado" o
"tipado". Si se tiene alguna experiencia previa en programación, se sabe que es bastante
común asignar un valor de un tipo a una variable de otro tipo.
Si los dos tipos son compatibles, Java realizará una conversión automática. Por
ejemplo, siempre es posible asignar un valor int a una variable long. Pero no todos los
tipos son compatibles, y en consecuencia, no todas las conversiones son implícitamente
posibles. Por ejemplo, no esta definida la conversión de double a byte, aunque,
afortunadamente, se puede obtener una conversión entre tipos incompatibles. Para ello,
se debe emplear un cast, que realiza una conversión explicita entre tipos incompatibles.
Las normas de conversión entre tipos numéricos son las habituales en un lenguaje
de Programación: si en una operación se involucran varios datos numéricos de distintos
tipos todos ellos se convierten al tipo de dato que permite una mayor precisión y rango de
representación numérica; así, por ejemplo:
•
•
•
Si cualquier operando es double todos se convertirán en double.
Si cualquier operando es float y no hay ningún double todos se convertirán a float
Si cualquier operando es long y no hay datos reales todos se convertirán en long
Del mismo modo estas normas se extenderán para int, short y byte.
En la conversión de tipos se establece la norma de que "en las conversiones el tipo destino
siempre debe ser igual o mayor que el tipo fuente":
Tipo Origen
Byte
Short
Char
Int
Long
Float
double,
double,
double,
double,
double,
double
Tipo Destino
float, long, int, char, short
float, long, int
float, long, int
float, long
float
Tabla 4.1 Conversiones sin pérdidas de información
Conversiones Automáticas de Java
Cuando a un tipo de variable se le asigna un tipo de datos, se realiza una conversión
automática de tipo siempre y cuando se cumplan estas dos condiciones:
• Los dos tipos son compatibles.
• El tipo de destino es más amplio que el tipo fuente.
Programación orientada a objetos en Java
71
Unidad IV. Sobrecarga
Si se cumplen estas dos condiciones, tiene lugar una conversión de ensanchamiento. Por
ejemplo, el tipo int siempre es suficientemente grande para guardar todos los valores byte
válidos, de manera que no se necesita una sentencia de conversión.
Para las conversiones de ensanchamiento, los tipos numéricos, incluyendo los enteros y de
coma flotante, son compatibles entre sí. Sin embargo, los tipos numéricos no son
compatibles con los char o los boolean; tampoco los char o los boolean son compatibles
entre sí.
Ejemplo: 1
Por ejemplo se puede asignar un valor de tipo byte a una variable int, Ya que byte e int
son compatibles y las variables int tienen un rango mayor que los valores byte. Por lo
tanto, no se perderá ningún dato en la conversión de tipos.
Código 4.1.1 Conversiones de tipo byte a tipo int
El compilador de Java no tiene ningún problema con este código y hace la conversión de
tipos automáticamente. Este es el resultado del programa
C:\>java app
int1 = 1
Este tipo de conversiones, en las que se convierte a un tipo de dato que tiene mayor
rango, se llama extensión de conversiones. En ellas, los tipos numéricos, como entero o
coma flotante, son compatibles entre sí. Por otro lado, los tipos char y boolean no son
compatibles entre sí y tampoco con los tipos numéricos.
Conversión de Tipos Incompatibles
Aunque la conversión automática de tipos es útil, o llega a satisfacer todas las
necesidades. Por ejemplo, ¿Qué ocurre si se intenta asignar un valor int a una variable
byte? Esta conversión no se realizará automáticamente porque un byte es menor que un
Programación orientada a objetos en Java
72
Unidad IV. Sobrecarga
int 38. Este tipo de conversiones recibe a menudo el nombre de conversión de
estrechamiento, porque se trata de estrechar el valor para que ajuste al tipo destino.
Para crear una conversión entre dos tipos incompatibles, ha de utilizarse una cast. Un cast
es simplemente una conversión explicita de tipos. Tiene esta forma general:
(tipo-de-destino) valor
Aquí, tipo-de-destino, especifica el tipo al que se desea convertir el valor determinado.
Por ejemplo, el siguiente fragmento convierte un int en un byte. Si el valor del entero es
mayor que el rango de un byte, se reducirá al módulo del rango del tipo byte.
Código 4.1.2 Conversión de tipos, de tipo int a tipo byte.
Este es el resultado de ejemplo anterior.
C:\>java app
byte1 = 1
Si no se hace explícitamente el cast, el compilador devolverá un error, pero con el cast de
tipos, no hay problema, ya que Java decide que se conoce la posibilidad de perder algunos
datos cuando se introduce un valor probablemente mayor en un tipo más pequeño. Por
ejemplo cuando se pone un número en coma flotante en un long, la parte fraccional del
número se truncará, y puede que se pierdan más datos si el valor en coma flotante esta
fuera del rango que un long puede gestionar.
Hay que tener en cuenta es que el compilador de Java convierte a un tipo de mayor
precisión, si es necesario, al evaluar expresiones. Por ejemplo, se va a considerar el
siguiente código, en el que parece que sólo hay bytes involucrados:
38
Conversión de estrechamiento.
Programación orientada a objetos en Java
73
Unidad IV. Sobrecarga
Código 4.1.3 Conversiones de tipos con perdida precisión.
Este código se compila y se ejecuta como se esperaba, pero no sería así sin el cast (byte):
C:\>java app
Byte3 = 100
Una conversión diferente tendrá lugar cuando se asigne un valor de coma flotante a un
tipo entero, en este caso, se trunca la parte decimal. Como ya se sabe, los enteros no
tienen componentes decimales, por lo que cuando a un entero se le asigna un valor en
coma flotante, el componente decimal se pierde. Por ejemplo si a un entero se le asigna el
valor 1,23, el valor resultante será simplemente 1. el 0,23 será truncado. El siguiente
programa es un ejemplo de algunas conversiones de tipo explicitas:
Código 4.1.4 Diferentes tipos de cast.
Programación orientada a objetos en Java
74
Unidad IV. Sobrecarga
La salida que produce este programa es:
Conversión de int a byte.
i y b 257 1
Conversión de double a int.
d y i 323.142 323
Conversion de double a byte.
d y b 323.142 67
Obsérvese cada una de estas conversiones. Cuando el valor 272 se convierte en una
variable byte, el resultado es el resto de la división de 257 entre 256 (el rango de un
byte), que es 1 en este caso. Cuando la d se convierte en int, su componente decimal
también se pierde, y ese valor se reduce al módulo 256, que en este caso es 67.
Promoción Automática de Tipo en Expresiones39
Las conversiones de tipos pueden realizarse, además de en las asignaciones, en las
expresiones. Para ver cómo sucede esto, se tiene en cuenta lo siguiente. En una
expresión, la precisión necesaria de un valor intermedio a menudo supera el rango de
cualquiera de los operándos. Por ejemplo, la siguiente expresión:
Byte a = 40;
Bye b = 50;
Byte c = 100;
Int d = a * b / c;
El resultado del término intermedio a * b puede superar fácilmente el rango de cualquiera
de sus operandos byte. Para tratar este tipo de problemas, Java promueve de una manera
automática cada operando byte o short a int. Cuando evalúa una expresión. Esto significa
que la subexpresíon a * b se calcula utilizando tipos enteros, no bytes. Por lo tanto, 2,000,
que es el resultado de la expresión intermedia 50 * 40, es valido aunque se hayan
especificado a y b como tipo byte
A pesar de lo útiles que resultan las promociones automáticas, pueden causar errores de
confusión en la compilación. Por ejemplo, este código, aparentemente correcto, puede
causar un problema:
Byte b = 50;
b = b * 2; // ¡Error! ! No se puede asignar un int a un byte!
Este código intenta almacenar 50 * 2, un valor de tipo byte perfectamente válido, en una
variable byte. Sin embargo, cuando se evaluó la expresión, los operandos se
promocionaron automáticamente al tipo int. Por lo tn anto, el tipo de la expresión ahora es
de tipo int, y no se puede asignar al tipo byte sin utilizar la conversión explícita. Esto se
39
Conversiones Implícitas
Programación orientada a objetos en Java
75
Unidad IV. Sobrecarga
verifica incluso en este caso particular, en el que el valor que se intenta asignar se ajusta
al tipo de destino.
En casos en los que se prevén las consecuencias del desbordamiento, se debería utilizar la
conversión explicita.
byte b = 50;
b = (byte) (b * 2);
Que conduce al valor correcto de 100.
4.2 Sobrecarga de Métodos
La sobrecarga de métodos es una técnica de la orientación a objetos que permite definir
diferentes versiones de un método, todos con el mismo nombre pero con diferente lista de
parámetros. Cuando se usa un método sobrecargado, el compilador de Java sabe cual es
el que se quiere utilizar por el numero y/o tipo de parámetros que se le pasen, y buscará
la versión del método con la lista de argumentos correcta.
En java dentro de una misma clase podemos definir dos o más métodos que compartan el
mismo nombre, aunque la declaración de sus parámetros sea diferente. Cuando éste es el
caso, se dice que los métodos están sobrecargados, y que el proceso es una sobrecarga
del método. La sobrecarga de métodos es una de las maneras en que Java implementa el
polimorfismo40. El polimorfismo es una de las características más interesantes de Java.
Cuando se llama a un método sobrecargado, Java utiliza el tipo y/o número de
argumentos como guía para determinar a qué versión del método sobrecargado se debe
llamar. Por lo tanto, los métodos sobrecargados han de ser diferentes en el tipo y/o
número de parámetros. Mientras que los métodos sobrecargados pueden tener diferentes
tipos, el tipo devuelto es por sí solo lo suficiente para distinguir dos versiones de un
método. Cuando Java encuentra una llamada a un método de sobrecarga, simplemente se
ejecuta la versión del método cuyos parámetros coinciden con los argumentos utilizados
en la llamada.
Ejemplo 1
Véase el siguiente ejemplo. Para sobrecargar un método, sólo hay que definirlo más de
una vez, especificando una nueva lista de parámetros en cada una de ellas. Cada lista de
parámetros deber ser diferente de cualquier otra de alguna forma, el número de
parámetros o el tipo de uno o más de ellos. Por ejemplo se creara una clase llamada
calculador con un método llamado “suma” que se sobrecarga dos veces. En la primera
declaración recibe dos números de parámetros y en la segunda declaración recibe tres
parámetros.
40
Se explicara detalladamente en los capítulos posteriores.
Programación orientada a objetos en Java
76
Unidad IV. Sobrecarga
Código 4.2.1 Sobrecarga de métodos.
Ahora se pueden usar ambos métodos en el código, como sigue:
Código 4.2.1 Sobrecarga de métodos. Uso de los métodos sobrecargados
en el código anterior.
Este es el resultado del programa:
C:\>java app
suma(2,2) = 4
suma(2,2,2) = 6
Como se puede ver, la sobrecarga proporciona una técnica potente, especialmente en el
código que se entrega a otros desarrolladores, porque permite pasar diferentes listas de
parámetros a un método, haciéndolo más fácil de usar de diferentes formas en el código.
Ejemplo 2
Aquí se tiene otro ejemplo sencillo que ilustra la sobrecarga de métodos:
Programación orientada a objetos en Java
77
Unidad IV. Sobrecarga
Código 4.2.1 Sobrecarga de métodos. Sobrecarga del método prueba.
Este programa genera la siguiente salida:
No tiene parámetros
a: 10
a y b: 10 20
a double: 123,25
Resultado de ob.prueba(2.67,12.68): = 15.35
Como se puede observar, el método prueba() se sobrecarga en cuatro ocasiones. La
primera versión no tiene parámetros, la segunda tiene un parámetro entero, la tercera
tiene dos parámetros enteros y la cuarta, dos parámetro double que suma y retorna el
valor de dicha suma. El hecho de que la cuarta versión de prueba() tambien devuelva un
valor no esta relacionado con la sobrecarga, ya que los tipos devueltos no desempeñan
ningún papel en la resolución de la sobrecarga. Cuando se llama a un método
sobrecargado, java busca las coincidencias entre los argumentos utilizados para llamar al
método y los parámetros del método, sin embargo, esta coincidencia no siempre tiene que
ser exacta. En algunos casos, las conversiones automáticas de tipos de Java pueden tener
su importancia en la resolución de sobrecarga.
Programación orientada a objetos en Java
78
Unidad IV. Sobrecarga
Por ejemplo, véase el siguiente programa:
Código 4.2.3 Aplicación de la conversión automática de tipos en la
sobrecarga de métodos.
Este programa genera la siguiente salida:
No tiene parametros
a y b: 10 20
prueba(double) a: 80
prueba(double) a: 123.2
Esta versión de SobrecargaDemo no se define define(int). Además, cuando se llama a
prueba() con un argumento entero dentro de sobrecarga, no se encuentra ninguna
coincidencia con los parámetros del método. Sin embargo, Java puede convertir
automáticamente un entero en double, y esta conversión puede utilizarse para resolver la
llamada. Por este motivo, cuando no se encuentra el método prueba(int), Java eleva i a
double y entonces llama a prueba(double). Por supuesto, si prueba (int) se hubiera
definido, este método hubiera sido llamado en lugar de prueba (double). Java empleará
este tipo de conversiones automáticas únicamente en caso de que no se encuentren
coincidencias exactas.
Programación orientada a objetos en Java
79
Unidad IV. Sobrecarga
Cuando se sobrecarga un método, cada versión de ese método puede realizar la actividad
que desee. No existe ninguna regla que establezca que los métodos de sobrecarga han de
relacionarse entre si, pero desde el punto de vista de estilo, la sobrecarga de métodos
implica la relación. Por consiguiente, aunque puede utilizarse el mismo nombre para
sobrecargar métodos que no están relacionados es mejor no hacerlo. Por ejemplo, podría
utilizarse el nombre sqr para crear métodos que devuelvan el cuadrado de un entero y la
raíz cuadrada de un valor en coma flotante, pero estas dos operaciones son muy distintas
y esto va en contra de un propósito original de la sobrecarga de métodos. En la práctica,
sólo se han de sobrecargar operaciones estrechamente relacionadas.
Sobrescritura de Métodos
En una jerarquía de clases, cuando un método de una subclase tiene el mismo nombre y
tipo que un método de superclase, se dice que el método de la subclase sobrescribe al
método de la superclase. Cuando se llama a un método sobrescrito desde una subclase,
esta llamada siempre se refiere a la versión de ese método definida por la subclase. La
versión del método definido por la superclases quedaría oculta. Véase el siguiente
ejemplo:
Código 4.2.4 Sobrescritura de métodos. Sobrecritura del método mostrar de
la subclase B sobre la superclase A.
Programación orientada a objetos en Java
80
Unidad IV. Sobrecarga
La salida que produce el programa es:
K=3
Cuando se llama a mostrar() en un objeto del tipo B, se utiliza la versión de mostrar()
definida en B; es decir, la versión mostrar() dentro de B domina sobre la versión declarada
en A. si se quiere acceder a la versión de la superclase de una función sobrescrita, se
utilizará el método super. Por ejemplo, en esta versión de la subclase. Esto permite
imprimir todas las variables de instancia:
Código 4.2.5 En este caso no se da sobrescritura del método “mostrar”
debido a que al llamarse se hace referencia al método de la superclase A
con la cláusula super.
La salida del código anterior es la siguiente:
i and j: 1 2
k:3
Aquí super.mostrar() llama a la versión de show de la superclase(). La sobrescritura de
métodos tan sólo se da cuando los nombres y el tipo de dos métodos son idénticos, si no
lo son, entonces los métodos simplemente están sobrecargados. Por ejemplo, véase esta
versión modificada del ejemplo anterior.
Programación orientada a objetos en Java
81
Unidad IV. Sobrecarga
Código 4.2.6 Los métodos con diferentes tipo de parámetros se
sobrecargan, no se sobrescriben.
La salida generada por este programa es la siguiente:
Este es k: 3
i y j: 1 2
La versión de mostrar() en B toma un parámetro de tipo string. Esto hace que su tipo sea
diferente al de A, que no toma parámetros. En consecuencia, no se la sobrescritura u
ocultamiento de nombre.
Programación orientada a objetos en Java
82
Unidad IV. Sobrecarga
4.3 Sobrecarga de Operadores 41
La sobrecarga de operadores permite redefinir ciertos operadores, para usarlos con las
clases que se definen. Se llama sobrecarga de operadores porque se están utilizando el
mismo operador con un número de usos diferentes, y el compilador decide cómo usar ese
operador dependiendo sobre qué opera.
La sobrecarga de operadores sólo se puede utilizar con objetos de clases, no se
pueden redefinir los operadores para los tipos simples predefinidos.
El Método toString()42
A veces es conveniente o necesario convertir un objeto a una cadena o String porque se
necesitará pasarlo a un método que sólo acepta Strings. Todas las clases heredan
toString() desde la clase Object y muchas clases del paquete java.lang sobreescriben este
método para proporcionar una implementación más acorde con la propia clase. Por
ejemplo, las clases Character, Integer, Boolean, etc.. sobreescriben toString() para
proporcionar una representación en String de los objetos.
La sobrecarga de operadores no se da en Java.
El método toString() como método de clase permite el uso implicito del operador sobrecargado
de concatenación ‘+’.
41
42
Programación orientada a objetos en Java
83
Unidad IV. Sobrecarga
4.4. Ejercicios resueltos
4.4.1 Implementar un programa que sume dos valores enteros y dos valores flotantes
implementando sobrecarga de métodos.
4.4.2 Implementar un programa que calcule el área de dos rectángulos utilizando
sobrecarga de constructores.
Programación orientada a objetos en Java
84
Unidad IV. Sobrecarga
4.4.3 Implementar un programa que reciba dos valores enteros a y b. Si a > b hacer a/b,
si a < b hacer suma de a+b y si son iguales, mandar el mensaje de igualdad. Usar
sobrecarga de métodos.
Programación orientada a objetos en Java
85
Unidad IV. Sobrecarga
Programación orientada a objetos en Java
86
Unidad IV. Sobrecarga
4.5 Ejercicios Propuestos
4.5.1 Escribir las sentencias de asignación que permitan intercambiar los contenidos de los
valores de dos variables.
4.5.2 Escriba un programa que lea dos enteros en la variables x e y, y a continuación
obtenga los valores de 1: x /y, 2: x % y. ejecutar el programa varias veces con diferentes
pares de enteros como entrada.
4.5.3 Escribir un programa que convierta un número dado en segundos en equivalente de
minutos y segundos.
4.5.4 Determinar si el carácter asociado a un código introducido por teclado corresponde a
un carácter alfabético, dígito, de puntuación, especial o no imprimible. Usar sobrecarga de
métodos.
4.5.5 Escribir un programa que mediante métodos determine el área del circulo
correspondiente a la circunferencia circunscrita de un triangulo del que se conoce las
coordenada de los vértices.
4.5.6 Construir un programa que calcule y escriba el producto, cociente entero y resto de
dos números de tres cifras.
4.5.7 La fuerza de atracción entre dos masas, m1 y m2, separadas por una distancia d,
está dada por la formula:
F= G * m1 * m2 / d2
Escribir un programa que lea la masa de dos cuerpos y la distancia entre ellos y a
continuación obtenga la fuerza gravitacional entre ella. La salida debe ser en dinas. Una
dina es igual a gr.cm/seg2.
4.5.8 la realción entre los dos lados (a,b) de un triángulo y la hipotenusa (h) viene dada
por la formula a2 + b2 = h2. Escribir un programa que lea la longitud de los lados y calcule
la hipotenusa.
4.5.9 Escribir un programa que determine si un año es bisiesto. Un año es bisiesto si es
múltiplo 4 por ejemplo, 1984. sin embargo, los años múltiplos de 100 sólo son bisiestos
cuando a la vez son múltiplos de 400. por ejemplo, 1800 no es bisiesto, mientras que 200
si lo será.
4.5.10 Usando sobrecarga de métodos, mplementar un programa que realice todas las
operaciones básicas (suma, resta, multiplicación y división) con dos números dados.
Programación orientada a objetos en Java
87
Unidad V. Herencia
UNIDAD V. HERENCIA
Herencia Simple, Herencia Múltiple, Clases Base, Clase Derivada, Miembros de las
Clases Derivadas y Aplicaciones de Herencia
Programación orientada a objetos en Java
88
Unidad V. Herencia
UNIDAD V. HERENCIA
5.1 Introducción a la Herencia
En la programación orientada existe la herencia, una de las características principales de
programación orientada a objetos43. La herencia es una forma de reutilización del software
en la que las clases, se crean absorbiendo los datos (atributos) y métodos
(comportamientos) de una clase existente, y se mejoran con nuevas capacidades, o con
modificaciones en las capacidades ya existentes. La reutilización de software ahorra
tiempo durante el desarrollo de programas. También fomenta la reutilización de software
probado y depurado de alta calidad, el cual aumenta la probabilidad de que un sistema se
implemente con efectividad.
La herencia es una de las piedras angulares de la programación orientada a objetos
porque permite la creación de clasificaciones jerárquicas. Mediante la herencia el
programador puede crear una clase general que defina los rasgos comunes de un
conjunto de términos relacionados. Esa clase puede ser heredada por otras clases mas
especificas, cada unas de las cuales añadirá aquellos rasgos que las hace únicas.
Al crear una clase, en vez de declarar miembros (variables y métodos) completamente
nuevos, el programador puede designar que la nueva clase herede los miembros de una
clase existente. Esta clase existente se conoce como superclase, y la nueva clase se
conoce como subclase. Una vez creada cada subclase puede convertirse en superclase de
futuras subclases. Una subclase generalmente agrega sus propias variables y métodos,
por lo tanto una subclase es más específica que una superclase y representa a un grupo
mas especializado de objetos. Generalmente la subclase exhibe los comportamientos de su
superclase junto los comportamientos específicos de esta subclase. La superclase, es la
superclase directa a partir de la cual la subclase hereda en forma explicita. Una superclase
indirecta se hereda de dos o más niveles arriba en la jerarquía de clases, la cual define las
relaciones de herencia entre las clases.
La experiencia en la creación de sistemas de software indica que algunas cantidades
considerables de código tratan con casos especiales, estrechamente relacionados. Cuando
los programadores se preocupan con casos especiales, los detalles pueden oscurecer el
panorama general. Con la programación orientada a objetos, los programadores se
enfocan en los elementos comunes entre los objetos en el sistema, en vez de enfocarse en
los casos especiales. A este proceso se conoce como abstracción.
En Java existen los términos comunes “tiene un” y “es un”. Es necesario hacer una
diferencia entre la relación “es un” y la relación “tiene un”. La relación “es un” representa
la Herencia; en este tipo de relación, un objeto de una subclase puede tratarse también
como un objeto de sus superclases. Por ejemplo un auto es un vehiculo. En contraste, la
relación “tiene un” identifica a la composición; en este tipo de relación, un objeto contiene
43
POO.
Programación orientada a objetos en Java
89
Unidad V. Herencia
una o más referencias a objetos como miembros. Por ejemplo, un auto tiene un volante
de dirección.
Las clases nuevas pueden heredar de las clases en diversas bibliotecas de clases. Las
organizaciones desarrollan sus propias bibliotecas de clases y pueden aprovechar las que
ya están disponibles en todo el mundo.
En la siguiente figura 9, se tiene una clase bicicleta que es superclase de bicicleta de
montaña, bicicleta de camino y bicicleta de dos asientos.
Bicicleta
Bicicleta
de
montaña
Bicicleta
de camino
Bicicleta
tandem
Figura 9: Clase bicicleta
5.2 Herencia Simple
La herencia simple es uno de los aspectos de la programación orientada a objetos que se
ha definido formalmente. La herencia simple, se puede definir como la herencia en la cual
una clase hereda los métodos y atributos de solo una clase superior. En éste tipo de
herencia una clase se extiende a partir de una sola superclase. La herencia múltiple, es la
posibilidad de que un objeto tenga la herencia de más de una clase; esta ventaja fue
considerada por los desarrolladores pero al final no la incluyeron por lo cual Java no lo
contempla.
Utilizando la herencia simple, se puede derivar una nueva clase a partir de la base. La
clase nueva se llama clase derivada y la clase original, clase base. La idea es añadir lo que
se quiera a la nueva clase para darle más funcionalidad que a la clase base.
A menudo un objeto de una clase “es un” objeto de otra clase también. Por ejemplo, en la
geometría un rectángulo es un cuadrilátero (al igual que los cuadrados, los paralelogramos
Programación orientada a objetos en Java
90
Unidad V. Herencia
y los trapezoides). Por lo tanto en Java puede decirse que la clase Rectángulo hereda de
la clase Cuadrilátero. En este contexto la clase Cuadrilátero es una superclase, y la clase
Rectángulo es una subclase. Un rectángulo es un tipo específico de cuadrilátero, pero es
incorrecto decir que todo cuadrilátero es un rectángulo; el cuadrilátero podría ser un
paralelogramo o alguna otra figura. En la siguiente tabla se muestran ejemplos sencillos
de superclases y subclases.
Superclase
Estudiante
Figura
Prestamo
Empleado
CuentaBancaria
Subclases
EstudianteGraduado,EstudianteNoGraduado
Circulo, Triangulo, Rectangulo
PrestamoAutomovil, PrestamoMejoraCasa, PrestamoHiopotecario
Docente, Administrativo
CuentaDeCheques, CuentaDeAhorros
Como todo objeto de una subclase “es un” objeto de su superclase, y como una
superclase puede tener muchas subclases, el conjunto de objetos representados por una
superclase generalmente es mas grande que el conjunto de objetos representado por
cualquiera de sus subclases. Por ejemplo la superclase Vehiculo representa a todos los
vehículos, incluyendo autos, camiones, barcos, bicicletas, etc. En contraste, la clase Auto
representa a un subconjunto más pequeño y específico de todos los vehículos.
Las relaciones de herencia forman estructuras jerárquicas en forma de árbol. Una
superclase existe en una relación jerárquica con sus subclases. Aunque las clases pueden
existir de manera independiente, cuando participan en relaciones de herencia se afilian
con otras clases. Una clase se convierte ya sea en una superclase, proporcionando datos y
comportamientos a otras clases, o en una subclase, heredando sus datos y
comportamientos de otras clases.
Es posible tratar a los objetos de superclases y a los objetos de subclases de manera
similar; sus similitudes se expresan en los miembros de la superclase. Los objetos de
todas las clases que extienden a una superclase común pueden tratarse como objetos de
esa superclase (es decir, dichos objetos tienen una relación “es un” con la superclase). Sin
embargo, los objetos de una superclase no pueden tratarse como objetos de sus
subclases. Por ejemplo, todos los autos son vehículos pero no todos los vehículos son
autos.
Un problema con la herencia es que una subclase puede heredar métodos que no
necesita, o que no debe tener. A pesar de que en un método de superclase sea apropiado
para una subclase, a menudo esa subclase requiere que el método realice su tarea de una
manera específica para la subclase. En dichos casos, la subclase puede sobrescribir44 el
método de la superclase con una implementación apropiada.
44
Redefinir.
Programación orientada a objetos en Java
91
Unidad V. Herencia
Ejemplo 1
Se tiene la clase Ave, se puede crear la subclase Pato, que es una especialización de Ave.
class Pato extends Ave { int numero_de_patas; }
La palabra clave extends 45 se usa para generar una subclase (especialización) de un
objeto. Una Pato es una subclase de Ave. Cualquier cosa que contenga la definición de
Ave será copiada a la clase Pato, además, en Pato se pueden definir sus propios métodos
y variables de instancia. Se dice que Pato deriva o hereda de Ave.
Además, se pueden sustituir los métodos proporcionados por la clase base
En Java no se puede hacer herencia múltiple 46. Por ejemplo, de la clase aparato con
motor y de la clase animal no se puede derivar nada, sería como obtener el objeto toro
mecánico a partir de una máquina motorizada (aparato con motor) y un toro (animal). En
realidad, lo que se pretende es copiar los métodos, es decir, pasar la funcionalidad del
toro de verdad al toro mecánico, con lo cual no sería necesaria la herencia múltiple sino
simplemente la comparación de funcionalidad.
Ejemplo 2
La herencia simple se puede ilustrar con un ejemplo sencillo como el siguiente:
Código 5.1.1 Ilustración de herencia simple.
Esta clase no está muy completa así, pero da una idea… Es una clase heredera de la clase
Frame (un tipo de ventana) que tiene un par de botones y un texto. Contiene los atributos
45
46
Extender de
En Java se solucionan esos problemas con la implementación de Interfaces.
Programación orientada a objetos en Java
92
Unidad V. Herencia
("si" y "no"), que es dos objetos del tipo Button, y un constructor llamado Muestra (igual
que la clase, por lo que es lo que se llama un constructor).
Ejemplo 3
Cuando en Java se indica que una clase “extends” otra clase se esta indicando que es una
clase hija de esta y que, por lo tanto, hereda todos sus métodos y variables.
Código 5.1.2 Herencia. La clase Perro hereda métodos y
características de la superclase Animal.
Programación orientada a objetos en Java
93
Unidad V. Herencia
Se puede observar un objeto de tipo perro creado invocando al constructor por defecto
perro(). Se puede observar como la variable edad se ha inicializado a 0, y la variable
nombre a “Tobi”, como se indicó en el constructor. Así mismo se ve como el objeto perro
ha heredado todos los métodos definidos en la clase animal.
5.3 Herencia Múltiple
La herencia múltiple es una de las oportunidades que ofrece el lenguaje c++ y es la
posibilidad de que un objeto tenga la herencia de más de una clase; esta ventaja fue
considerada por los desarrolladores de Java como una pega y la quitaron, e incluso hay
desarrolladores de c++ que prefieren evitar este tipo de herencia ya que puede complicar
mucho la depuración de programas Para ilustrar un caso de herencia múltiple se ha
definido la superclase Animal de ella heredan dos clases distintas: Mamífero y Vertebrado .
Ahora se quiere definir un objeto que tiene propiedades de esas dos clases: Hiena, ya que
es un animal mamífero y además es vertebrado.
5.4 Clase Base y Clase Derivada
5.4.1 Definición de la Clase Base
Clase base. También se le llama superclase, es la clase que hereda los métodos y atributos
a la clase derivada o clase base.
Código 5.1.3 Declaración de una clase base o superclase.
5.4.1.2 Declaración de la Clase Base
La declaración de una clase base o superclase es una declaración normal. La siguiente es
la definición más simple de una clase:
Como se puede observar, la definición de una superclase consta de dos partes
fundamentales:
* La declaración de la superclase
Indica el nombre de la superclase precedido por la palabra clave class.
Programación orientada a objetos en Java
94
Unidad V. Herencia
* El cuerpo de la superclase
El cuerpo de la clase sigue a la declaración de la clase y está contenido entre la pareja de
llaves ({ y }). El cuerpo de la clase contiene las declaraciones de las variables de la clase,
y también la declaración y la implementación de los métodos que operan sobre dichas
variables.
5.4.2 Definición de Clase Derivada
Clase derivada. También se le conoce como “subclase” es aquella que hereda los métodos
y atributos de la superclase o clase base.
5.4.2.2 Declaración de la Clase Derivada
En la declaración de la subclasese utiliza la palabra reservada extends para especificar que
dicha clase heredera los métodos de la superclase:
Código 5.1.4 Declaración de una subclase.
La extensión de clases se lleva a cabo mediante la cláusula extends. Extends establece
una relación de especialización –generalización entre clases. La clase extendida es la
superclase. La clase que se extiende es la subclase. Una clase puede tener, a lo sumo, una
superclase47. La subclase puede introducir nuevos métodos. Así mismo, la subclase puede
redefinir métodos de la superclase
Ejemplo:
Supóngase que se tiene una clase llamada “numeros_imaginarios” que hereda métodos o
que es subclase de “numeros”, la declaración de dicha clase sería:
47
De hecho en Java toda clase tiene su superclase.
Programación orientada a objetos en Java
95
Unidad V. Herencia
5.5 Parte Protegida48
5.5.1 Propósito de la Parte Protegida
Intuitivamente, protected49 se utiliza para aquellos atributos y métodos que pueden ser
únicamente accedidos a nivel de subclase. De esta forma, la parte protegida de una clase
es aquella parte que se publica únicamente a los implementadores que extienden la clase.
No obstante, su significado es más sutil. Un miembro protegido puede ser referido desde
el código de una clase a través de referencias a objetos que son, al menos, del mismo tipo
que dicha clase. Los identificadores creados en la parte protegida no serán accesibles
desde otros programas o módulos, pero sí tendrán acceso a ellos aquellos objetos que
sean derivados del nuestro
También pueden ser accedidos desde cualquier clase que pertenece al paquete de la
clase que lo declara.
Constructores en las clases Derivadas
El constructor de una clase derivada puede llamar al constructor de su clase base
mediante la palabra super.
Subclase(lista_parámetros){
super(lista_parámetros);
// sentencias adicionales
}
Si no se llama explícitamente al constructor de la clase base, se llama automáticamente al
constructor por defecto de la clase base.
5.5.1.1 Llamada a constructor por defecto.
48
49
Protected
Protegido(a).
Programación orientada a objetos en Java
96
Unidad V. Herencia
5.6 Redefinición de los miembros de las clases derivadas
El uso de super
Además se podría pensar en redefinir algunos métodos de la clase base pero haciendo que
métodos con el mismo nombre y características se comporten de forma distinta. Por
ejemplo se podría pensar en rediseñar el método toString de la clase Empleado añadiendo
las características propias de la clase Ejecutivo. Así se podría poner:
5.6.1. Redefinición de métodos utilizando “super”.
De esta forma cuando se invoque jefe.toString() se usará el método toString de la clase
Ejecutivo en lugar del existente en la clase Empleado.
Obsérvese en el ejemplo el uso de super, que representa referencia interna implícita a la
clase base (superclase). Mediante super.toString() se invoca el método toString de la
clase Empleado
Inicialización de clases derivadas
Cuando se crea un objeto de una clase derivada se crea implícitamente un objeto de la
clase base que se inicializa con su constructor correspondiente. Si en la creación del objeto
se usa el constructor no-args 50, entonces se produce una llamada implícita al constructor
no-args para la clase base. Pero si se usan otros constructores es necesario invocarlos
explícitamente.
Ejemplo:
50
Constructor por defecto.
Programación orientada a objetos en Java
97
Unidad V. Herencia
Código. 5.6.2 Uso de “super” en la inicialización de clases derivadas.
Observe que el constructor de Ejecutivo invoca directamente al constructor de Empleado
mediante super(argumentos). En caso de resultar necesaria la invocación al constructor de
la superclase debe ser la primera sentencia del constructor de la subclase.
5.7 Clases Virtuales y Visibilidad
Virtual es una palabra clave que tiene dos acepciones completamente diferentes
dependiendo del contexto de su utilización. Utilizada con nombres de clase sirve para
controlar aspectos del mecanismo de herencia; utilizada con nombres de funcionesmiembro, controla aspectos del polimorfismo y del tipo de enlazado que se utiliza para
tales funciones51
5.8 Constructores en Clases Derivadas
En el tema de la herencia, los constructores no se heredan, por ejemplo:
Código. 5.8.1 Los constructores no se heredan.
51
Java no soporta las clases virtuales.
Programación orientada a objetos en Java
98
Unidad V. Herencia
B b = new B(1,2); // error, los constructores no se heredan
Código. 5.8.2. Invocación del constructor de la clase base utilizando
“super”.
La invocación del constructor de A siempre debe ser la primera instrucción del constructor
de B. El principio es que en B las componentes de la clase base (A) deben inicializarse
antes que las componentes que se agregan en la clase B.
5.9 Aplicaciones
Aplicación 1. Ejemplo Práctico de Herencia
Véase ahora un ejemplo más práctico que ayudará a ilustrar el poder de la herencia
utilizando la clase box.
Programación orientada a objetos en Java
99
Unidad V. Herencia
Programación orientada a objetos en Java
100
Unidad V. Herencia
Código. 5.9.1. Se extiende la clase box para agregarle un cuarto
componente que es peso. Por lo tanto, la nueva clase contiene el largo,
el ancho, el alto y el peso de la caja.
La salida de este programa es:
El voulmen de micaja1 es 3000.0
El peso de micaja1 es 34.3
El volumen de micaja2 es 24.0
El peso de micaja2 es 0.076
BoxPeso hereda todas las características de Box y añade el componente peso. No es
necesario que BoxPeso vuelva a crear todas las características de Box, le basta con
ampliar la clase Box.
La principal ventaja de la herencia es que, una vez se ha creado una superclase que
define los atributos comunes a un conjunto de objetos, puede utilizarse para crear
cualquier número de subclases más específicas. Cada subclase puede adoptar de forma
mas precisa su propia clasificación. Por ejemplo:
Programación orientada a objetos en Java
101
Unidad V. Herencia
Código. 5.9.2. La clase ColorCaja hereda de Box y añade un
atributo del color.
Hay que recordar que una vez se ha creado la superclase que define los aspectos
generales de un objeto, esta superclase puede heredarse para formar clases
especializadas. Cada subclase simplemente añade sus propios atributos. Ésa es la esencia
de la herencia.
Aplicación 2. Herencia derivando la clase figura.
La clase base es Figura, y de ella van a heredar las clases Poligono y Circulo. A su vez, de
Poligono heredarán las clases Cuadrado y Triangulo. El diagrama esquemático de clases es
el siguiente:
La clase base Figura solo tiene dos atributos: nombre de la figura y perímetro (longitud
total de su borde exterior) y, aparte del constructor, un único método llamado
imprimirInformacion que imprime por pantalla la información de la figura.
Aquí está la clase como se muestra en el código 5.9.3.
Código. 5.9.3. Clase Figura programada.
En el método main, crea tres objetos y luego imprime la información de cada uno de ellos:
un cuadrado de lado 2 metros, un círculo de radio 2 metros y un triángulo de lado 3
metros.
Programación orientada a objetos en Java
102
Unidad V. Herencia
Compila y ejecuta el programa. La salida por pantalla debe ser la siguiente:
Soy un cuadrado y mi perímetro es 8.0 m
Soy un círculo y mi perímetro es 12.5663704 m
Soy un triángulo y mi perímetro es 9.0 m
Aplicación 3 Clase Circulo.
Ahora se va a programar la clase Circulo, que hereda de la clase anterior Figura. Esta
nueva clase tiene un atributo más (aparte de los heredados), de tipo double, que
almacena el radio del círculo, que se le pasa en el constructor. El radio sirve para calcular
el perímetro del círculo (2*pi*radio).
Además esta clase sobre escribe el método anterior imprimirInformacion para añadir un
mensaje más explicativo con el valor del radio.
El código de la clase Circulo se muestra en el código 5.9.4:
Código 5.9.4. Clase circulo.
Modifica el método main, y crea dos objetos de la clase Circulo, uno de radio 2 metros y
otro de radio 3 metros, e imprime su información. Tras compilar y ejecutar el programa, la
salida por pantalla debe ser la siguiente:
Soy un círculo y mi radio es 2.0 m, con lo que mi perímetro es 12.5663704 m
Soy un círculo y mi radio es 3.0 m, con lo que mi perímetro es 18.849555600000002 m
Aplicación 4. Clase polígono.
Ahora toca la clase Poligono, muy parecida a la clase Circulo anterior. La diferencia es
que en vez de radio los atributos del polígono son el número de lados y la longitud de
cada lado, con los que podemos calcular el valor del perímetro.
Programación orientada a objetos en Java
103
Unidad V. Herencia
Este ejercicio consiste en programar la clase Poligono. En el método main crea dos
polígonos, uno de 3 lados con longitud 3 (triángulo) y otro de 4 lados con longitud 4
(cuadrado).
El esqueleto de la clase se muestra en el código 5.9.5:
Código 5.9.5 Clase polígono.
La salida en pantalla debe ser la siguiente:
Soy un polígono cuadrado, tengo 4 lados de longitud 2.0 m, con lo que mi perímetro es 8.0 m
Soy un polígono triángulo, tengo 3 lados de longitud 3.0 m, con lo que mi perímetro es 9.0 m
Aplicación 5. Clase cuadrado y triangulo.
Sólo quedan las clases Cuadrado y Triangulo, que derivan de la clase Poligono. Estas dos
clases no tienen atributos nuevos y ni siquiera sobreescriben el método
imprimirInformacion.
Programa las dos clases. En cada una de ellas, añade un main que cree dos objetos.
Los esqueletos de las clases son los siguientes:
Programación orientada a objetos en Java
104
Unidad V. Herencia
Código 5.9.6 Clase cuadrado.
Código 5.9.7 clase triangulo.
Aplicación 7. Creación de una jerarquía multinivel
Se pueden construir jerarquías que contengan tantos niveles de herencia como se quiera.
Es totalmente aceptable utilizar una subclase como una superclase de otra. Por ejemplo,
en las clases A, B y C, C puede ser la subclase de B, que a su vez es una subclase de A.
cuando se da esta situación, cada subclase hereda todos los rasgos de sus superclases. En
este caso, C hereda todos los aspecto de B y A, para ver la utilidad de una jerarquía
multinivel, observe el siguiente ejemplo:
Programación orientada a objetos en Java
105
Unidad V. Herencia
Programación orientada a objetos en Java
106
Unidad V. Herencia
Programación orientada a objetos en Java
107
Unidad V. Herencia
Código. 5.9.8 En las tres secciones de código anteriores, la subclase
BoxPeso se utiliza como una superclase para crear la subclase llamada
Transporte. transporte hereda todas las características de BoxPeso y Box,
y añade un campo llamado costo, que contiene el coste del envió del
paquete.
La salida del programa es:
El Volumen de transporte1 es 3000.0
El peso de transporte1 10.0
Costo de Transporte1: $3.41
El volumen del transporte2 es 24.0
El peso de transporte2 es 0.76
Costo de transporte2: $1.28
Gracias a la herencia, Transporte 52 puede utilizar las clases Box y BoxPeso definidas
previamente, añadiendo sólo la información adicional que necesita para su aplicación
especifica. La reutilización del código es una de las ventajas de la herencia. Este ejemplo
pode de relieve otro aspecto importante: super() siempre hace referencia al constructor de
la superclase más próxima. El método super() en Transporte llama al constructor de Box.
En una jerarquía de clases, si el constructor de una superclase necesita parámetros,
entonces todas las subclases han de pasar esos parámetros en línea ascendente. Esto es
así tanto si la subclase necesita esos parámetros como si no.
52
Transporte.
Programación orientada a objetos en Java
108
Unidad V. Herencia
ORDEN DE EJECUCION DE LOS CONSTRUCTORES
Cuando se crea una jerarquía ¿En qué orden se ejecutan los constructores de las clases
que forman esa jerarquía? Por ejemplo, con una subclase llamada B y una superclase
llamada A. ¿Se ejecutará el constructor A antes que el B, o a la inversa? La respuesta es
que en la jerarquía de clases, los constructores se ejecutan en el orden en que se derivan,
es decir, desde la superclase a la subclase. Además, dado que super() tiene que ser la
primera sentencia que se ejecute en el constructor de una subclase, este orden es el
mismo tanto si se usa super() como si no. En el caso de que no se utilice super(), se
ejecutará el constructor por defecto o el constructor sin parámetros de cada superclase. El
siguiente ejemplo muestra el momento en que se ejecutan los constructores:
Código 5.9.9. Orden de ejecución de constructores en una jerarquía
de clases.
La salida de este programa es::
Dentro del constructor A
Dentro del constructor B
Dentro del constructor C
Como se ve, los constructores se ejecutan en el orden en que se derivan. Esto es lógico,
ya que una superclase no conoce sus subclases y cualquier inicialización que necesite
realizar es independiente, y posiblemente un requisito previo para cualquier inicialización
realizada por la subclase, por lo que se debe ejecutar en primer lugar.
Programación orientada a objetos en Java
109
Unidad V. Herencia
5.10 Ejercicios propuestos.
5.10.1 Implementar una clase Automóvil (carro) dentro de una jerarquía de herencia.
Considere que además de ser un vehiculo, un automóvil es también una comodidad, un
símbolo de estado social, un modo de transporte etc.
5.10.2 Implementar una jerarquía de herencia de animales tal que contenga al menos seis
niveles de derivación y doce clases.
5.10.3 Deducir las clases necesarias para diseñar un programa de ordenador que permita
jugar a diferentes juegos de cartas.
5.10.4 Confeccionar una clase Persona que tenga como atributos el nombre y la edad.
Definir como responsabilidades un método que cargue los datos personales y otro que los
imprima. Plantear una segunda clase Empleado que herede de la clase Persona. Añadir un
atributo sueldo y los métodos de cargar el sueldo e imprimir su sueldo.
Definir un objeto de la clase Persona y llamar a sus métodos. También crear un objeto de
la clase Empleado y llamar a sus métodos.
5.10.5 Elaborar una jerarquía de herencia que modele los seres vivos capaces de hablar.
Las clases deben modelar al menos a los loros, los profesores y los alumnos. Todas las
clases elaboradas deben disponer de un método habla sin argumentos que proporcione
una salida por pantalla similar a la siguiente:
Hola, me llamo Pedro y se hablar.
Soy racional.
Tengo 40 años.
Nací el 1 de enero de 1965
Soy profesor.
Para que el ejercicio sea interesante es necesario que todos los objetos habladores tengan
un conjunto de características que les diferencian de los demás, por ejemplo, que los loros
no sean conscientes de su edad o su fecha de nacimiento.
5.10.6 Los loros del ejercicio anterior no pueden ser universitarios simultáneamente, pero
un profesor puede ser también alumno. Elaborar un conjunto de clases que permitan
modelar esta situación de forma que un objeto pueda cambiar su forma de hablar en
tiempo de ejecución en función de la recepción de algún mensaje adecuado.
5.10.7 Escribir un programa que lea del dispositivo estándar de entrada los datos para
crear una lista de personas: a) general; b) estudiantes; c) empleados; d) estudiantes
empleados. El programa debe permitir ordenar alfabéticamente por el primer apellido.
5.10.8 implementar una jerarquía Librería que tenga al menos una docena de clases.
Considérense una librería que tenga colecciones de libros de literatura, humanidades,
tecnología, etc.
Programación orientada a objetos en Java
110
Unidad V. Herencia
5.10.9 Implementar una jerarquía de tipos datos númericos que extienda los tipos de
datos fundamentales tales como int y float, disponibles en Java. Las clases a diseñar
pueden ser complejo, vector, matriz, etc.
Programación orientada a objetos en Java
111
Unidad VI. Polimorfismo
UNIDAD VI. POLIMORFISMO Y REUTILIZACION
Concepto de Polimorfismo, Clases Abstractas, Definición e Implementación de una
Interfaz, Definición y creación de Paquetes.
Programación orientada a objetos en Java
112
Unidad VI. Polimorfismo
UNIDAD VI. POLIMORFISMO
6.1 Concepto de polimorfismo
El concepto de Polimorfismo es uno de los fundamentos para cualquier lenguaje orientado
a Objetos, las mismas raíces de la palabra pueden ser una fuerte pista de su significado:
Poli = Multiple, morfismo= Formas , esto implica que un mismo Objeto puede tomar
diversas formas.
A través del concepto de Herencias
53
es posible ilustrar este comportamiento:
Figura 10: Ilustración del polimorfismo.
El poder manipular un Objeto como si éste fuera de un tipo genérico otorga mayor
flexibilidad al momento de programar con Objetos, el término Polimorfismo también es
asociado con un concepto llamado Late-Binding54, obsérvese el siguiente fragmento de
código:
Figura a = new Circulo();
Figura b = new Triangulo();
Inicialmente se puede pensar que este código generaría un error debido a que el tipo de
referencia es distinta a la instancia del objeto, sin embargo, el fragmento anterior es
correcto y demuestra el concepto de Polimorfismo.
El polimorfismo permite “programar en forma general”, en vez de “programar en forma
específica”. En especial, el polimorfismo nos permite escribir programas que procesen
53
54
Inheritance.
Ligamiento Tardío.
Programación orientada a objetos en Java
113
Unidad VI. Polimorfismo
objetos de clases que formen parte de la misma jerarquía de clases, como si todos fueran
objetos de sus superclases.
El polimorfismo en java consiste en declarar y definir varios métodos con el mismo
nombre, pero con diferente número y/o tipo de argumentos y que realizan diferentes
operaciones. Sin embargo, el tipo que devuelven los métodos debe coincidir.
Java es un lenguaje totalmente orientado a objetos, y como tal podemos utilizar las
propiedades que este tipo de programación ofrece. Una de estas propiedades es el
polimorfismo, pero ¿Qué es el polimorfismo?. La palabra polimorfismo significa múltiples
formas y es la propiedad que tiene un lenguaje de programación de que una clase
(conjunto de objetos con características en común), pueda tener diferentes
comportamientos.
Imagínese que es responsable de programar un editor de facturas, el cual tendrá dos
salidas, una es el envió de la factura por fax y la otra es la impresión de la factura. Si el
programa encargado enviar faxes y el de impresión ya están elaborados, y solo pueden
ser utilizados por documentos que puedan ser faxeados y documentos que puedan ser
impresos respectivamente, como se puede adicionarlos al editor para faxear e imprimir las
facturas.
Para el problema descrito anteriormente una buena opción es aplicar polimorfismo, para
que la clase Factura pueda tener el comportamiento adicional que necesita, es decir,
pueda ser de tipo documento faxeable o documento imprimible y los módulos de envió de
fax e impresión se utilicen sin hacerles ningún cambio.
La figura 11 muestra como la clase cliente Factura hace uso de los servicios de la clase
Fax
e
Impresora
implementando
las
interfaces
DocumentoFaxeable
y
DocumentoImprimible respectivamente, por lo tanto la clase Factura se puede comportar
como un objeto de la clase DocumentoFaxeable y/o DocumentoImprimible, y son estos
tipos de objetos los únicos que son aceptados por las clases Impresora y Fax.
Figura 11: Polimorfismo y reutilización
Programación orientada a objetos en Java
114
Unidad VI. Polimorfismo
Existe otra forma de utilizar polimorfismo sin tener que implementar un contrato, es por
medio de herencia, la herencia permite que una clase padre “herede” sus características a
una clase hija, y establece que clase hija será del tipo de la clase padre y tendrá sus
características55 y comportamientos56. Una de las utilidades de la herencia es que se
puede crear una clase General (propiedades y características en común) y clases hijas que
solo modificarán la parte que ellas requieren, permitiendo así que tengan el
comportamiento de la clase padre con sus propias características, y como valor agregado
la reutilización de código.
Supóngase que ahora se esta encargado de programar la parte de administración de
clientes de una aplicación de ventas, y se sabe que existen dos tipos de clientes
candidatos a clases, el cliente que tiene las características de un cliente común, y el cliente
preferencial que tiene todas las propiedades del cliente común pero además se le aplican
descuentos, ¿Es necesario programar cada tipo de cliente por separado? ¿Si aparece otro
tipo de cliente se programará desde cero?....No. Utilizando herencia la clase Cliente puede
ser nuestra clase padre y la clase ClientePreferencial la clase hija de Cliente que en cada
compra se le aplicará un descuento y si apareciera otro tipo de cliente, solo heredaría de
Cliente y modificaríamos la parte que lo hace diferente.
La figura 12 muestra como a través de herencia la clase Cliente (clase padre) hereda sus
características a la clase ClientePreferencial (clase hija), y esta modifica un método para
adicionar su propia implementación.
Figura 12 Ilustración de la herencia
55
56
Propiedades.
Métodos.
Programación orientada a objetos en Java
115
Unidad VI. Polimorfismo
Ahora se sabe, que la próxima vez que se tenga la necesidad de crear programas donde
las clases tengan diferentes comportamientos para realizar diferentes acciones, donde sea
indispensable crear un conjunto de clases que compartirán una serie de características y
además se demande la reutilización de código. Una buena opción en un lenguaje
orientado a objetos, es la utilización del polimorfismo.
Ejemplo: Una sintaxis algo genérica puede ser la que sigue:
Código 6.1.1. Ejemplo de polimorfismo
6.2 Clases abstractas
6.2.1 Definición
Una de las características más útiles de cualquier lenguaje orientado a objetos es la
posibilidad de declarar clases que definen como se utiliza solamente, sin tener que
implementar método. Esto en Java se hace mediante interfaces y con clases abstractas.
Una clase abstracta es una clase de la que no se puede crear objetos. La utilidad de estas
clases estriba en que otras clases hereden de ésta, por lo que con ello se conseguirá
reutilizar código. Para declarar una clase como abstracta se utiliza la palabra clave
abstract.
Los métodos para los que no aporte una implementación serán declarados a su vez
abstractos. Si una clase tiene un método abstract es obligatorio que la clase sea abstract.
Todas las subclases que hereden de una clase abstracta tendrán que redefinir los métodos
abstractos dándoles una implementación. En el caso de que no implementen alguno de
esos métodos la clase hija también será abstracta y tendrá que declararse como tal (tanto
la clase como los métodos que siguen siendo abstractos).
En método abstract no puede ser static, ya que estos no pueden ser redefinidos por las
subclases.
Programación orientada a objetos en Java
116
Unidad VI. Polimorfismo
Hay ocasiones, cuando se desarrolla una jerarquía de clases en que algún comportamiento
está presente en todas ellas pero se materializa de forma distinta para cada una. Por
ejemplo, supóngase una estructura de clases para manipular figuras geométricas. Se
podría pensar en tener una clase genérica, que podría llamarse FiguraGeometrica y una
serie de clases que extienden a la anterior que podrían ser Circulo, Poligono, etc. Podría
haber un método dibujar dado que sobre todas las figuras puede llevarse a cabo esta
acción, pero las operaciones concretas para llevarla a cabo dependen del tipo de figura en
concreto (de su clase). Por otra parte la acción dibujar no tiene sentido para la clase
genérica FiguraGeometrica, porque esta clase representa una abstracción del conjunto de
figuras posibles.
Código 6.2.1.1. Ilustración de clases abstractas.
Para resolver esta problemática Java proporciona las clases y métodos abstractos. Un
método abstracto es un método declarado en una clase para el cual esa clase no
proporciona la implementación (el código). Una clase abstracta es una clase que tiene al
menos un método abstracto. Una clase que extiende a una clase abstracta debe
implementar los métodos abstractos (escribir el código) o bien volverlos a declarar como
abstractos, con lo que ella misma se convierte también en clase abstracta.
Caracteristicas de las clases Abstractas en Java
a) Una clase que tiene al menos un método abstracto, es una clase abstracta.
b) Para declarar un método o una clase abstracta se usa la palabra abstract.
c) Cuando en una clase derivada no se (re)define un método abstracto mediante una
implementación, el método continúa siéndolo en la clase derivada.
d) Se exige que todas las clases abstractas sean declaradas como tales.
e) No se permite la creación de objetos de clases abstractas.
Como ya se dijo anteriormente para declarar una clase o un método como abstractos, se
utiliza la palabra reservada abstract.
Programación orientada a objetos en Java
117
Unidad VI. Polimorfismo
Una clase abstracta no se puede instanciar57 pero si se puede heredar y las clases hijas
serán las encargadas de agregar la funcionalidad a los métodos abstractos. Si no lo hacen
así, las clases hijas deben ser también abstractas.
Ejemplo
Se diseñará una clase con un método abstracto f(double x) que representa una función de
parámetro x cualquiera. Se observa que por lógica esta función se debe implementar en
alguna clase derivada para que tenga sentido.
Además de este método abstracto, se implementara un método llamado evaluar que llama
al método f, retornando su valor.
Código 6.2.1.2. Clases abstractas.
Con esto se puede comprobar que no se puede crear un objeto de una clase abstracta.
Ejemplo :
Funcion func = new Funcion( );
double v = func.evaluar(0.6); /* error logico!! */
6.2.2 Redefinición
La redefinición de una clase abstracta consiste en extenderla y redefinir sus miembros
para dicha clase puede ser utilizada y generar resultados.
Continuando con el ejemplo anterior:
Ahora se extenderá la funcionalidad de clase abstracta Funcion creando la clase derivada
FuncionExp que representa a la función exponencial.
En esta clase se implementa el método abstracto f.
57
No se pueden crear objetos directamente de ella.
Programación orientada a objetos en Java
118
Unidad VI. Polimorfismo
Código 6.2.2.1. Implementación de un método abstracto.
Usando las características de herencia, se tiene el siguiente ejemplo :
Código 6.2.2.2 Llamado a métodos implementados de clases abstracta.
Al igual que la clase FuncionExp, se crea a continuación una clase que representa a una
función lineal, y se redefinen los métodos.
Código 6.2.2.3 Redefinición de métodos.
Y a continuación se crea un programa de prueba para los ejemplos anteriores:
Programación orientada a objetos en Java
119
Unidad VI. Polimorfismo
Programa de prueba
Código 6.2.2.4 Programa de prueba para los dos ejemplos anteriores.
6.3 Definición de una Interfaz
Las interfaces Java son expresiones puras de diseño. Se trata de auténticas
conceptualizaciones no implementadas que sirven de guía para definir un determinado
concepto (clase) y lo que debe hacer, pero sin desarrollar un mecanismo de solución58. Se
trata de declarar métodos abstractos y constantes que posteriormente puedan ser
implementados de diferentes maneras según las necesidades de un programa.
En otras palabras, una interfaz es un conjunto de declaraciones de funciones. Si una clase
implementa una interfaz, debe definir todas las funciones especificadas por la interfaz.
Las interfaces pueden definir también variables finales (constantes). Una clase puede
implementar más de una interfaz, representando una alternativa a la herencia múltiple.
En algunos aspectos los nombres de las interfaces pueden utilizarse en lugar de las clases.
Por ejemplo, las interfaces sirven para definir referencias a cualquier objeto de cualquiera
de las clases que implementan esa interfaz. Con ese nombre o referencia, sin embargo,
sólo se pueden utilizar los métodos de la interfaz. Éste es un aspecto importante del
polimorfismo.
Una interfaz puede derivar de otra o incluso de varias interfaces, en cuyo caso incorpora
las declaraciones de todos los métodos de las interfaces de las que deriva (a diferencia de
las clases, las interfaces de Java sí tienen herencia múltiple).
Utilizando la palabra clave interfaz, se puede abstraer completamente la interfaz de una
clase de su implementación. Es decir, con interfaz se puede especificar lo que una clase
debe hacer, pero no cómo ha de hacerlo. Las interfaces tienen una sintaxis parecida a la
de las clases, pero les faltan las variables de instancia, y sus métodos se declaran sin
cuerpo. En la práctica, esto significa que se pueden definir las interfaces que no hagan
58
Es la alternativa que Java otorga a la herencia múltiple.
Programación orientada a objetos en Java
120
Unidad VI. Polimorfismo
suposiciones sobre cómo se implementan. Una vez que está definida, cualquier número de
clases puede implementar una interfaz. Asimismo, una clase puede implementar cualquier
número de interfaces.
Para implementar una interfaz, una clase ha de crear el conjunto completo de métodos
definidos por la interfaz. Sin embargo, cada clase tiene libertad de determinar los detalles
de su propia implementación. Con la palabra clave interfaz Java permite la utilización
completa del aspecto del polimorfismo, “una interfaz, múltiples métodos”.
Las interfaces están diseñadas para dar soporte a la resolución dinámica de métodos
durante la ejecución. Normalmente, para que un método de una clase pueda ser llamado
desde otra clase, es necesario que las dos clases estén presentes durante la compilación
para que el compilador java pueda comprobar que el formato de los métodos es
compatible. Este requisito da lugar por si sólo a un entorno de clase no estático y
extensible. Inevitablemente, en un sistema así, las clases, de forma que los mecanismos
estarán disponibles para más y más subclases. Las interfaces, desconectando la definición
de un método o de un conjunto de métodos de la herencia jerárquica, eliminan ese
problema. Como las interfaces tienen una jerarquía distinta de la de las clases, es posible
que clases que no están relacionadas en términos de jerarquía implementen la misma
interfaz, lo que pone de manifiesto la verdadero potencia de las interfaces.
6.4 Implementación de la Definición de una Interfaz
Una interfaz se define como una clase. La forma general de definir una interfaz es ésta:
Código 6.4.1 Implementación de la de definición de una interfaz.
En este ejemplo el acceso o es público o no se usa. Cuando no se incluye el especificador
de acceso, se utiliza el acceso por defecto, y la interfaz está disponible sólo para otros
miembros del paquete en que se declara. Cuando se declara como public, la interfaz
puede utilizarse por otro código. Nombre es el nombre de la interfaz, y debe ser un
identificador válido. Obsérvese que los métodos que se declaran no tienen cuerpos y
terminan con un punto y coma después de la lista de parámetros. Son esencialmente
métodos abstractos, ya que no puede haber implementación por defecto de un método
Programación orientada a objetos en Java
121
Unidad VI. Polimorfismo
declarado dentro de una interfaz. Cada clase que incluya una interfaz ha de implementar
todos los métodos.
Las variables pueden declararse dentro de las declaraciones de la interfaz y son,
implícitamente, final y static: esto significa que no pueden ser alteradas por la
implementación de la clase y que deben inicializarse con un valor constante. Todos los
métodos y variables son implícitamente public si la interfaz se declara public. Un ejemplo
de definición de una interfaz sencilla, que contiene un método llamado callback() que
toma un solo parámetro entero.
interface Callback(
void callback(int param);
}
Implementación de una Interfaz
Una vez definida una interfaz una o más clases pueden implementarse. Para implementar
una interfaz, se ha de incluir la cláusula implements en una definición de clase, y luego
crear los métodos definidos por la interfaz. La forma general de una clase que incluye la
cláusula implements es esta:
Código 6.4.2 Implementación de una interfaz.
El acceso es public o no se usa. Si una clase implementa más de una interfaz, las
interfaces se separan con comas. Si una clase implementa dos interfaces, entonces los
clientes de las dos interfaces deberán usar el mismo método. Los métodos que
implementan una interfaz deben declararse como public. Además, el formato del método
implementado debe coincidir exactamente con el formato especificado en la definición de
la interfaz. A continuación, un pequeño ejemplo de una clase que implementa la interfaz
DevolverLllamada.:
Código 6.4.3 Implementación de la interfaz DevolverLlamada.
Programación orientada a objetos en Java
122
Unidad VI. Polimorfismo
Obsérve que DevolverLlamada() se declara por medio del especificador de acceso public.
Es habitual y además permitido que las clases que implementen interfaces definan
miembros adicionales propios. Por ejemplo, la siguiente versión de Cliente implementa
DevolverLlamada y añade el método NoMetododeInterfaz( );
Código 6.4.4 Definición de miembros adicionales en clases que implementan
interfaces.
6.5 Reutilización de la definición de una Interfaz
Se pueden declarar variables como referencias a objetos que usan una interfaz en lugar
de un tipo de clases. Se puede hacer referencia a cualquier instancia de cualquier clase
que implementa una interfaz declarada por medio de tales variables. Cuando se llama a un
método por medio de estas referencias se llamará a la versión correcta que se basa en la
instancia actual de la interfaz que esta siendo referenciada. Está es una de las
característica clave de las interfaces. El método que se va ejecutar se determina
dinámicamente durante la ejecución y se permite que las clases en las que se encuentra
ducho método se creen después del código llamante, que puede seleccionar una interfaz
sin tener ningún conocimiento sobre el método al que se ha llamado. Este proceso es
similar al que se seguía cuando se utilizaba una referencia de una superclase para acceder
a un objeto de una subclase.
El siguiente ejemplo llama al método DevuelveLlamada() por medio de una variable de
referencia:
Código 6.5.1. Llamada al método DevuelveLlamada() por medio de una
variable de referencia.
La salida es:
Programación orientada a objetos en Java
123
Unidad VI. Polimorfismo
DevuelveLlamada llamada con 42
Observe que la variable c se ha declarado como el tipo de la interfaz DevuelveLlamada,
aunque se le ha asignado una instancia de Clienet. A pesar de que c se puede utilizar para
acceder al método DevuelveLlamada (), no sirve para acceder a otros miembros de la
clase Cliente. Una variable de referencia a una interfaz solo tiene conocimiento de los
métodos que figuran en la declaración de su interfaz. Por lo tanto, c no podría utilizarse
para acceder al método NoMetododeInterfaz() debido a que está definido por Cliente,
pero no por DevuelveLlamada.
El ejemplo anterior mostraba, de forma mecánica, como una variable de referencia
a una interfaz puede acceder a la implementación de un objeto, pero no demostraba la
potencia del polimorfismo. Como ejemplo se creará una segunda implementación de
DevuelveLlamada:
Ahora, se probará con la siguiente clase:
Código 6.5.2 Demostración del potencial del polimorfismo implementando la
clase OtroCliente.
La salida del programa es la siguiente:
DevuelveLlamada llamado con 42
otra version de DevuelveLlamada
Programación orientada a objetos en Java
124
Unidad VI. Polimorfismo
p al cuadrado es 1764
Como se observa la versión del método DevuelveLlamada() al que se ha llamado está
determinada por el tipo de objeto al que c hace referencia durante la ejecución. Aunque el
ejemplo que ahora se muestra es demasiado sencillo, enseguida se muestra otro más
práctico.
Implementación parcial
Si una clase incluye una interfaz pero no se implementa completamente los métodos
definidos por esa interfaz, entonces debe ser declarada como abstract. Por ejemplo:
Código 6.5.3. La implementación parcial de una interfaz la convierte en una clase
abstracta.
En este caso, la clase Incompleta no implementa el método DevuelveLlamada() y ha de
ser declarada como abstracta. Cualquier clase que herede Incomplete ha de implementar
DevuelveLlamada(), o bien declararse como abstract.
Aplicación de las Interfaces
Para comprender la potencia de las interfaces, véase ahora un ejemplo más práctico.
Existen varias formas de implementar una pila 59, por ejemplo, la pila puede ser de
tamaño fijo o de tamaño creciente. La pila también puede estar contenida dentro de una
matriz, una lista, un árbol binario, etc. No importa de qué manera se implemente la pila,
su interfaz permanece inalterable. Es decir, los métodos push()60y pop()61 definen la
interfaz a la pila independientemente de los detalles de la implementación. Así, es fácil
definir dicha interfaz y dejar para cada implementación los detalles más específicos.
Véanse dos ejemplos.
El primero de ellos presenta una interfaz que define una pila de enteros y se guarda en un
archivo llamado pila.java. Esta interfaz se utilizará para las dos implementaciones de la
pila.
59
60
61
Stack.
Insertar un elemento a la pila.
Eliminar un elemento de la pila.
Programación orientada a objetos en Java
125
Unidad VI. Polimorfismo
Código 6.5.4. Declaración de una interfase pila para almacenar y
recuperar un elemento.
El siguiente programa crea una clase llamada PilaFija y que implementa una versión de
una pila de enteros de longitud fija:
Programación orientada a objetos en Java
126
Unidad VI. Polimorfismo
Código 6.5.3. Programa que crea una clase llamada PilaFija y que
implementa una versión de una pila de enteros de longitud fija.
A continuación se muestra otro ejemplo de la implementación de Pila que crea una pila
dinámica utilizando la misma definición de la interfaz. En esta implementación, cada pila
se construye partiendo de una longitud inicial. Si se sobrepasa esa longitud, se incrementa
el tamaño de la pila. Cada vez que se necesite más espacio, se doblará el tamaño de la
pila.
Programación orientada a objetos en Java
127
Unidad VI. Polimorfismo
Código 6.5.4. Programa que crea una clase llamada PilaDnamica y que implementa una
versión de una pila de enteros de longitud dinámica.
La siguiente clase utiliza las implementaciones PilaFija y PilaDinamica, por medio de una
referencia a la interfaz. Esto significa que las llamadas a los métodos push() y pop() se
resuelven durante el tiempo de la ejecución y no en el de compilación.
Programación orientada a objetos en Java
128
Unidad VI. Polimorfismo
Código 6.5.5. Implementación de PilaFija y PilaDinamica.
En este programa, mipila es una referencia a la interfaz Pila. Por lo tanto, cuando se
refiere a ds, utiliza las versiones de push() y pop() definidas por la implementación
PilaDinamica. Cuando se refiere a fs, utilza las versiones de push() y pop() definidas por
PilaFija. Como ya se ha explicado, estas decisiones se toman durante la ejecución. El
acceso a múltiples implementaciones de una interfaz a través de una variable de
referencia de la interfaz es la forma más eficaz de que dispone Java para lograr el
polimorfismo en el tiempo de ejecución.
6.6 Definición y Creación de Paquetes
Conforme empieza a crecer un desarrollo de software surge la necesidad de reutilizar
ciertos componentes que ya han sido escritos, así como dar cierta estructura para
mantener una organización de código; al igual que otros lenguajes, esta organización
se lleva acabo mediante librerías, denominadas "packages" en el mundo Java .
Java toma una perspectiva nueva respecto a otros lenguajes, adoptando una
convención a partir de dominios en Internet, esto es, los programas y por ende librerías
("packages") estarán basados en el nombre de la empresa/dominio para la cual son
diseñados, lo anterior permite evitar la tan conocida Colisión de Nombres en Software.
Programación orientada a objetos en Java
129
Unidad VI. Polimorfismo
Esta colisión de nombres se da cuando dos clases llevan el mismo nombre y ambas
requieren ser utilizadas dentro de un programa en particular, empleando Dominios en
Internet se garantiza que el nombre de la clase/librería sea única , puesto que es una
característica de Dominios en Internet.
Para que puedan ser asignadas clases a determinadas librerías es necesario indicar
dicha Librería("Package") en la definición inicial de un programa, además de esto, es
necesario crear una estructura de directorios para generar las determinadas Clases; lo
anterior se ilustra mejor a través de un ejemplo:
Creación de Librerías
Estructura de Directorios para utilizar Librerías ("Paquetes")
Para utilizar "paquetes" en Java es necesario generar una estructura de directorios que
lleven la misma secuencia de las librerías que desean diseñarse, observe:
+-com+|
+-osmosislatina+|
+-escritura+|
+-graficas+|
+-correo+|
+-errores+|
+-auxiliares+L
o anterior demuestra una estructura para las librerías del dominio com.osmosislatina, se
debe mencionar que no existe ninguna restricción en el número de directorios
anidados, de tal forma, es posible que existan librerías de 5 o 10 niveles de
profundidad, esta sub-clasificación se va realizando en base a los requerimientos de las
librerías y es dentro de cada sub-directorio donde son colocadas las distintas Clases.
Además de la generación de estos directorios, se debe incluir un calificador de la librería
en el código fuente de cada Clase:
package com.osmosislatina.escritura;
Lo anterior sería incluido en todos los programas pertenecientes a la librería
("Package") com.osmosislatina.escritura, debe mencionarse que este calificador debe
ser la primer declaración en todo programa; recuérdese que además de este calificador
el programa debe estar colocado en la estructura de directorios correspondiente, lo
anterior es sumamente importante al llevarse acabo la compilación para la generación
de Byte-Code
Programación orientada a objetos en Java
130
Unidad VI. Polimorfismo
Código Fuente Pantalla.java
La siguiente Clase define dos métodos que pueden ser utilizados para imprimir
resultados a pantalla:
La siguiente Clase debe ser colocada bajo la estructura de
directorios com/osmosislatina/escritura, en base a su ambiente
(Linux o Windows). Por favor genérese dicha estructura para
colocar esta clase
package com.osmosislatina.escritura;
public class Pantalla {
public static void sinSalto(String s) {
System.out.print(s);
}
public static void conSalto(String s) {
System.out.println(s);
}
}
•
•
•
•
Primeramente se declara la librería ("package") a la que será asignada el
programa a través del vocablo package.
Se define la Clase con los respectivos métodos sinSalto y conSalto.
NOTA: Recuerde que este programa debe residir dentro del directorio
com/osmosislatina/escritura/.
NOTA 2: Obsérvese que esta Clase no posee el método principal main.
Para compilar esta Clase basta ejecutar el comando:
$ javac Pantalla.java
Lo anterior genera el archivo de ByteCode : Panatalla.class. En la siguiente sección será
diseñado un programa que haga uso de esta librería ("package").
Programación orientada a objetos en Java
131
Unidad VI. Polimorfismo
6.7 Reutilización de las clases de un Paquete / Librería
Para emplear librerías 62 en un programa es necesario importarlas, esto es llevado
acabo mediante el calificativo import como se demuestra a continuación:
import com.osmosislatina.graficas.Recuadro;
La declaración anterior permite que la clase Recuadro de la librería
com.osmosislatina.graficas este disponible en el programa en cuestión, las
características del uso de import son las siguientes:
Se debe declarar al inicio de un programa, antes de la definición de la clase,
aunque posterior a la definición de package (si existiese) .
•
•
Se pueden utilizar un número ilimitado de import.
•
Es posible importar todas las clases de una librería a través de un asterisco (*).
Código Fuente MandaPantalla.java
La siguiente Clase manda llamar métodos definidos en la Clase Pantalla.java.
Código 6.7.1. Código Fuente MandaPantalla.java
62
•
Primeramente se declara la librería a la que será asignada el programa a través
del vocablo package.
•
Posteriormente se importan las clases que serán utilizadas en el programa a
través del vocablo import.
Conocidas como package.
Programación orientada a objetos en Java
132
Unidad VI. Polimorfismo
Se define el método main dentro del cual se genera una instancia de la case
Pantalla (aquella importada) y sobre la que posteriormente se mandan llamar los
distintos métodos a través de su referencia.
•
La compilación (generación de bite-code) de esta Clase requiere que, esta sea llevada a
cabo bajo el directorio raíz de la estructura de Clases, esto es, aunque esta Clase
radique dentro del directorio com/osmosislatina/auxiliares es necesario llevar acabo la
compilación desde la raíz (./com), lo anterior se debe a que esta Clase requiere ubicar
(importar) las clases de la librería com/osmosislatina/escritura; los detalles de esta
rutina serán descritos en la sección de CLASSPATH.
Para ejecutar este programa también se requiere descender al directorio raíz de la
librería ("Package).
El paquete (package)
•
•
•
Los paquetes son una forma de organizar grupos de clases. Un paquete contiene
un conjunto de clases relacionadas bien por finalidad, por ámbito o por herencia.
Los paquetes resuelven el problema del conflicto entre los nombres de las clases.
Al crecer el número de clases crece la probabilidad de designar con el mismo
nombre a dos clases diferentes.
Las clases tienen ciertos privilegios de acceso a los miembros dato y a las
funciones miembro de otras clases dentro de un mismo paquete.
Cuando se crea un proyecto nuevo se crea en un subdirectorio que tiene el nombre del
proyecto. A continuación, se crea la aplicación, un archivo .java que contiene el código de
una clase cuyo nombre es el mismo que el del archivo. Se pueden agregar nuevas clases
al proyecto, todas ellas contenidas en archivos .java situadas en el mismo subdirectorio.
La primera sentencia que se encuentra en el código fuente de las distintas clases que
forman el proyecto es package o del nombre del paquete.
Programación orientada a objetos en Java
133
Unidad VI. Polimorfismo
6.8 Clases Genéricas (Plantillas) 63
Las clases plantilla, clases genéricas, o generadores de clases, son un artificio que permite
definir una clase mediante uno o varios parámetros. Este mecanismo es capaz de generar
la definición de clases (instancias o especializaciones de la plantilla) distintas, pero
compartiendo un diseño común. Se puede imaginar que una clase genérica es un
constructor de clases, que como tal, acepta determinados argumentos (no confundir con
el constructor de-una-clase, que genera objetos).
6.9 Ejercicios Resueltos
6.9.1 Crear una clase abstracta denominada Animal de la cual se derivan las clases Gato y
Perro. Ambas clases redefinen la función habla declarada abstracta en la clase base
Animal.
El polimorfismo permite pasar la referencia a un objeto de la clase Gato, Perro o Pajaro a
una función hazleHablar que conoce al objeto por su clase base Animal.
63
Este mecanismo no es implementado por java
Programación orientada a objetos en Java
134
Unidad VI. Polimorfismo
El compilador no sabe exactamente que objeto se le pasará a la función hazleHablar en el
momento de la ejecución del programa. Si se pasa un objeto de la clase Gato se imprimirá
¡Miau!, si se pasa un objeto de la clase Perro se imprimirá ¡Guau!. Y si se le pasa un
objeto de la clase Pajaro imprimirá ¡pió! El compilador solamente sabe que se le pasará un
objeto de alguna clase derivada de Animal. Por tanto, el compilador no sabe que función
habla será llamada en el momento de la ejecución del programa.
El polimorfismo ayuda a hacer el programa más flexible, por que en el futuro se pueden
añadir nuevas clases derivadas de Animal, sin que cambie para nada el método
hazleHablar.
6.9.2
Crear una interface denominado Parlanchin que contenga la declaración de una
función denominada habla.
Se desarrolla la jerarquía de clases que deriva de Animal implemente la interface
Parlanchi.
Programación orientada a objetos en Java
135
Unidad VI. Polimorfismo
Ahora véase otra jerarquía de clases completamente distinta, la que deriva de la clase
base Reloj. Una de las clases de dicha jerarquía Cucu implementa el interface Parlanchin y
por tanto, debe de definir obligatoriamente la función habla declarada en dicho interface.
Se define la función hazleHablar de modo que conozca al objeto que se le pasa no por una
clase base, sino por el interface Parlanchin. A dicha función se le puede pasar cualquier
objeto que implemente el interface Parlanchin, este o no en la misma jerarquía de clases.
Programación orientada a objetos en Java
136
Unidad VI. Polimorfismo
Al ejecutar el programa, se vera que se imprime en la consola ¡Miau!, por que a la función
hazleHablar se le pasa un objeto de la clase Gato, y después ¡Cucu, cucu, ..! por que a la
función hazleHablar se le pasa un objeto de la clase Cucu.
Si solamente hubiese herencia simple, Cucu tendría que derivar de la clase Animal (lo que
no es lógico) o bien no se podría pasar a la función hazleHablar. Con interfaces, cualquier
clase en cualquier familia puede implementar el interface Parlanchin, y se podrá pasar un
objeto de dicha clase a la función hazleHablar. Esta es la razón por la cual los interfaces
proporcionan más polimorfismo que el que se puede obtener de una simple jerarquía de
clases.
6.9.3
Implemente una llamada Forma de la cual se deriven la clase Círculo, la clase
Cuadrado y la Clase Triangulo. Implemente el método de Dibujar y el Método de
borrar en cada una. Utilice polimorfismo.
Programación orientada a objetos en Java
137
Unidad VI. Polimorfismo
Programación orientada a objetos en Java
138
Unidad VI. Polimorfismo
6.10 Ejercicios Propuestos
6.10.1 Modificar el ejercicio 6.9.3 en el apartado de problemas resueltos, creando una
nueva clase denominada pentágono que herede de Forma y que sobrecargue los métodos
dibujar y borrar. Compilar y ejecutar.
6.10.2 Crear una interfaz llamado Manejo que contenga los métodos dibujar y borrar y
modificar el ejercicio anterior para que la clase Forma implemente el interfaz manejo.
6.10.3 Implementar una clase que se llame Perro y que tenga un método sobrecargado
llamado ladrido. Sobrecárgalo de tal manera que el tipo de parámetro determine el tipo de
ladrido. Exteriorizar el tipo de ladrido con un mensaje. Dentro del programa principal
llamar al método ladrido con diferentes parámetros.
6.10.4 Implementar una jerarquía Empleado de cualquier tipo de empresa que le sea
familiar. La jerarquía debe tener al menos cuatro niveles, con herencia de miembros de
dato, y métodos. Los métodos deben poder calcular salarios, despidos, promoción, dar de
alta jubilación etc. Los métodos también deben poder calcula aumentos salariales y primas
para Empleados de acuerdo con su categoría y productividad. La jerarquía de herencia
debe poder ser utilizada para proporcionar diferentes tipos de acceso a Empleados.
6.10.5 Se requiere realizar una aplicación para que cada profesor de la universidad
gestione las fichas de sus alumnos. Un profesor puede impartir una o varias asignaturas y
dentro de cada asignatura puede tener distintos grupos de alumnos. Los alumnos pueden
ser presénciales o a distancia. Al comenzar las clases, se entrega al profesor un listado con
los alumnos por cada asignatura. Escribir un programa de tal forma que el listado de
alumnos se introduzca por el teclado y se den de alta calificaciones de exámenes y
prácticas realizadas. Se podrán obtener listados de calificaciones una vez realizados los
exámenes y porcentajes de aprobados.
6.10.6 Implementar un programa que utilizando polimorfismo implemente la forma de
hablar de un ladrón, un ingeniero, un político y un abogado.
6.10.7 Implementar que imprima los diferentes sonidos de los instrumentos musicales:
Guitarra, saxogon, piano, Guzla y Ukele. Asígnele una frase a cada instrumento que
represente el sonido. Utilice polimorfismo.
Programación orientada a objetos en Java
139
Unidad VII. Excepciones
UNIDAD VII. EXCEPCIONES
Definición, Gestión, Tipos, Manejo y Lanzamiento de Excepciones Definidas por el
Lenguaje y Definidas por el Usuario
Programación orientada a objetos en Java
140
Unidad VII. Excepciones
UNIDAD VII. EXCEPCIONES
7.1 Definición
7.1.1 ¿Qué son las Excepciones?
Una excepción es la indicación de un problema que ocurre durante la ejecución de un
programa. El nombre “excepción” viene del hecho del que, aunque puede ocurrir un
problema, este ocurre con poca frecuencia, si la “regla” es que una instrucción
generalmente se ejecuta en forma correcta, entonces la “excepción a la regla” es cuando
ocurre un problema. El manejo de excepciones permite a los programadores crear
aplicaciones que puedan resolver (o manejar) las excepciones. En muchos casos, el
manejo de una excepción permite que el programa continúe su ejecución como si no se
hubiera encontrado el problema. Un problema más grave podría evitar que el programa
continuara su ejecución normal en vez de requerir al programa que notifique al usuario
sobre el problema antes de terminar de una manera controlada.
A diferencia de otros lenguajes de programación orientados a objetos como C/C++, Java
incorpora en el propio lenguaje la gestión de errores. El mejor momento para detectar los
errores es durante la compilación. Sin embargo prácticamente sólo los errores de sintaxis
son detectados durante este periodo. El resto de problemas surgen durante la ejecución
de los programas. En el lenguaje Java, una Exception es un cierto tipo de error o una
condición anormal que se ha producido durante la ejecución de un programa. Algunas
excepciones son fatales y provocan que se deba finalizar la ejecución del programa.
Algunos ejemplos de datos anormales son; Intentar manejar archivos que no existen,
accesos no legales en arrays y operaciones aritméticas ilegales como una división por
cero.
Cuando surge una condición excepcional, se crea un objeto que representa esta excepción
y se lanza método que ha causado el error. Este método puede escoger entre gestionar el
mismo la excepción o pasarla. De cualquiera de las dos maneras, en un punto
determinado, se cazará la excepción y se procesará. Las excepciones pueden generarse
por el intérprete de Java o de forma manual por el propio código. Normalmente, las
excepciones generadas por Java están relacionadas con errores fundamentales que violan
las reglas del lenguaje Java o las restricciones del entorno de ejecución Java. Las
excepciones generadas de forma manual se utilizan, generalmente, para informar acerca
de alguna condición de error en la parte del código que llama al método.
En todos los casos donde surgen excepciones es recomendable terminar ordenadamente y
dar un mensaje explicando el tipo de error que se ha producido. Otras, como por ejemplo
no encontrar un fichero en el que hay que leer o escribir algo, pueden ser recuperables.
En este caso el programa debe dar al usuario la oportunidad de corregir el error(indicando
una nueva localización del archivo no encontrado).
Un buen programa debe gestionar correctamente todas o la mayor parte de los errores
que se pueden producir.
Programación orientada a objetos en Java
141
Unidad VII. Excepciones
7.1.2 Clases de Excepciones Predefinidas por el Lenguaje
Todos los tipos de excepciones son subclases de la clase Throwable64, incorporada en
Java. Por lo tanto, Throwable ocupa el primer puesto en la jerarquía de clases de
excepciones. Inmediatamente después se encuentran dos subclases que dividen las
excepciones en dos grupos. Uno de estos grupos están encabezados por Exception, esta
clase se utiliza para las condiciones excepcionales que los usuarios de los programas
deben capturar, también es la clase de la que derivan las subclases necesarias para crear
los tipos propios de las excepciones, existe una importante subclase de Exception, llamada
RuntimeException. Las excepciones de este tipo se dignen se definen de forma automática
por los programas que se escriben e incluyen aspectos como la división por cero, la
utilización de un índice un arreglo no válido.
El otro grupo esta encabezado por Error, que define las excepciones que no se espera que
el programa pueda capturar en circunstancias normales. En intérprete Java utiliza las
excepciones de tipo Error para indicar los errores relacionados con el momento de la
ejecución, el desbordamiento de la pila es un ejemplo de este tipo de error.
Las excepciones predefinidas por la implementación actual del lenguaje Java y su jerarquía
interna de clases son las que se representan en el esquema de la figura 13 que aparece a
continuación:
Figura 13 Jerarquía de las clases de excepciones.
64
La clase Throwable es la clase base de las excepciones.
Programación orientada a objetos en Java
142
Unidad VII. Excepciones
Los nombres de las excepciones indican la condición de error que representan. Las
siguientes son las excepciones predefinidas más frecuentes que se pueden encontrar:
ArithmeticException
Las excepciones aritméticas son típicamente el resultado de división por 0:
int i = 12 / 0;
NullPointerException
Se produce cuando se intenta acceder a una variable o método antes de ser definido:
class Hola extends Applet {
Image img;
paint( Graphics g ) {
g.drawImage( img,25,25,this );
}
}
IncompatibleClassChangeException
El intento de cambiar una clase afectada por referencias en otros objetos, específicamente
cuando esos objetos todavía no han sido recompilados.
ClassCastException
El intento de convertir un objeto a otra clase que no es válida.
y = (Prueba)x;
// donde x no es de tipo Prueba
NegativeArraySizeException
Puede ocurrir si hay un error aritmético al cambiar el tamaño de un array.
OutOfMemoryException
¡No debería producirse nunca! El intento de crear un objeto con el operador new ha
fallado por falta de memoria. Y siempre tendría que haber memoria suficiente porque el
garbage collector se encarga de proporcionarla al ir liberando objetos que no se usan y
devolviendo memoria al sistema.
NoClassDefFoundException
Se referenció una clase que el sistema es incapaz de encontrar.
ArrayIndexOutOfBoundsException
Programación orientada a objetos en Java
143
Unidad VII. Excepciones
Es la excepción que más frecuentemente se produce. Se genera al intentar acceder a un
elemento de un array más allá de los límites definidos inicialmente para ese array.
UnsatisfiedLinkException
Se hizo el intento de acceder a un método nativo que no existe. Aquí no existe un método
y se llama a a.kk(), cuando debería llamar a A.kk().
InternalException
Este error se reserva para eventos que no deberían ocurrir. Por definición, el usuario
nunca debería ver este error y esta excepción no debería lanzarse.
El compilador Java obliga al programador a proporcionar el código de manejo o control de
algunas de las excepciones predefinidas por el lenguaje. Por ejemplo, el siguiente
programa, no compilará porque no se captura la excepción InterruptedException que
puede lanzar el método sleep() 65.
Código 7.1.2.1 En el ejemplo no se captura la Excepción InterruptedException, por lo
tanto no se compilará.
Este es un programa muy simple, que al intentar compilar, producirá el siguiente error de
compilación que se visualizará en la pantalla tal como se reproduce a continuación:
65
Dormir.
Programación orientada a objetos en Java
144
Unidad VII. Excepciones
% Javac Java701.java
Java701.java:41: Excepcion java.lang.InterruptedException debe ser tomada,
o debe ser debe ser declarada en la cláusula throws de este método.
Thread.currentThread().sleep( 1000 ); // currentThread() genera
Como no se ha previsto la captura de la excepción, el programa no compila. El error
identifica la llamada al método sleep() como origen del problema. Así que, la siguiente
versión del programa, Java903.java, soluciona el problema generado por esta llamada.
Código 7.1.2.1 En este programa se resuelve el problema del código anterior, se
implementa la excepción por lo tanto ya se compilará.
Lo único que se ha hecho es indicar al compilador que el método miMetodo() puede lanzar
excepciones de tipo InterruptedException. Con ello se consigue propagar las excepción
que genera el método sleep() al nivel siguiente de la jerarquía de clases. Es decir, en
realidad no se resuelve el problema sino que se está pasando a otro método para que lo
resuelva él.
En el método main() se proporciona la estructura que resuelve el problema de
compilación, aunque no haga nada, por el momento. Esta estructura consta de un bloque
try y un bloque catch, que se puede interpretar como que intentará ejecutar el código del
bloque try y si hubiese una nueva excepción del tipo que indica el bloque catch, se
ejecutaría el código de este bloque.
La transferencia de control al bloque catch no es una llamada a un método, es una
transferencia incondicional, es decir, no hay un retorno de un bloque catch.
Programación orientada a objetos en Java
145
Unidad VII. Excepciones
7.1.3 Propagación de Excepciones
Cuando un método lanza una excepción, quiere decir que detecta que se ha producido
una situación anómala, pero no sabe que hacer con ella. En ese caso, el método lanza la
excepción y termina, propagando la excepción al método que le llamó, que quizá sepa qué
hacer en ese caso. Las excepciones se propagan por todos los métodos de la pila de
llamadas, hasta que se encuentre un método que la gestione.
Código 7.1.3.1 Propagación de excepciones.
La propagación de excepciones se da como lo muestra la figura 14.
Figura 14: Propagación de excepciones.
Programación orientada a objetos en Java
146
Unidad VII. Excepciones
main (de PedirNumero)
readLine (de BufferedReader)
Lanza IOException
Se produce la excepción
Termina la ejecución
Se relanza (se podría haber capturado)
7.2 Gestión de Excepciones
Excepciones No Capturadas
Antes de aprender a gestionar las excepciones en el programa, será útil ver que ocurre
cuando no se gestiona en absoluto. Este programita incluye una excepción que, de forma
intencionada provoca un error debido al la división entre ceo.
Código 7.2.1 Se provoca una excepción intencional debido a la división
entre cero.
Cuando el intérprete Java detecta un intento de división entre cero, construye un nuevo
objeto de excepción y luego lanza esa excepción, esto provoca que la ejecución de Exc0
se detenga. Porque una vez que la excepción se ha lanzado, ha de cazarse con un gestor
de excepciones y tratarse de forma inmediata., en este ejemplo no se han proporcionado
gestores de excepciones, de manera que la excepción se ha capturado por el gestor por
defecto que proporciona el intérprete Java, cualquier excepción que no el programa cace,
será, en última instancia, procesada por el gestor por defecto, que representa un mensaje
que describe la excepción, imprime el trazado de la pila y concluye el programa.
Aquí se tiene la excepción que se genera cuando el programa se ejecuta.
Java.lang.ArithmeticException: //por cero en Exc0.main(Exc0.java 4)
Obsérvese como el nombre de clase, Exc0; el nombre de método, main; el nombre del
archivo, exc0.java; y el número de línea 4, se incluye en el trazado simple de la pila.
Obsérvese también, que el tipo de excepción lanzada, denominada ArithmeticException,
describe de manera más específica el tipo de error que se ha producido. Java proporciona
bastantes tipos de excepciones que se ajustan a las distintas clases de errores de
momento de ejecución que se pueden generar.
El trazado de la pila siempre mostrará la secuencia de llamadas a métodos que preceden
al error. Por ejemplo, aquí se presenta otra versión del programa anterior que introduce el
mismo error pero en un método distinto de main():
Programación orientada a objetos en Java
147
Unidad VII. Excepciones
El trazado de la pila que resulta del gestor de excepciones por defecto muestra la pila de
llamadas completa:
java.lang.ArithmeticException: / by zero
at Exc1.subroutine(Exc1.java:4)
at Exc1.main(exc1.java:7)
Como puede verse, el final de la pila es línea 7 de main, que es donde se llama al método
subroutine(), que provoca la excepción en la línea 4. La pila de llamadas es muy útil para
la depuración porque muestra la secuencia exacta de pasos que condujo al error.
7.2.1 Manejo de Excepciones
La lógica del programa evalúa frecuentemente condiciones que determinan cómo debe
proceder la ejecución del programa. Considérese el siguiente seudocódigo.
Figura 15 Manejo de Excepciones.
En este seudocódigo se empieza realizando una tarea; después, se evalúa si esa tarea se
ejecutó correctamente. Si no lo hizo, se realiza el procesamiento de los errores. De otra
manera, se continúa con la siguiente tarea. Aunque esta forma de manejo de errores
funciona, al entremezclar la lógica del programa con la lógica del manejo de errores podría
ser difícil de leer, mantener y depurar; especialmente en aplicaciones extensas. De hecho
si los problemas potenciales ocurren con poca frecuencia, al entremezclar la lógica del
Programación orientada a objetos en Java
148
Unidad VII. Excepciones
programa y la lógica del manejo de errores se puede degradar el rendimiento del
programa, ya que este debe evaluar la lógica del manejo de errores para determinar si se
puede llevar acabo la siguiente tarea. El manejo de excepciones permite al programador
remover el código para el manejo de errores de la “línea principal” de ejecución del
programa, lo cual mejora la claridad y capacidad de modificación del mismo. Los
programadores pueden optar por manejar las excepciones que elijan: todas las
excepciones, todas las excepciones de cierto tipo o todas las excepciones de un grupo de
tipos relacionados 66. Esta flexibilidad reduce la probabilidad de que los errores se pasen
por alto y, por consecuencia, hace que un programa sea más robusto.
El manejo de excepciones está diseñado para procesar errores sincrónicos, que ocurren
cuando se ejecuta una instrucción. Ejemplos comunes de estos errores son los índices
fuera de rango, el desbordamiento aritmético (es decir, un valor fuera de rango
representable de valores), la división entre cero, los parámetros inválidos de método, la
interrupción de subprocesos y la asignación fallida de memoria (debido a la falta de ésta).
El manejo de excepciones no esta diseñado para procesar los problemas asociados con los
eventos asíncronos 67. los cuales ocurren en paralelo con, y en forma independiente de
flujo de control del programa.
Con lenguajes de programación que no soportan el manejo de excepciones, los
programadores a menudo retrasan la escritura de código de procesamiento de errores, o
algunas veces olvidan incluirlo. Esto hace que los productos de software sean menos
robustos. Java permite al programador tratar con el manejo de excepciones fácilmente,
desde el comienzo de un proyecto. Sin embargo, el programador debe incorporar una
estrategia de manejo de excepciones en los proyectos de software.
El mecanismo de manejo excepciones también es útil para procesar los problemas que
ocurren cuando un programa invoca a los métodos de otras clases. En vez de manejar los
problemas internamente, dichos métodos utilizan por lo común excepciones para notificar
a los métodos que hacen las llamadas cuando ocurren los problemas. Esto permite a los
programadores implementar un manejo de errores personalizado para cada aplicación.
Las aplicaciones complejas normalmente consisten de componentes predefinidos de
software y de componentes específicos para cada aplicación. Cuando un componente
predefinido se encuentra con un problema, ese componente necesita de un mecanismo
para comunicar el problema al componente específico de la aplicación: el componente
predefinido no puede saber de antemano cómo procesa cada aplicación cierto problema
ocurrido. El manejo de excepciones simplifica la combinación de componentes de software
y les permite trabajar efectivamente, al permitir que los componentes predefinidos
comuniquen los problemas a los componentes específicos de la aplicación, los cuales
podrán entonces procesar los problemas de una manera especifica para cada aplicación.
El manejo de excepciones esta dirigido a situaciones en las que el método que detecta un
problema es incapaz de manejarlo. Dicho método lanza una excepción. No hay garantía de
que habrá un manejador de excepciones (código que se ejecuta cuando el programa
66
Por ejemplo, los tipos de excepciones que pertenecen a una jerarquía de herencia.
Por ejemplo, completar las operaciones de E/S de disco, la llegada de mensajes de red, clics del ratón y pulsaciones de
teclas.
67
Programación orientada a objetos en Java
149
Unidad VII. Excepciones
detecta una excepción) para procesar este tipo de excepción. Si existe, el manejador de
excepciones atrapa y maneja a esa excepción. El resultado de una excepción no atrapada
a menudo produce efectos adversos y podría terminar con la ejecución del programa.
Java proporciona las instrucciones try para permitir el manejo de excepciones. Una
instrucción try consiste de la palabra clave try, seguida por llaves ({}) que delimitan a ese
bloque try. El bloque try contiene instrucciones que podrían ocasionar excepciones, e
instrucciones que no deberían ejecutarse en caso de que ocurra una instrucción. Debe
haber por lo menos una cláusula catch (a la que también se le llama manejador de
excepciones) o una cláusula finally inmediatamente después del bloque try. Cada cláusula
catch específica entre paréntesis un parámetro de excepción, el cual identifica al tipo de
excepción que puede procesar el manejador. El nombre del parámetro de excepción
permite que la cláusula catch interactúe con un objeto de excepción atrapada. Después
del último manejador catch, una clausula finally opcional proporciona código que siempre
se ejecuta, sin importar que ocurra o no una excepción.
El punto en el programa en que ocurre una excepción (es decir, la ubicación en la que un
método detecta y lanza una excepción) se conoce como el punto de lanzamiento. Si ocurre
una excepción en un bloque try, ese bloque termina inmediatamente y el control del
programa se transfiere a la primer cláusula catch que vaya después del bloque try. Esto se
conoce como modelo de terminación del manejo de excepciones, ya que el bloque try que
encierra a una excepción lanzada termina al ocurrir esa excepción. Al igual que con
cualquier otro bloque de código, cuando termina un bloque try las variables locales que
estén declaradas en el bloque quedan fuera de alcance. A continuación, el programa
busca la primera cláusula catch que puede procesar el tipo de excepción que ocurrió. El
programa ubica la cláusula catch que concuerde, comparando el tipo de la excepción
lanzada con el tipo de parámetro de excepción de cada cláusula catch, hasta que el
programa encuentre una concordancia. La concordancia ocurre si los tipos son idénticos, o
si el tipo de la excepción lanzada es una subclase del tipo de parámetro de excepción,
cuando ocurre una concordancia, se ejecuta el código contenido dentro del manejador
catch concordante. Cuando una cláusula catch termina de procesarse, las variables locales
que se declaran dentro de la cláusula (incluyendo su parámetro) quedan fuera de alcance.
Cualquier cláusula catch restante que corresponda a ese bloque try se ignora, y la
ejecución continúa en la primera línea de código después de la secuencia try/catch.
Si no ocurren excepciones en un bloque try, el programa ignora el (los) manejador(es)
para ese bloque. La ejecución del programa continúa con la siguiente instrucción que haya
después de la secuencia try/catch. Si aparece una cláusula finally después de la última
cláusula catch, la cláusula finally se ejecutará sin importa que ocurra o no una excepción.
Si ocurre una excepción en un método y no es atrapada, o la instrucción que produjo la
excepción no se encuentra dentro de un bloque try, hace que termine inmediatamente y el
programa trata de localizar un bloque try circundante en el método que hizo la llamada.
En la declaración de un método, una cláusula throws específica las excepciones que lanza
ese método. Esta cláusula aparece después de la lista de parámetros y antes del cuerpo
del método. La cláusula contiene una lista separada por comas de las excepciones que
lanzará el método, si ocurre un problema cuando éste se ejecute- dichas excepciones
pueden ser lanzadas por instrucciones en el cuerpo del método, o pueden lanzarse
Programación orientada a objetos en Java
150
Unidad VII. Excepciones
mediante los métodos que se llamen en el cuerpo. Un método puede lanzar excepciones
de clases indicadas, o puede lanzar excepciones de sus subclases.
Ejemplo de manejo de excepciones
- Error de División entre Cero.
Para evitar esta situación y gestionar un error de tiempo de ejecución, sencillamente hay
que incluir el código que quiera controlar dentro de un bloque try. Inmediatamente
después del bloque try, se incluye la cláusula match que especifica el tipo de excepción
que se desea capturar. Para mostrar como puede hacerse esto de forma sencilla, el
siguiente programa incluye un bloque try y una cláusula match que procesa la excepción
ArithmeticException generada por el error debido a la división entre cero.
Código 7.2.1.1. Error de división entre cero.
Este programa genera la siguiente salida:
División entre cero.
Después de la sentencia Catch.
Nótese que la llamada a println() dentro del bloque try no llega a ejecutarse. Una vez que
se lanza una excepción. Por lo tanto, no aparece en pantalla la línea “Esto no será
impreso”. Una vez que se ejecuta la sentencia catch, el control del programa continua con
la siguiente línea al bloque try/catch.
Un bloque try y su correspondiente sentencia catch forman una unidad. El campo de
acción de una cláusula catch se limita a aquellas sentencias especificadas por la sentencia
try que le precede inmediatamente. Una sentencia catch no puede capturar una ejecución
lanzada por otra sentencia try, excepto en el caso de las sentencias try anidadas. Las
sentencias protegidas por try han de estar entre llaves, es decir han de estar en un bloque
no puede usarse try en una sentencia individual.
Programación orientada a objetos en Java
151
Unidad VII. Excepciones
El objetivo de la mayoría de cláusulas catch bien construidas ha de ser el de resolver la
condición excepcional y luego continuar como si el error nunca hubiese ocurrido. Por
ejemplo, en el siguiente programa cada iteración de bloque for obtiene dos enteros
aleatorios. Estos dos enteros se dividen uno entre el otro, y el cociente se utiliza como
divisor del valor 12345. El resultado final se almacena en la variable a. si en cualquiera de
las dos operaciones se produce una división entre cero, se captura el error, el resultado
se pone a cero y el programa continua.
Código 7.2.1.2 Manejo de excepciones.
7.2.1 Lanzamiento de Excepciones
El lanzamiento de las excepciones se hace con las palabras try – catch – finally
Try
Es el bloque de código donde se prevé que se genere una excepción. Es como si se dijera
"intenta estas sentencias y mira a ver si se produce una excepción". El bloque try tiene
que ir seguido, al menos, por una cláusula catch o una cláusula finally.
Catch
Es el código que se ejecuta cuando se produce la excepción. Es como si se dijera "controlo
cualquier excepción que coincida con mi argumento". En este bloque se tiene que
asegurar de colocar código que no genere excepciones. Se pueden colocar sentencias
catch sucesivas, cada una controlando una excepción diferente. No debería intentarse
capturar todas las excepciones con una sola cláusula, como esta:
Programación orientada a objetos en Java
152
Unidad VII. Excepciones
catch( Excepcion e ) { ...
Esto representaría un uso demasiado general, podrían llegar muchas más excepciones de
las esperadas. En este caso es mejor dejar que la excepción se propague hacia arriba y
dar un mensaje de error al usuario.
Se pueden controlar grupos de excepciones, es decir, que se pueden controlar, a través
del argumento, excepciones semejantes. Por ejemplo:
Código 7.2.1.3 Control de exepciones
La cláusula catch comprueba los argumentos en el mismo orden en que aparezcan en el
programa. Si hay alguno que coincida, se ejecuta el bloque. El operador instanceof se
utiliza para identificar exactamente cual ha sido la identidad de la excepción.
Finally
Es el bloque de código que se ejecuta siempre, haya o no excepción. Hay una cierta
controversia entre su utilidad, pero, por ejemplo, podría servir para hacer un log o un
seguimiento de lo que está pasando, porque como se ejecuta siempre puede dejar
grabado si se producen excepciones y se ha recuperado de ellas o no.
Programación orientada a objetos en Java
153
Unidad VII. Excepciones
Este bloque finally puede ser útil cuando no hay ninguna excepción. Es un trozo de código
que se ejecuta independientemente de lo que se haga en el bloque try.
Cuando se va a tratar una excepción, se plantea el problema de qué acciones se van a
tomar. En la mayoría de los casos, bastará con presentar una indicación de error al
usuario y un mensaje avisándolo de que se ha producido un error y que decida si quiere o
no continuar con la ejecución del programa.
Para lanzar una excepción se tienen que hacer dos cosas como mínimo. La primera es
crear el objeto que se va a lanzar, la segunda, lanzar el objeto. Para realizar esto se crea
una instancia de un objeto perteneciente a la jerarquía de java.lang.Throwable, luego se
utiliza la instrucción throw para lanzar el objeto.
Normalmente esta tarea se realiza en una sola línea ya que al lanzar el objeto se crea
información para que la excepción sea reportada y es conveniente que la línea que se
reporta como origen de la excepción sea la misma donde se lanza. La siguiente es un
ejemplo de esto:
throw new IOException("No se encuentra el archivo");
Java requiere, como regla general que todo método que pueda lanzar una excepción debe
declarase específicamente, no importa si es explícitamente lanzada por el método o por un
método que fue llamado. Para realizar esto se utiliza la instrucción throws en la
declaración del método de la siguiente forma:
public void dividir(int x, int y) throws ArithmeticException, IOException {
}
La jerarquía de clases que existe bajo la clase java.lang.Throwable esta dividida en tres
partes. Una parte, java.lang.Error contiene excepciones que se utilizan para indicar
errores, java.lang.Exception que contiene las llamadas excepciones de verificación y
java.lang.RuntimeException que es subclase de java.lang.Exception y agrupa las llamadas
excepciones en tiempo de ejecución que son siempre por errores de programación.
Las excepciones de verificación describen los problemas que pueden darse en un
programa, típicamente, dificultades con el ambiente como problemas de conexión con la
red. En un programa comercial se debe escribir código que pueda manejar y recuperarse
de estas excepciones. De hecho, el compilador verifica que se estén manejando estas
excepciones por lo que entrega un mensaje de error en tiempo de compilación si alguna
no esta manejada.
Las excepciones en tiempo de ejecución típicamente describen errores de programa como
índices fuera de rango, aquellas que con un código correctamente escrito normalmente no
es necesario manejar. Lógicamente no se deberían de manejar errores que no deberían de
sucederse.
Programación orientada a objetos en Java
154
Unidad VII. Excepciones
java.lang.Error describe problemas que son muy inusuales y por lo tanto de difícil
recuperación por lo tanto no se requiere que se manejen. Estos reflejan un error de
programa o problemas de ambiente como puede ser la memoria agotada.
Una estrategia de diseño e implementación de programa que es muy efectiva a la hora de
producir código robusto y confiable es programar por contrato. Usando esta estrategia se
definen las responsabilidades de los métodos y de aquellos que llaman a esos métodos. En
un método dividir se puede requerir que el divisor sea distinto de cero, en caso contrario
se lanza una excepción dado que el contrato entre el método que llama y el llamado se ha
roto. Para este tipo de mensajes se deben utilizar excepciones de tiempo de ejecución ya
que la llamada claramente es inapropiada y el que realiza la llamada debe verificar estos
errores de programación y corregirlos.
Para manejar una excepción de verificación se debe decidir que hacer con ella. Se puede
colocar un bloque try/catch para tratar de recuperarse o decidir que el método debe ser
abandonado cuando se sucede la excepción. En este último caso no es necesario utilizar
try/catch pero si hay que especificar que excepción será lanzada utilizando throws en la
declaración del método.
Cuando se extiende una clase y se sobrecarga un método el compilador insiste en que
todas las excepciones lanzadas por el nuevo método deben ser las mismas o subclases de
las lanzadas por el método original. De la misma forma no puede lanzar ninguna
excepción que no sea subclase de la excepción declarada en la clase base.
7.3 Excepciones Definidas por el Usuario
7.3.1 Clase Base de las Excepciones
Todas las excepciones que se lanzan en Java están consideradas en el árbol de
excepciones que se deriva de la clase Throwable. Por lo cual la clase Throwable es
considerada la clase base de las excepciones. Existen dos subclases directas de
Throwable: Error y Exception. Los objetos de la clase Error provocan que el intérprete de
Java presente un mensaje de información y concluya la ejecución del programa. Los
objetos de la clase Exception indican condiciones anómalas durante la ejecución de un
método. Esta clase tiene, a su vez, nueve subclases predefinidas. Las clases de
excepciones definidas por el programador se construyen como subclases de la clase
Exception.
En la siguiente figura 16 se observa parte de la jerarquía de clases derivada de Throwable:
La clase Error está relacionada con errores de la máquina virtual de Java y no el código,
generalmente estos errores no
dependen del programador por lo que no debe
preocuparse por tratarlos. En la clase Exception se encuentran las excepciones
RuntimeException, producidas por errores de programación. El compilador de Java obliga
a corregirlas.
Programación orientada a objetos en Java
155
Unidad VII. Excepciones
Figura 16: Clase base de la clase Throwable.
Como se puede ver en la figura 16, la clase Throwable tiene dos descendientes directos:
Error y Exception.
- Error
Cuando falla un enlace dinámico, y hay algún fallo "hardware" en la máquina virtual, ésta
lanza un error. Tipicamente los programas Java no capturan los Errores. Pero siempre
lanzarán errores.
- Exception
La mayoría de los programas lanzan y capturan objetos derivados de la clase Exception.
Una Excepción indica que ha ocurrido un problema pero que el problema no es demasiado
serio. La mayoría de los programas que se escriben lanzarán y capturarán excepciones. La
clase Exception tiene muchos descendientes definidos en los paquetes Java. Estos
descendientes indican varios tipos de excepciones que pueden ocurrir. Por ejemplo,
IllegalAccessException señala que no se puede encontrar un método particular, y
NegativeArraySizeException indica que un programa intenta crear un array con tamaño
negativo.
Una subclase de Exception tiene un significado especial en el lenguaje Java:
RuntimeException.
Excepciones en Tiempo de Ejecución
La clase RuntimeException representa las excepciones que ocurren dentro de la máquina
virtual Java 68(durante el tiempo de ejecución). Un ejemplo de estas excepciones es
NullPointerException, que ocurre cuando un método intenta acceder a un miembro de un
objeto a través de una referencia nula. Esta excepción puede ocurrir en cualquier lugar en
68
Java Virtual Machine (JVM).
Programación orientada a objetos en Java
156
Unidad VII. Excepciones
que un programa intente desreferenciar una referencia a un objeto. Frecuentemente el
costo de checar estas excepciones sobrepasa los beneficios de capturarlas.
Los paquetes Java definen varias clases RuntimeException. Se pueden capturar estas
excepciones al igual que las otras. Sin embargo, no se requiere que un método especifique
que lanza excepciones en tiempo de ejecución. Además puedes crear sus propias
subclases de untimeException.
Excepciones en Tiempo de Ejecución -- La Controversia contiene una explicación detallada
sobre cómo utilizar las excepciones en tiempo de ejecución.
7.3.2. Creación de una Clase Derivada del Tipo Excepción
Aunque las excepciones que incorpora Java gestionan la mayoría de los errores más
comunes, es probable que el programador prefiera crear sus tipos de excepciones para
gestionar situaciones específicas a sus aplicaciones, esto es bastante sencillo de conseguir
definiendo una subclase de Throwable. En realidad, no es necesario que estas subclases
que crea el programador implementen nada. simplemente, es su presencia en el sistema
lo que permitirá que se utilicen como excepciones.
La clase exception no define ningún método por si misma, pero, obviamente, hereda los
métodos que proporciona la clase Throwable. Por tanto todas las excepciones, incluyendo
aquellas que crea el programador, pueden disponer de métodos definidos por Throwable.
Estos métodos, que además pueden sobrescribirse en las clases de excepción propias, se
recogen en la tabla siguiente:
Tabla. Métodos definidos por la clase Throwable
Método
Throwable
Throwable getCause()
Descripción
Devuelve un objeto de la clase throwable que contiene el
trazado completo de la pila
Devuelve la excepción que subyace en la excepción actual. Si
no hay excepciones subyacentes, se devuelve null
Devuelve una descripción localizada de la excepción.
String
getLocalizedMessage()
StackTraceElement[]
getStack Trace()
Devuelve una descripción de la excepción
Devuelve una matriz que contiene el trazado de la pila, un
elemento cada vez, y una matriz de StackTraceElement. El
primer método de la pila es el último de ser llamado antes de
que se lancé la excepción este método se encuentra en el
primer elemento de la matriz. La clase StackTraceElement da
al programa acceso a la información acerca de cada elemento
en el trazado, así como acerca de los nombres de los métodos.
Programación orientada a objetos en Java
157
Unidad VII. Excepciones
Asocia causeExc con la llamada a la excepción como causa de
la excepción de la llamada. Devuelve una referencia a la
excepción
Presenta en la pantalla el trazado de la pila
Envía el trazado de la pila a flujo determinado
Throwable InitCause
(throwable causeExc)
void printStackTrace()
void printStackTrace
(PrintSreamstream)
Envía el trazado a los elementos pasados en elementos. Este
método es para aplicaciones especializadas , no para un uso
común
Devuelve una cadena con la descripción de la excepción , ese
método es llamado como println() cuando se desea imprimir
un objeto de la clase throwable.
void printDStackTrace
(Snack
TraceElementselements)
String toString()
El siguiente ejemplo declara una nueva subclase de excepcion y luego utiliza esta subclase
para señalar una condición de error en un método. Esta subclase sobrescribe el método
toString() para permitir que la descripción de la excepción puede impimirse mediante
println():
Programación orientada a objetos en Java
158
Unidad VII. Excepciones
Código 7.3.2.1 Programa que crea un tipo propio de excepción.
Este ejemplo define una subclase de Exception, llamada MiExcepcion. Esta subclase es
bastante sencilla, sólo contiene un constructor y un método sobrecargado, toString(), que
permitirá presentar el valor de la excepción. La clase ExcepcionDemo define un método,
llamado compute(), que lanza un objeto del tipo MiExcepcion.
La excepción se lanza cuando el parámetro entero de compute() es superior a 10. El
método main() establece un gestor de excepciones para MiExcpecion, luego llama a
compute() con un valor legal inferior a 10, y con un valor no válido. Para mostrar las dos
vías que sigue el código.
Este es el resultado:
Llamado a compute(1)
Salida normal
Llamado a compute(20)
Agarrada MiExcepcion[20]
7.3.3 Manejo de una Excepción Definida por el Usuario
Para el manejo de las excepciones propias, solo se extiende la clase Exception.
Programación orientada a objetos en Java
159
Unidad VII. Excepciones
Por ejemplo, considérese un programa cliente/servidor. El código cliente se intenta
conectar al servidor, y durante 5 segundos se espera a que conteste el servidor. Si el
servidor no responde, el servidor lanzaría la excepción de time-out:
Si se quieren capturar las propias excepciones, se deberá utilizar la sentencia try:
Código 7.3.2.Manejo de una excepción definida por el usuario. Sólo se
extiende la clase Exception
Cualquier método que lance una excepción también debe capturarla, o declararla como
parte del interfaz del método. Cabe preguntarse entonces, el porqué de lanzar una
excepción si hay que capturarla en el mismo método. La respuesta es que las excepciones
no simplifican el trabajo del control de errores69. Tienen la ventaja de que se puede tener
muy localizado el control de errores y no hay que controlar millones de valores de retorno,
pero no van más allá.
7.4 Ejercicios resueltos
7.4.1 Implementar un programa que pida un entero y lance una excepción si se teclea una
letra o cualquier otro carácter.
69
Aunque muchos desarrolladores de software tienen esa noción.
Programación orientada a objetos en Java
160
Unidad VII. Excepciones
7.4.2 Implementar un programa que realice una operación de división introduciendo los
dos valores desde el teclado y mande una excepción en caso de que uno de los valores no
sea numérico o la división de cero.
7.4.3 Implementar un programa que reciba dos parámetros desde la línea de comandos y
los sume. Si no se omite alguno de los dos, se manda una excepción.
Programación orientada a objetos en Java
161
Unidad VII. Excepciones
7.4.4 Implementar un programa realice la división de dos números naturales, si uno de los
dos no lo es, que arroje una excepción.
Programación orientada a objetos en Java
162
Unidad VII. Excepciones
7.5 Ejercicios propuestos:
7.5.1 Escribir un código de una clase Java que lance excepciones para cuantas condiciones
considere convenientes. Utilizar una cláusula catch que utilice la sentencia switch para
seleccionar el mensaje apropiado y terminar el calculo.
Nota. Utilice una jerarquía de clases para listas las condiciones de error.
7.5.2 Escribir un código de un método en el cual se defina un bloque try y dos
manejadores catch. En uno de ellos se relanza la excepción. También ha de haber un
manejador finally, que lanzara una excepción que relanza el catch, para lo cual, escribir un
sencillo programa en que se genere la excepción que es captada por el catch descrito.
7.5.3 Escribir el código de una clase para tratar el error que se produce cuando un
argumento de un algoritmo neperiano es negativo. El constructor de la clase tendrá como
argumento una cadena y el valor que generado el error.
7.5.4 Escriba un programa Java en el que se genere la excepción del problema anterior, y
se capture.
7.5.5 Definir una clase para tratar los errores en el manejo de cadenas de caracteres. A
continuación, definir una subclase para tratar el error supuesto de cadenas de longitud
mayor de 30 caracteres, y otra subclase que maneje los errores de cadenas que tienen
caracteres no alfabéticos.
7.5.6 Escribir un programa java en el que se de entrada a cadenas de caracteres y se
capturen excepciones del tipo mencionado en el problema anterior.
7.5.7 Escribir un programa que demuestren como se atrapan las diversas excepciones
mediante:
catch (Excepction exception)
7.5.8Escriba un programa que demuestre como un constructor pasa información sobre
falla del constructor a un manejador de excepciones.
7.5.9 Escribir un programa que demuestre como volver a lanzar una excpecion.
7.5.10 Escriba un programa que demuestre que un método con su propio bloque try no
tiene que atrapar cada posble error generado dentro de este bloque try. Algunas
excepciones podrían escabullirse y manejarse en otros alcances.
Programación orientada a objetos en Java
163
Unidad VIII. Flujos y archivos
UNIDAD 8.FLUJOS Y ARCHIVOS
Definición, Tipos y Operaciones básicas de Archivos
Programación orientada a objetos en java
164
Unidad VIII. Flujos y archivos
UNIDAD 8.- FLUJOS Y ARCHIVOS
8.1 Definición de archivos de texto y Archivos Binarios
Archivos de texto: Es una estructura de datos permanente no estructurada formada por
una secuencia de caracteres ASCII
compuestos
70
.
Los archivos de texto son aquellos que están
únicamente por texto sin formato, sólo caracteres. Estos caracteres se
pueden codificar de distintos modos dependiendo de la lengua usada. Algunos de los
sistemas de codificación más usados son: ASCII, ISO-8859–1 o Latín-1, Unicode, etc. Se
les conoce también como archivos de texto plano por carecer de información destinada a
generar formatos y tipos de letra (por ejemplo, tipo de letra: Arial, Times, Courier;
formato: negritas, subrayado, cursivas; tamaño, etc.).
Las aplicaciones destinadas a la escritura y modificación de archivos de texto se llaman
editores de texto.
La costumbre ha hecho que se nombren con la extensión de archivo .TXT aunque pueden
tener cualquier otra, a capricho del usuario (son válidas y habituales .INF .80 .DAT .TMP
.PRV .HLP etc.). Los archivos .BAT (o de proceso por lotes), los .HTM y muchos otros son
también archivos de texto, que tienen funciones especiales.
Archivos binarios: Es una estructura de datos permanente compuesto por registros
(filas) y éstos a su vez por campos (columnas). Se caracteriza por tener un tipo de dato
asociado, el cual define su estructura interna.
Los archivos binarios son archivos electrónicos que han sido guardados utilizando el
código básico de las computadoras u ordenadores: una sucesión de ceros y unos.
Constituyen, en última instancia, la forma en la cual almacenan la información, aunque su
interacción con los usuarios requiere de lenguajes auxiliares que resulten más inteligibles
al ser humano.
70
Acrónimo de American Standard Code for Information Interchange (Código Normalizado Americano para el Intercambio
de la Información).
Programación orientada a objetos en java
165
Unidad VIII. Flujos y archivos
8.2 Operaciones Básicas en Archivos de Texto y Binario
8.2.1 Crear
Para crear un archivo la sintaxis es:
FileWriter nombre_variable = new FileWriter(“Nombre del archivo incluyendo ruta”)
Por ejemplo:
FileWriter archivo = new FileWriter("c:/prueba.txt");
En el ejemplo anterior se crea un archivo de nombre pureba.txt ubicado en la ruta c:.
Si quiere añadir al final de un archivo ya existente, simplemente se debe poner un flag a
true como segundo parámetro del constructor de FileWriter
FileWriter archivo = new FileWriter("c:/prueba.txt",true);
En este ejemplo se añadirán líneas al final del archivo prueba.txt
8.2.2 Abrir
La apertura de un archivo se hace con la siguiente sentencia:
FileReader nombre_variable = new FileReader(“Nombre del archivo incluyendo
ruta”)
Por ejemplo:
FileReader fr2 = new FileReader("archivo.txt");
Esto es equivalente a:
File archi = new File("archivo.txt");
FileReader fr2 = new FileReader(archi);
Si a la hora de la apertura no encuentran el archivo indicado, los constructores de
FileReader y FileInputStream pueden lanzar la excepción java.io.FileNotFoundException.
Programación orientada a objetos en java
166
Unidad VIII. Flujos y archivos
8.2.3 Cerrar
public void close() throws IOException
Cierra el stream de entrada. Este método debe invocarse para liberar los recursos71
asociados al stream. Una vez que el stream ha sido cerrado, las operaciones posteriores
sobre dicho sfream producirán una exepción IOException. Cerrar un stream previamente
cerrado no tiene ningún efecto. La implementación por defecto de close no hace nada.
8.2.4 Lectura y Escritura
Frecuentemente los programas necesitan traer información desde una fuente externa o
enviar información a una fuente externa. La información puede estar en cualquier parte,
en un archivo, en disco, en algún lugar de la red, en memoria o en otro programa.
También puede ser de cualquier tipo: objetos, caracteres, imágenes o sonidos.
Para traer la información, un programa abre un stream sobre una fuente de información
(un archivo, memoria, un socket) y lee la información serialmente, de esta forma:
Flujo
Lectura
Fuente
Programa
Similarmente, un programa puede enviar información a un destino externo abriendo un
stream sobre un destino y escribiendo la información serialmente, de esta forma:
Escritura
Flujo
Fuente
Destino
No importa de donde venga o donde vaya la información y tampoco importa el tipo de los
datos que están siendo leídos o escritos, los algoritmos para leer y escribir son casi
siempre los mismos.
Leer
abrir un stream
mientras haya información
leer información
cerrar el stream
71
Escribir
abrir un stream
mientras haya información
escribir información
cerrar el stream
Como los descriptores de archivos.
Programación orientada a objetos en java
167
Unidad VIII. Flujos y archivos
El paquete java.io contiene una colección de clases stream que soportan estos algoritmos
para leer y escribir. Estas clases están divididas en dos árboles basándose en los tipos de
datos (caracteres o bytes) sobre los que opera.
Flujo de caracteres
Flujo de bytes
Sin embargo, algunas veces es más conveniente agrupar las clases basándose en su
propósito en vez en los tipos de datos que lee o escribe. Así, se pueden agrupar los
streams dependiendo de si leen u escriben lados en las "profundidades" o procesan la
información que está siendo leída o escrita.
Flujo de caracteres
Flujo de bytes
Caída de flujo de datos
Procesando flujos
InputStream
La clase abstracta InputStream declara métodos para leer bytes de una fuente particular
InputStream es la superclase de la mayoría de los streams de bytes de entrada en java y
tiene los siguientes métodos:
public abstract int read() throws IOException
Lee un solo byte de datos y devuelve el byte leído como un valor entero en el intervalo de
O a 255, no de -128 a 127. En otras palabras, el valor del byte se trata como un entero
sin signo. Si no hay un byte disponible debido a que se ha alcanzado el final del stream,
se devuelve el valor -1. Este método se bloquea hasta que haya entrada disponible, se
encuentre el final del stream o se lance una excepción. Se devuelve un int en vez valor de
byte real porque se necesita devolver todos los valores de byte válidos, Más un indicador
de final de stream. Para ello se requieren más valores de los que puede permitir un byte,
por lo que se usa el tipo mayor de int.
Programación orientada a objetos en java
168
Unidad VIII. Flujos y archivos
public int read(byte[] buf, int despl, int cuenta) throws IOException
Lee bytes y los almacena en una parte de un array de byte. El máximo número de bytes que
se leen es cuenta. Los bytes se almacenan desde buf [despl] hasta un máxima buf [despl
+cuenta-1 ]. Todos los demás valores de buf se dejan inalterados. Se devuelve el número
de bytes que se han leído realmente. Si no se leen bytes debido a que se detectado el final
del stream, se devuelve el valor -1. Si cuenta vale cero, no se leen bytes y se devuelve
cero. Este método se bloquea hasta que haya entrada disponible, se alcance el final del
stream o se lance una excepción. Si no se puede leer el primer byte, una razón diferente a
la de detectar el final del stream (Por ejemplo, stream ya ha sido cerrado), se lanza una
excepción IOException. Una vez que se ha leído el byte, cualquier fallo posterior al tratar
de leer bytes subsecuentes no se indica con una excepción, sino que se trata como si se
encontrara el final del stream: el método se completa normalmente y devuelve el número
de bytes leídos antes de que se produjera el fallo.
public int read(byte[] buf) throws IOException
Es equivalente a read (buf, 0, buf .length).
public long skip(long cuenta) throws IOException
Salta un máximo de cuenta bytes de la entrada, o hasta que se detecte el final del
stream. Devuelve el número real de bytes que se han saltado. Si cuenta es negativo, no
se salta ningún byte.
public int available() throws IOException
Devuelve el número de bytes que se pueden leer (o saltar) sin bloquearse. La
implementación por defecto devuelve cero.
public void close() throws IOException
Cierra el stream de entrada. Este método debe invocarse para liberar los recursos (Como
los descriptores de archivos) asociados al stream. Una vez el stream ha sido cerrado, las
operaciones posteriores sobre dicho stream producirán una excepción IOException. Cerrar
un stream previamente cerrado no tiene ningún efecto. La implementación por defecto de
close no hace nada.
La implementación de InputStream requiere sólo que una subclase proporcione la
variante de un solo byte de read, ya que los otros métodos read se definen en función de
aquélla. La mayoría de los Streams, sin embargo, pueden mejorar las prestaciones
redefiniendo también otros métodos. Las implementaciones por defecto de available y
close necesitan generalmente ser redefinidas para adecuarlas a un stream particular.
El programa siguiente muestra el uso de streams de entrada para contar el número
total de bytes de un archivo, o de System.in si no se especifica ningún archivo:
Programación orientada a objetos en java
169
Unidad VIII. Flujos y archivos
Código 8.2.4.1 Programa que toma un archivo de la línea de comandos y
cuenta los bytes.
El programa toma un nombre de archivo de la línea de comandos. La variable in
representa el stream de entrada. Si no se proporciona un nombre de archivo, se utiliza el
stream de entrada estándar, System.in. Si se proporciona, se crea un objeto
FilelnputStream, una subclase de InputStream.
El ciclo72 while cuenta el número total de bytes del archivo. Al final, se imprime el resultado. Ésta es la salida cuando el programa se ejecuta sobre su propio archivo fuente:
•
318 bytes
Se podría estar tentado de obtener el total utilizando el método available, pero esto no
funcionaría con muchos tipos de streams. El método available devuelve el número de
bytes que se pueden leer sin bloqueo. En el caso de un archivo, el número de bytes
disponibles es generalmente su contenido total. Pero si System.in está asociada a un
teclado, la respuesta podría ser incluso cero, ya que si no hay entrada pendiente el
siguiente read se bloqueará.
OutputStream
La clase abstracta OutputStream es análoga a InputStream. Proporciona una abstracción
para escribir bytes en un destino. Sus métodos son:
public abstract void write(int b) throws IOException
Escribe b como un byte. Este byte se pasa como un int porque a menudo es el resultado
de una operación aritmética sobre un byte. Las expresiones que involucran bytes son de
tipo int, por lo que hacer que el parámetro sea int significa que el resultado puede pasar a
byte sin realizar una conversión explícita de tipo. Nótese, sin embargo. Que sólo se
escriben los 8 bits de menor peso del int. Este método se bloquea hasta que el byte se
escribe.
72
Ciclo.
Programación orientada a objetos en java
170
Unidad VIII. Flujos y archivos
public void write(byte[] buf, int despl, int cuenta) throws IOException
Escribe parte de un array de bytes, empezando en buf [despl], y escribiendo cuenta bytes.
Este método se bloquea hasta que los bytes han sido escritos.
public void write(byte[] buf) throws IOException
Equivale a write (buf, 0, buf .length)
public vaid flush() throws IOException
Vacía el stream. Si el stream tiene bytes en buffers correspondientes a varios métodos.
write, flush los envía inmediatamente a su destino. Si el destino es otro stream, también
se vacía. Una sola invocación a flush vaciará todos los streams de una cadena. Si el
stream no es buffered, puede ocurrir que flush no haga nada (que es su implementación
por •defecto).
public void close() throws IOException
Cierra el stream de salida. Este método se debe invocar para liberar los recursos (como
los descriptores de archivos) asociados al stream. Una vez que un stream ha sido cerrado,
las operaciones posteriores sobre el mismo harán que se lance una IOException. Cerrar un
stream previamente cerrado no tiene ningún efecto. La implementación por defecto de
close no hace nada.
La implementación de OutputStream requiere sólo que una subclase proporcione la variante de un solo byte de write, ya que los otros métodos write se definen en términos de
aquélla. La mayoría de los streams, sin embargo, pueden mejorar sus prestaciones
redefiniendo también otros métodos. Las implementaciones por defecto de flush y close
necesitarán generalmente ser redefinidas de forma apropiada para cada stream particular.
Concretamente, por ejemplo, puede ser necesario vaciar los streams buffered cuando se
cierran.
Se presenta seguidamente un programa que copia su entrada en su salida, transformando
un valor particular de byte en otro por el camino. El programa TransformarByte toma dos
parámetros: un byte desde y un byte hacia los bytes que coinciden con el valor en la
cadena de texto.
Código 8.2.4.2 Programa que toma dos parámetros, un byte desde y un byte
hacia.
Programación orientada a objetos en java
171
Unidad VIII. Flujos y archivos
Por ejemplo, si se invoca al programa de la siguiente forma:
java TransformarByte b B
Si se tecleara el texto ¡abracadabra!, se obtendría como salida
¡aBracadaBra!
El manejo de datos de un stream después de leerlo, o antes de escribirlo, se realiza
generalmente escribiendo streams Filter, en lugar de codificar directamente dicho manejo
en un
• programa.
Como en el caso de streams de bytes, los streams de caracteres se deben cerrar explícitamente para liberar sus recursos asociados.
Reader73
La clase abstracta Reader proporciona un stream de caracteres análogo al stream de
bytes InputStream, y los métodos de Reader son esencialmente un reflejo de los de
InputStream:
public int read() throws IOException
Lee un solo carácter y lo devuelve como un valor entero en el intervalo de O a 65535. Si
no hay un carácter disponible debido a que se ha alcanzado el final del stream. Se devuelve el valor -1. Este método se bloquea hasta que haya entrada disponible, se encuentre el final del stream o se lance una excepción.
public abstract int read(char[l buf, int despl, int cuenta) throws IOException
Lee caracteres y los almacena en una parte de un array de char. El máximo número de
caracteres que se leen es cuenta. Los caracteres leídos se almacenan desde buf [despl]
hasta un máximo de buf[despl+cuenta-1]. Todos los demás valores de buf se dejan
inalterados. Se devuelve el número de caracteres que se han leído realmente. Si no se
leen caracteres debido a que se detecta el final del stream, se devuelve el valor -1. Si
cuenta vale cero, no se leen caracteres y se devuelve cero. Este método se bloquea hasta
que haya entrada disponible, se alcance el final del stream o se lance una excepción. Si no
se puede leer el primer carácter por una razón diferente a la de detectar el final del
stream (concretamente por ejemplo, si el stream ya ha sido cerrado), se lanza una excepción IOException. Una vez que se ha leido un carácter, cualquier fallo posterior al tratar de leer caracteres subsecuentes no se indica con una excepción, sino que se trata
como si se encontrara el final del stream: el método se completa normalmente y devuelve
el número de caracteres leídos antes de que se produjera el fallo.
public int read(char[] buf) throws IOException
Es equivalente a read (buf, 0, buf .length).
73
Lector.
Programación orientada a objetos en java
172
Unidad VIII. Flujos y archivos
public long skip(long cuenta) throws IOException
Salta un máximo de cuenta caracteres de la entrada, o hasta que se detecte el final del
stream. Devuelve el número real de caracteres que se han saltado. El valor de cuenta no
puede ser negativo.
public boolean ready() throws IOException
Devuelve true si el stream está listo para ser leído, es decir, si hay al menos un carácter
disponible para ser leído. Nótese que un valor de retorno de false no garantiza que la
siguiente invocación de read se bloqueará, ya que pueden haber llegado nuevos datos
disponibles en el momento que se produce la invocación a read.
public abstract void close() throws IOException
Cierra el stream de entrada. Este método debe invocarse para liberar los recursos (como
los descriptores de archivos) asociados al stream. Una vez el stream ha sido cerrado, la
operaciones posteriores sobre dicho stream producirán una exepción IOExeeption. Cerrar
un stream previamente cerrado no tiene ningún efecto.
La implementación de Reader requiere sólo que una subclase proporcione la implementación del método read que lee en un array de char, y el método close. Muchas subclases
pueden mejorar las prestaciones redefiniendo también los otros métodos.
Hay varias diferencias entre Reader e InputStream. En el caso de Reader, el método fundamental de lectura lee en un array de char, y los otros métodos read se definen en
función de ese método fundamental. Por el contrario, la clase InputStream usa el método
read de un solo byte como método fundamental de lectura. En la clase Reader las
subclases deben implementar el método abstracto close, y no heredan una
implementación vacía (muchas clases de streams necesitarán saber al menos si han sido o
no cerradas, por lo que close necesitará generalmente ser redefinido). Finalmente,
InputStream tiene un método available para indicar cuántos datos hay disponibles para
lectura, mientras que Reader tiene un método ready que indica simplemente si hay datos
disponibles.
Programación orientada a objetos en java
173
Unidad VIII. Flujos y archivos
Código 8.2.4.3. Programa que cuenta el número de caracteres blancos que hay en un stream de
caracteres.
total caracteres , 111 espacios
Writer74
La clase abstracta writer proporciona un stream análogo a OutputStream, pero diseñado
para trabajar con caracteres en vez de con bytes. Los métodos de writer son
esencialmente un reflejo de los OutputStream, pero añaden algunas formas útiles
de write.
void write(char[] buf, int despl, int cuenta) thro IOException
Escribe parte de un array de caracteres, empezando en buf [despl], y escribiendo cuenta
caracteres. Este método se bloquea hasta que los caracteres han sido escritos.
public void write(char[] buf) throws IOException
Es equivalente a write (buf , 0 , buf .length).
public void write(String cad, int despl, int cuenta) throws IOException
Escribe cuenta caracteres de la cadena de texto cad, empezando en cad. charAt (despl).
74
Escritor.
Programación orientada a objetos en java
174
Unidad VIII. Flujos y archivos
public void write(String cad) throws IOException
Equivale a write (cad , 0 , cad. length (c)
public abstract void flush() throws IOException
Vacía el stream. Si el stream tiene caracteres en buffers correspondientes a varios métodos write, flush los envía inmediatamente a su destino. Si el destino es otro stream,
también se vacía. Una sola invocación a flush vaciará todos los streams de una cadena. Si
el stream no es buffered, flush no hará nada.
public abstract void close() .throws IOException
Cierra el stream de salida, vaciándolo si es necesario. Este método se debe invocar para
liberar los recursos (como los descriptores de archivos) asociados al stream. Una vez
que un stream ha sido cerrado, las operaciones posteriores sobre el mismo harán que
se lance una IOException_ Cerrar un stream previamente cerrado no tiene ningún
efecto.
Las subclases de Writer deben implementar la variante de write que opera sobre un
array. y los métodos close y flush. Todos los demás métodos de Writer se implementan
en función de estos tres. Esto es una diferencia con OutpuStream, que utiliza la variante
de un solo byte del método write como método fundamental, y proporciona
implementaciones por defecto de flush y close_ Como en el caso de Reader, muchas
subclases pueden dar mejores prestaciones si redefinen también otros métodos.
public abstract void close() .throws IOException
Cierra el stream de salida, vaciándolo si es necesario. Este método se debe invocar para
liberar los recursos (como los descriptores de archivos) asociados al stream. Una vez
que un stream ha sido cerrado, las operaciones posteriores sobre el mismo harán que
se lance una IOException_ Cerrar un stream previamente cerrado no tiene ningún
efecto.
Las subclases de Writer deben implementar la variante de write que opera sobre un
array. y los métodos close y flush. Todos los demás métodos de Writer se implementan
en función de estos tres. Esto es una diferencia con OutpuStream, que utiliza la variante
de un solo byte del método write como método fundamental, y proporciona
implementaciones por defecto de flush y close_ Como en el caso de Reader, muchas
subclases pueden dar mejores prestaciones si redefinen también otros métodos.
InputStreamReader
75
y OutputStreamWriter76
Los streams de conversión InputStreamReader y OutputStreamWriter realizan conversiones entre Unicode y streams de bytes utilizando una determinada codificación, o la
75
Para java, un InputStream es cualquier cosa de la que se leen bytes. Puede ser el teclado, un archivo, un socket, o
cualquier otro dispositivo de entrada.
76
Para Java, un OutputStreamWriter es cualquier cosa en donde se puedan escribir bytes, un archivo, un socket
o cualquier dispositivo de salida.
Programación orientada a objetos en java
175
Unidad VIII. Flujos y archivos
codificación por defecto del sistema local. Los objetos InputS reamReader reciben como
fuente un stream de bytes de entrada y producen los correspondientes caracteres de
Unicode. Los objetos OutputStreamReader reciben como destino un stream de bytes de
salida y producen las formas codificadas en bytes de los caracteres Unicode que se
escriben. Por ejemplo, el código que se presenta a continuación lee bytes
correspondientes a caracteres árabes codificados con ISO 8859-6, Y los convierte en los
caracteres de Unicode apropiados.
Por defecto, estos streams de conversión funcionarán con la codificación por defecto de la
plataforma, y si se desean utilizar otras codificaciones, deberán especificarse. Estas clases
son el "pegamento" que permite utilizar codificaciones locales de caracteres de 8 bits de
forma consistente e independiente de la plataforma.
public InputStreamReader(InputStream in)
Crea un InputStreamReader para leer de un InputStream dado utilizando la codificación de
caracteres por defecto.
public InputStreamReader(InputStream in, String codificacion)
throws UnsupportedEncodingException
Crea un InputStreamReader para leer del InputStream dado utilizando la codificación de
caracteres dada. Si el nombre de la codificación no se admite, se lanza una excepción Un
supportedEncoding Exception.
public OutputStreamWriter(OutputStream out)
Crea un OutputStreamWriter para escribir el OutputStream dado utilizando la codificación
de caracteres por defecto.
public OutputStreamWriter(OutputStream out, String codificacion)
throws UnsupportedEncodingException
Crea un InputStreamWriter para escribir en un OutputStream dado utilizando la codificación de caracteres dada. Si el nombre de la codificación no se admite, se lanza una
excepción UnsupportedEncodingException.
Los métodos read de InputStreamReader simplemente leen bytes de su InputStream
asociado y los convierten en caracteres utilizando la codificación adecuada para ese
stream. Similarmente, los métodos write de OutputStreamWriter toman los caracteres que
se les suministran, los convierten en bytes utilizando la codificación apropiada y los
escriben en su correspondiente OutputStream asociado.
En ambas clases, si se cierra el stream de conversión, se cierra también el stream de
Programación orientada a objetos en java
176
Unidad VIII. Flujos y archivos
bytes asociado. Esto no siempre tiene por qué ser deseable (como por ejemplo, al
convertir los streams estándar), por lo que es conveniente considerar cuidadosamente
cuándo se cierran los streams de conversión.
Ambas clases admiten también el método getEncoding, que devuelve una cadena de texto
que representa el nombre canónico de la codificación de caracteres que se utiliza en el
stream. o null si el stream ha sido cerrado.
Las clases FileReader y FileWriter son subclases de estos streams de conversión. Esto nos
ayuda en la lectura y escritura de archivos locales de forma consistente utilizando
Unicode, mediante la codificación local. Pero si la codificación local por defecto no es la
que necesitamos, debemos utilizar objetos InputStreamReader o OutputStreamWriter
explícitos.
No existen clases ReaderlnputStream ni WriterOutputStream para convertir streams de
caracteres en streams de bytes.
8.2.5 Recorrer
En una Lectura
El corrimiento de archivos se hace de línea en línea con ciclos, que mejor que un ejemplo
para mostrar como funciona;
Código 8.2.5. Recorrer un archivo.
El recorrimiento se hace con el ciclo while de línea en línea hasta encontrar el fin de
archivo.
En una Escritura
En este caso se utiliza un ciclo for para recorrer el archivo e insertarle 10 líneas al mismo.
Código 8.2.6. Recorrer un archivo para escritura.
Programación orientada a objetos en java
177
Unidad VIII. Flujos y archivos
8.3 Aplicaciones
Ejemplo 1:
Código 8.3.1. Lectura de un archivo de texto en java.
Ejemplo 2:
Código 8.3.2. Escritura de un archivo de texto en java.
Programación orientada a objetos en java
178
Unidad VIII. Flujos y archivos
Ejemplo 3:
Archivo: archivo.txt
El proceso de lectura de un archivo de texto es similar a la lectura desde el dispositivo
estándar. Se crea un objeto entrada de la clase FileReader en vez de InputStreamReader.
El final del archivo viene dado cuando la función read devuelve -1. El resto del código es
similar.
Código 8.3.3. Lectura de un archivo
Para mostrar el archivo de texto en la pantalla del monitor, se imprime el contenido del
objeto str de la clase StringBuffer.
System.out.println(str);
Una vez concluido el proceso de lectura, es conveniente cerrar el flujo de datos, esto se
realiza en una cláusula finally que siempre se llama independientemente de que se
produzcan o no errores en el proceso de lectura/escritura.
Programación orientada a objetos en java
179
Unidad VIII. Flujos y archivos
El código completo de este ejemplo es el siguiente:
Código 8.3.4. Lectura del archivo “archivo2.java” en pantalla.
Ahora se crea un código completo que genera un archivo copia del original, es el
siguiente:
Programación orientada a objetos en java
180
Unidad VIII. Flujos y archivos
Código 8.3.5. Crea una copia del archivo “archivo3.java”.
Ejemplo 4. El siguiente ejemplo, genera un archivo de prueba que contiene números
enteros aleatorios. Crea un archivo llamado prueba.dat.
Programación orientada a objetos en java
181
Unidad VIII. Flujos y archivos
Código 8.3.6 Genera un archivo de prueba *.dat y lo llena de números
enteros.
Ejemplo 5. La siguiente clase permite leer el archivo "prueba.dat" utilizando las clases
FileReader y BufferReader:
Código 8.3.7 Lee prueba.dat utilizando BufferReader y BufferReader.
Programación orientada a objetos en java
182
Unidad VIII. Flujos y archivos
8.4 Ejercicios propuestos
8.4.1 Crear una aplicación que lea de teclado una oración dada por el usuario y que ésta
se escriba en un archivo.
8.4.2 Crear una aplicación para mostrar directorios en una lista, que pida al usuario una
ruta absoluta y luego muestre todos los nombres de archivos que haya dentro de ese
directorio. Si alguno de los archivos es un directorio, debe imprimirse la palabra "dir"
después de su nombre.
8.4.3 Construir un directorio de amigos. Considérese que la información más relevante
para representar a un amigo es: nombre, teléfono, correo-e y fecha de cumpleaños.
Utilizar objetos serializables para escribir y leer de archivo.
8.4.4 Escribir un método en que se abra un flujo, RandomAccessFile, en modo lectura (“r”)
en el caso de que la operación lance una excepción abrir el archivo en modo
lectura/escritura(“rw”).
8.4.5 Escribir un método para copiar un archivo. El método entrá dos argumentos de tipo
cadena, el primero es el archivo original y el segundo es el archivo destino. Utilizar flujos
FileInputStream y FileOutPutStream.
8.4.6 Se tiene un archivo de caracteres de nombre “SALAS.DAT”. Escribir un programa
para crear el archivo “SALAS.BIN” con el contenido del primer archivo, pero en modo
binario.
8.4.7 Utilizar los argumentos del método main() para dar entrada a dos cadenas; la
primera representa una mascara. La segunda el nombre de un archivo de caracteres. El
programa tiene que localizar las veces que ocurre la mascara en los archivos.
8.4.8 El archivo “numeros.dat” contiene enteros positivos y negativos. Escribir un
programa que habrá un flujo DataInputStream para leer el archivo y determinar el número
de enteros negativos.
8.4.9 Escribir un programa que elimine todos los archivos con la extensión *.txt
directorio actual. Utilizar los métodos de la clase File.
del
8.4.10 Escribir un programa que escriba por pantallas las líneas de caracteres de un
archivo, numerando cada línea del mismo.
Programación orientada a objetos en java
183
Resumen
CONCLUSIONES
Como ya se vio en este libro de texto, Java es un lenguaje orientado a objetos
basado en C++ con atractivas características que lo convierten en uno de los más
usados actualmente. Además, Gracias a su simplicidad y claridad en el manejo de
conceptos orientados a objetos, Java ha crecido a tal magnitud que numerosas
tecnologías y compañías han enfocado sus esfuerzos hacia este lenguaje.
Tienes grandes ventajas:
•
•
•
•
•
•
•
•
•
•
Simple. Java es simple dado que abstrae la complejidad intrínseca de C++ como el
manejo de apuntadores y el reciclado de la memoria.
Orientado a objetos. Java permite el diseño de aplicaciones basadas en objetos
dado su mejor comprensión y definición en el diseño de interfaces y reusabilidad
de componentes.
Fácil uso en la red. Java facilita el acceso a la red por medio de TCP/IP con utilerías
simples e intuitivas para comunicar por HTTP o FTP, por ejemplo.
Robusto. Java pone énfasis en la detección de errores y bugs a temprana fase del
desarrollo, específicamente en la compilación, que encontrarlos en tiempo de
ejecución.
Seguro. Java está orientado a la red y sistemas distribuidos, por lo que refuerza la
seguridad en la transmisión por medios de comunicación por red.
Neutral arquitectura. Debido a que Java está orientado a la red donde están
involucrados diferentes CPU, diferentes sistemas operativos y arquitecturas, Java
crea programas con un formato especial solo ejecutables por el ambiente Java.
Portable. A diferencia de C++ donde no existe forma directa de migrar un
programa de una plataforma a otra, cualquier programa en Java puede ser
compilado y ejecutado en cualquier plataforma sin necesidad de modificar el
código.
Interpretado. Java crea programas en un formato especial conocido como
bytecodes. Este formato debe ser ejecutado por un intérprete dependiente de la
plataforma.
Multihilado. Java permite la creación de procesos internos conocidos como hilos
(threads) lo que permite la concurrencia de tareas y acceso a recursos.
Dinámico. El lenguaje Java puede evolucionar o mejorarse liberando versiones que
no impactan en los programas ya desarrollados por medio de la incrustación de
librerías.
En lo personal, creo que es un lenguaje con un enorme potencial y que en un
futuro, si no es que ya esta pasando, dominara claramente el mercado de la
programación.
En hora buena creo hice muy bien al seleccionar este proyecto, ya que aprendí
muchísimo elaborando este libro de texto, y además es muy gratificante saber que
todo lo aprendido servirá como herramienta de apoyo para la materia de POO
(Programación orientada a objetos).
Programación orientada a objetos en java
184
Anexo I. Introducción al lenguaje Java
ANEXO I. INTRODUCCIÓN AL LENGUAJE JAVA
Programación orientada a objetos en java
185
Anexo I. Introducción al lenguaje Java
ANEXO I. Introducción al Lenguaje Java
1.1 Introducción
Hoy en día la informática invade más campos de la vida cotidiana, estando el ciudadano
cada vez más familiarizado con términos del mundo informático, entre ellos, como los
lenguajes de programación. A cualquier persona que haya empleado alguna vez un
ordenador le resultará familiar alguno de estos nombres: C, Pascal, Cobol, Visual Basic,
Java, Fortran y a una persona ya más introducida en ese mundillo posiblemente haya oído
muchos otros: Oak, Prolog, Dbase, JavaScrip, Delphi, Simula, Smalltalk, Modula, Oberon,
Ada, BCPL 77, Common LISP, Scheme. En la actualidad se podrían recopilar del orden de
varios cientos de lenguajes de programación distintos, sino miles.
Cabe hacerse una pregunta: ¿Para qué tanto lenguaje de programación?. Toda esta
multitud de nombres puede confundir a cualquier no iniciado que haya decidido aprender
un lenguaje, quien tras ver las posibles alternativas no sabe cual escoger, al menos entre
los del primer grupo, que por ser más conocidos deben estar más extendidos.
El motivo de esta disparidad de lenguajes es que cada uno ha sido creado para una
determinada función, está especialmente diseñado para facilitar la programación de un
determinado tipo de problemas, para garantizar seguridad de las aplicaciones, para
obtener una mayor facilidad de programación, para conseguir un mayor aprovechamiento
de los recursos del ordenador... Estos objetivos son muchos de ellos excluyentes: el
adaptar un lenguaje a un tipo de problemas hará más complicado abordar mediante este
lenguaje la programación de otros problemas distintos de aquellos para los que fue
diseñado. El facilitar el aprendizaje al programador disminuye el rendimiento y
aprovechamiento de los recursos del ordenador por parte de las aplicaciones programadas
en este lenguaje.
1.2 Características de Java
Estas preguntas ayudan a ver para que tipo de problemas está pensado Java:
1.2.1 Simple
Es un lenguaje sencillo de aprender. Su sintaxis es la de C++ “simplificada”. Los creadores
de Java partieron de la sintaxis de C++ y trataron de eliminar de este todo lo que
resultase complicado o fuente de errores en este lenguaje.
77
Basic Combined Programming Language (Lenguaje de Programación Básico Combinado)
Programación orientada a objetos en java
186
Anexo I. Introducción al lenguaje Java
1.2.2 Orientado a Objetos
Posiblemente sea el lenguaje más orientado a objetos de todos los existentes; en Java
todo, a excepción de los tipos fundamentales de variables (int, char, long...) es un objeto.
1.2.3 Distribuido
Java está muy orientado al trabajo en red, soportando protocolos como TCP/IP, UDP,
HTTP y FTP. Por otro lado el uso de estos protocolos es bastante sencillo comparándolo
con otros lenguajes que los soportan.
1.2.4 Robusto
El compilador Java detecta muchos errores que otros compiladores solo detectarían en
tiempo de ejecución o incluso nunca. (ej: if(a=b) then ... el compilador Java no dejaría
compilar este código.
1.2.5 Seguro
Sobre todo un tipo de desarrollo: los Applet 78. Java garantiza que ningún Applet puede
escribir o leer de un disco o mandar información del usuario que accede a la página a
través de la red (por ejemplo, la dirección de correo electrónico). En general no permite
realizar cualquier acción que pudiera dañar la máquina o violar la intimidad del que visita
la página web.
1.2.6 Portable
En Java no hay aspectos dependientes de la implementación, todas las implementaciones
de Java siguen los mismos estándares en cuanto a tamaño y almacenamiento de los
datos. Esto no ocurre así en C++, por ejemplo. En éste un entero, por ejemplo, puede
tener un tamaño de 16, 32 o más bits, siendo la única limitación que el entero sea mayor
que un short y menor que un long int. Así mismo C++ bajo UNIX almacena los datos en
formato little endian, mientas que bajo Windows lo hace en big endian. Java lo hace
siempre en little endian 79 para evitar confusiones.
1.2.7 Arquitectura Neutral
Un applet es un componente de software que corre en el contexto de otro programa, por ejemplo
un navegador web.
79
El término “Endian” se refiere a la forma en que los números binarios de bytes múltiples son
guardados en la computadora.
78
Programación orientada a objetos en java
187
Anexo I. Introducción al lenguaje Java
El código generado por el compilador Java es independiente de la arquitectura: podría
ejecutarse en un entorno UNIX, Mac o Windows. El motivo de esto es que el que
realmente ejecuta el código generado por el compilador no es el procesador del ordenador
directamente, sino que este se ejecuta mediante una máquina virtual. Esto permite que
los Applets de una web pueda ejecutarlos cualquier máquina que se conecte a ella
independientemente de que sistema operativo emplee (siempre y cuando el ordenador en
cuestión tenga instalada una máquina virtual de Java).
1.2.8 Rendimiento medio
Actualmente la velocidad de procesado del código Java es semejante a la de C++, hay
ciertos pruebas estándares de comparación80 en las que Java gana a C++ y viceversa.
Esto es así gracias al uso de compiladores just in time, compiladores que traduce los
bytecodes de Java en código para una determinada CPU 81, que no precisa de la máquina
virtual para ser ejecutado, y guardan el resultado de dicha conversión, volviéndolo a
llamar en caso de volverlo a necesitar, con lo que se evita la sobrecarga de trabajo
asociada a la interpretación del bytecode.
No obstante por norma general el programa Java consume bastante más memoria que el
programa C++, ya que no sólo ha de cargar en memoria los recursos necesario para la
ejecución del programa, sino que además debe simular un sistema operativo y hardware
virtuales (la máquina virtual). Por otro lado la programación gráfica empleando las librerías
Swing es más lenta que el uso de componentes nativos en las interfaces de usuario.
En general en Java se ha sacrificado el rendimiento para facilitar la programación y sobre
todo para conseguir la característica de neutralidad arquitectural, si bien es cierto que los
avances en las máquinas virtuales remedian cada vez más estas decisiones de diseño.
1.2.9 Multithread
Soporta de modo nativo los threads 82, sin necesidad del uso de librerías específicas (como
es el caso de C++). Esto le permite además que cada Thread de una aplicación java
pueda correr en una CPU distinta, si la aplicación se ejecuta en una máquina que posee
varias CPU. Las aplicaciones de C++ no son capaces de distribuir, de modo transparente
para el programador, la carga entre varias CPU.
1.3 Java frente a los demás lenguajes
Java es un lenguaje relativamente moderno. Su primer uso en una “tarea seria” de
programación fue la construcción del navegador HotJava por parte de la empresa Sun en
mayo de 1995, y fue a principios de 1996 cuando Sun distribuye la primera versión de
80
Benchnarks.
Unidad de Proceso Central.
82
Hilos.
81
Programación orientada a objetos en java
188
Anexo I. Introducción al lenguaje Java
Java. Es esta corta edad lo que hace que Java esté más orientado al mundo web, que no
existía cuando, por ejemplo, C fue desarrollado. También es esto lo que ha hecho que
soporte de modo nativo (no mediante el uso de librerías, como C) los threads, siendo
posible aprovechar las ventajas de los sistemas multiprocesadores.
Las ventajas fundamentales de Java frente a otros lenguajes son el menor periodo de
aprendizaje por parte del programador, llegando a ser un programador productivo en
menos tiempo (sencillez) y siendo posible desarrollar aplicaciones más rápido que en otros
lenguajes (sencillez y robustez), lo cual se traduce en el mundo empresarial en un ahorro
de costos de desarrollo.
Sus cualidades de distribuido, seguro e independencia de la plataforma lo hacen ideal para
aplicaciones relacionadas con el mundo web; precisamente a esto es a lo que Java debe
su gran difusión y fama. El hecho de que sea independiente de la máquina y del sistema
operativo permite que distintas máquinas con distintos sistemas operativos se conecten a
una misma página web y ejecuten los mismos applets. Además la seguridad que garantiza
Java para los applets impiden que alguien trate de averiguar información sobre los
usuarios que se conectan a la página web o intente dañar sus máquinas.
En cuanto a su capacidad de soporte de threads y su capacidad de sacarle partido a
sistemas multiprocesador lo convierten en un lenguaje más “orientado hacia el futuro “.
Estas cualidades podrían dar pie a que algún día los rendimientos computacionales de
Java sean comparables con los de C++ y otros lenguajes que hoy son
computacionalmente más eficientes.
2 j2sdk, java 2 standard development kit
Distribuido por Sun 83, jdk. Dicho entorno de programación es suministrado por Sun de
forma gratuita, este se puede encontrar en la dirección web: http://Java.sun.com/j2se/.
Es de consenso que el entorno jdk no es el más adecuado para el desarrollo de
aplicaciones Java, debido a funcionar única y exclusivamente mediante comandos de
consola, ya que hoy en día la programación se suele ayudar de entornos visuales, como
JBuilder, JCreator o muchos otros, que facilitan enormemente la tarea. Sin embargo,
puede ser un entorno bastante útil para aprender el lenguaje, ya que aunque los entornos
visuales nos hagan mucho trabajo siempre es necesario ir al código para modificarlo y
obtener el comportamiento deseado, lo cual quiere decir que se necesita dominar el
lenguaje y es más fácil llegar a este dominio escribiendo códigos completos en un entorno
“hostil” que ayuda, que simplemente remodelando códigos ya generados por entornos
visuales.
83
Pagina Oficial de Java.
Programación orientada a objetos en java
189
Anexo I. Introducción al lenguaje Java
1.4 Como Compilar y Ejecutar Programas en Java
1.4.1 Javac
Es el comando compilador de Java. Su sintaxis es:
Javac ejemplo.Java
La entrada de este comando ha de ser necesariamente un archivo que contenga código
escrito en lenguaje Java y con extensión .Java. El comando nos creará un archivo .class
por cada clase que contenga el archivo Java.
Los archivos .class contienen código bytecode, el código que es interpretado por la
máquina virtual Java.
1.4.2 Java
Es el intérprete de Java. Permite ejecutar aplicaciones que previamente hayan sido
compiladas y transformadas en archivos .class. Su sintaxis es:
Java ejemplo
No es necesario aquí suministrar la extensión del archivo, ya que siempre ha de ser un
archivo .class.
1.4.3 Appletviewer
Se trata de un comando que verifica el comportamiento de un applet. La entrada del
comando ha de ser una página web que contenga una referencia al applet que se desea
probar. Susintaxis es:
Appletviewer supagina.html
El comando ignora todo el contenido de la página web que no sean applets y se limita a
ejecutarlos. Un ejemplo de página web “mínima” para poder probar un applet llamado
myapplet.class sería:
<HTML>
<TITLE>My Applet </TITLE>
<BODY>
<APPLET CODE=”myapplet.class” WIDTH=180 HEIGHT=180>
</APPLET>
</BODY>
</HTML>
Programación orientada a objetos en java
190
Anexo I. Introducción al lenguaje Java
Javadoc
Este útil comando permite generar documentación en formato html sobre el contenido de
archivos con extensión .Java. Su sintaxis es:
Javadoc ejemplo.Java
En la documentación generada por este comando se puede ver que métodos y
constructores posee una determinada clase, junto con comentarios sobre su uso, si posee
inner 84 classes, la versión y el autor de la clase....
1.5 Estructuras de Datos Básicas en Java
En este tema se tratarán las estructuras básicas de Java de datos, sus tipos y las
variables, operadores. Aquellos que estén familiarizados con C, o C++, no encontrarán
prácticamente nada nuevo en este tema, ya que, como se ha dicho en el primer tema,
Java hereda toda su sintaxis de C, pudiendo considerarse la sintaxis de Java una versión
simplificada de la de C. Sólo las operaciones con Strings pueden resultar un poco
novedosas.
1.5.1 Tipos de Datos
En Java toda variable declarada ha de tener su tipo, y además antes de poder emplearla
se ha de inicializar a un valor, si no el compilador se quejará y no generará los archivos
.class. Esto por ejemplo en C no es necesario, siendo fuente de muchos errores al
emplearse en operaciones variables que se olvidan de inicializar. A continuación se pasan
a describir los tipos de datos:
1.5.2 Enteros
Almacenan como su propio nombre indica números enteros, sin parte decimal. Cabe
destacar, como ya se indicó en el primer tema, que por razones de portabilidad todos los
datos en Java tienen el mismo tamaño y formato. En Java hay cuatro tipos de enteros:
84
Clases Embebidas.
Programación orientada a objetos en java
191
Anexo I. Introducción al lenguaje Java
1.5.3 Tipos de Datos Enteros en Java
Tipo
Int
Short
Long
Byte
Tamaño
(bytes)
Rango
4
-2147483648 a 2147483647
2
-32768 a 32767
8
1
-9.223.372.036.854.775.808 a 9.223.372.036.854.775.807
-128 a 127
1.5.4 Tipos de Datos Reales en Java
Almacenan número reales, es decir números con parte fraccionaria. Hay dos tipos:
Tipo
Tamaño (bytes)
Rango
4
+ 3.40282347E+38
8
+ 179769313486231570E+308
Float
Double
1.5.5 Caracteres
En Java hay un único tipo de carácter: char. Cada carácter en Java esta codificado en un
formato denominado Unicote 85, en este formato cada caracter ocupa dos bytes, frente a
la codificación en ASCII, donde cada caracter ocupaba un solo byte.
Unicode es una extensión de ASCII 86, ya que éste último al emplear un byte por caracter
solo daba acogida a 256 símbolos distintos. Para poder aceptar todos los alfabetos (chino,
japonés, ruso...) y una mayor cantidad de símbolos se creó el formato Unicode.
Es un estándar industrial cuyo objetivo es proporcionar el medio por el cual un texto en cualquier
forma o idioma puede ser codificado.
85
Programación orientada a objetos en java
192
Anexo I. Introducción al lenguaje Java
En Java al igual que en C se distingue la representación de los datos char frente a las
cadenas de caracteres. Los char van entre comillas simples: char ch = ‘a’, mientras que las
cadenas de caracteres usan comillas dobles.
1.5.6 Boolean
Se trata de un tipo de dato que solo puede tomar dos valores: true y false. Es un tipo de
dato bastante útil a la hora de realizar chequeos sobre condiciones. En C no hay un dato
equivalente y para suplir su ausencia muchas veces se emplean enteros con valor 1 si
“true” y 0 si “false”. Otros lenguajes como Pascal sí tiene este tipo de dato.
1.5.7 Variables
Al igual que C, Java requiere que se declaren los tipos de todas las variables empleadas.
La sintaxis de iniciación es la misma que C:
int i; Sin embargo, y a diferencia que en C, se requiere inicializar todas las variables antes
de usarlas, si no el compilador genera un error y aborta la compilación. Se puede
inicializar y asignar valor a una variable en una misma línea:
int i = 0;
Asignación e inicialización pueden hacerse en líneas diferentes:
int i ;
i = 0;
Es posible iniciar varias variables en una línea:
int i, j,k=10;
Después de cada línea de código, bien sea de iniciación o de código, al igual que en C va
un ;. En Java, al igual que en todo lenguaje de programación hay una serie de palabras
reservadas que no pueden ser empleadas como nombres de variables (if, int, char, else,
goto....); alguna de estas se emplean en la sintaxis del lenguaje, otras, como goto no se
emplean en la actualidad pero se han reservado por motivos de compatibilidad por si se
emplean en el futuro.
Los caracteres aceptados en el nombre de una variable son los comprendidos entre “A-Z”,
“az”, _, $ y cualquier carácter que sea una letra en algún idioma.
86
Acrónimo de American Standard Code for Information Interchange.
Programación orientada a objetos en java
193
Anexo I. Introducción al lenguaje Java
1.6 Entornos de Desarrollo de Java
El propósito de esta sección es informar al lector de algunas de los entornos de desarrollo
IDE 87 existentes para el lenguaje Java.
1.6.1 Bluej http://www.bluej.org/
Es el IDE que, sin duda, se recomienda al lector para que empiece a dar sus primeros
pasos en Java. Esta herramienta freeware ha sido diseñada para introducir al estudiante
en la programación orientada a objetos. Es un IDE “ligera”, posee la funcionalidad básica
de cualquier IDE: editor, compilador y depurador. Siempre visualiza el código del proyecto
en UML 88, mostrando las clases con las relaciones de herencia y dependencias entre ellas.
Posee ciertas capacidades para “jugar” con las clases permitiendo la creación de objetos,
así como “jugar” con ellos invocando sus métodos, viendo el valor que toman sus
variables… Estas cualidades carecen de valor para un programador experto, pero permiten
a un programador novato familiarizarse con los conceptos de objeto, método, variable,
herencia… a diferenciar entre objeto y clase… No sólo se recomienda esta IDE a los que
empiecen a trabajar con java por su orientación didáctica; se hace además porque se
considera que cualquier IDE “pesada”, no es apta para aprender a programar. Su elevada
Complejidad, si bien es fácilmente compensada con las opciones que ofrecen a un
programador veterano, no lo es en un programador novato, quien ya tiene bastante con
pelearse con el lenguaje para además tener que hacerlo con el IDE. Por otro lado los
asistentes y el elevado grado de automatización de algunas tareas en los IDE pesados
hacen que el programador novato haga cosas sin saber realmente lo que está haciendo,
con lo cual, si bien logra hacer pequeñas aplicaciones, su aprendizaje estará plagado de
lagunas.
Para un programador experto que domina las bases del lenguaje en unos días son más
que suficientes para sentirse cómodo en un nuevo IDE.
1.6.2 Jcreator http://www.jcreator.com/
Se trata de una IDE ligera, no posee, por ejemplo, capacidades para desarrollo de
aplicaciones de modo gráfico. Sin embargo es interesante ya que requiere máquinas poco
potentes para ejecutarse, un Pentium 2 a 300 con 64 megas de RAM sería más que
suficiente, mientras que las siguientes, e incluso BlueJ, requieren equipos bastante más
potentes.
No obstante, a diferencia de BlueJ este producto si es un IDE que puede ser empleado por
un programador profesional (BlueJ pierde todo interés más allá de la docencia), con lo
87
88
Ambientes de Desarrollo Integrado (Integrated Development Environment).
Lenguaje de Modelado Unificado.
Programación orientada a objetos en java
194
Anexo I. Introducción al lenguaje Java
cual los que empiecen directamente con ella podrán “aguantar” más que los que se
decidan por BlueJ.
Es un IDE comercial, con dos versiones:
JCreator : gratis.
JCreator Pro : Aproximadamente 69$ (licencia de estudiante).
1.6.3 Jbuilder
Http://www.borland.com/jbuilder/
Desde el punto de vista de algunos expertos esta es la mejor IDE para Java del mercado.
Requiere máquinas potentes, la última versión (llamada X por Borland) se arrastra
bastante con un equipo inferior a un Pentium III a 800 con 512 megas de RAM.
Posee capacidades de desarrollo visual de aplicaciones, así como múltiples asistentes y
está integrada con una gran cantidad de herramientas, unas Opensource 89(Ant, CVS,
Struts
Tomcat…) y otras propietarias (Borland Aplication Server, JDataStore, ClearCase, Visual
SouceSafe …).
Nuevamente es comercial, y los precios de las versiones no gratuitas son bastante
prohibitivos:
JBuilder X Persona: gratis
JBuilder X Developer: $
JBuilder X Enterprise : $
Existen versiones gratuitas de evaluación por 30 días de todos los productos.
1.6.4 Netbeans http://www.netbeans.org/
Ofrece una funcionalidad más limitada que JBuilder, y es bastante menos intuitivo de
manejar, en especial para los programadores novatos. Sin embargo es la herramienta
gratuita (Open Source) que más funcionalidad tiene. Permite el diseño de aplicaciones de
modo visual. Esta herramienta Open Source está respaldada por Sun Microsystems,
empresa que construye su IDE para java, Sun ONE Studio.
Si el aprendiz no puede permitirse una herramienta comercial, como JBuilder, y quiere
más de lo que da JCreator, esta es, la mejor alternativa en este momento.
1.6.5 Eclipse http://www.eclipse.org/
NetBeans es un proyecto de código abierto de gran éxito con una gran base de usuarios,
una comunidad en constante crecimiento, Sun MicroSystems fundó el proyecto de código
abierto NetBeans en junio 2000 y continúa siendo el patrocinador principal de los
proyectos.
A día de hoy hay disponibles dos productos: el NetBeans IDE y el NetBeans Plataform.
89
Código Abierto.
Programación orientada a objetos en java
195
Anexo I. Introducción al lenguaje Java
El NetBeans IDE es un entorno de desarrollo - una herramienta para programadores
pensada para escribir, compilar, depurar y ejecutar programas. Está escrito en Java - pero
puede servir para cualquier otro lenguaje de programación. Existe además un número
importante de módulos para extender el IDE NetBeans. El IDE NetBeans es un producto
libre y gratuito sin restricciones de uso.
También disponible está el NetBeans Platform; una base modular y extensible usada
como una estructura de integración para crear aplicaciones de escritorio grandes.
Empresas independientes asociadas, especializadas en desarrollo de software,
proporcionan extensiones adicionales que se integran fácilmente en la plataforma y que
pueden también utilizarse para desarrollar sus propias herramientas y soluciones.
Ambos productos son de código abierto y gratuito para el uso tanto comercial y como no
comercial. El código fuente está disponible para su reutilización de acuerdo con el
Desarrollo Cómun y Licencia de Distribución 90.
Es una IDE extensible en base a plugins 91. Esta filosofía, junto con la actividad que
muestra su comunidad convierten a esta herramienta en toda una promesa de futuro. Sin
embargo, desde el punto de vista del autor, al día de hoy es una herramienta menos
completa que NetBeans, no proporcionando por ejemplo capacidad para el desarrollo
visual de aplicaciones. Por otro lado hay ciertos puntos, como la instalación, que están un
poco descuidados, y su filosofía en base a plugins obliga al usuario a buscar y descargarse
varios plugins o resignarse a carecer de bastante funcionalidad.
No obstante esta herramienta posee algunas capacidades, como el refactoring, no
presentes en NetBeans en el momento de escribir estas líneas.
Además es más pedagógico “construir” su propia IDE en base a plugins que descargarse
un paquete donde ya se da todo hecho.
Common Development and Distribution License (CDDL).
Son pequeños programas que se instalan sobre los navegadores y que confieren posibilidades
multimedia al mismo. Identifican el archivo multimedia usando el código MIME: Multipurpose
Internet Mail Extensions (Extensiones de correo Internet Multipropósito).
90
91
Programación orientada a objetos en java
196
Anexo II. El entorno de desarrollo Eclipse
ANEXO II. EL ENTORNO DE DESARROLLO ECLIPSE
2.1. ¿Que es Eclipse?
Eclipse es una plataforma de desarrollo open source basada en Java. Es un desarrollo de
IBM cuyo código fuente fue puesto a disposición de los usuarios. En sı mismo Eclipse es
un marco y un conjunto de servicios para construir un entorno de desarrollo a partir de
componentes conectados (plug-in).
Hay plug-ins para el desarrollo de Java (JDT Java Development Tools) así como para el
desarrollo en C/C++, COBOL, etc. La versi´on instalada en el laboratorio incluye el plug-in
JDT.
2.2. Trabajando con Eclipse
Al ejecutar Eclipse aparece una ventana como la mostrada en la figura 17. Eclipse
contiene una serie de perspectivas. Cada perspectiva proporciona una serie de
funcionalidades para el desarrollo de un tipo específico de tarea. Por ejemplo la
perspectiva Java combina un conjunto de views que permiten ver información útil cuando
se esta escribiendo código fuente, mientras que la perspectiva de depuración contiene
vistas que muestran información útil para la depuración de los programas Java.
La barra de herramientas vertical (en la parte izquierda) muestra las perspectivas abiertas
y permite pulsando sobre ellas cambiar de una a otra. La perspectiva activa se muestra en
la barra del titulo en la parte superior de la ventana.
2.2.1. Creación de un proyecto
Eclipse permite organizar los ficheros en forma de proyecto. Para crear un proyecto Java
se procede del siguiente modo:
1. Seleccionando en el menú File − New − Project o pulsando con el botón derecho del
Ratón sobre la vista Navigator en la perspectiva Resource y seleccionando New − Project.
2. Aparece una ventana en la que se puede seleccionar el tipo de proyecto. En este caso
se pulsa sobre Java en la parte izquierda y Java project en la derecha. Pulsar sobre el
botón Next . Ver la figura 18
3. A continuación se piden los datos sobre el proyecto (nombre y ruta donde se
almacenarán los ficheros asociados al proyecto). Una vez introducidos se pulsa sobre
finish. Véase la figura 19.
4. Eclipse abre automáticamente la perspectiva Java cuando se crea un proyecto Java. Se
crea el directorio especificado con dos ficheros .project y .classpath que contienen
información sobre el proyecto.
Listado 1: Código generado utilizando el asistente
Programación orientada a objetos en java
197
Anexo II. El entorno de desarrollo Eclipse
/∗
∗ Created on “fecha”
∗
∗ To change the template for this generated f i l e go to
∗ Window>Preferences>Java>Code Generation>Code and Comments
_/
/_∗ Clase
∗ @author juan
∗
∗ Descripcion :
_/
public class HolaMundo {
public static void main( String [ ] args ) {}
Perspectiva Java contienen un directorio con el nombre del proyecto. Como se comento
anteriormente, se puede pasar de una perspectiva a otra pulsando sobre los botones de la
barra vertical izquierda.
5. Hay una perspectiva mas asociada con Java, se puede abrir del siguiente modo:
Window − Open perspective − Java browsing. En esta perspectiva aparecen vistas
correspondientes al proyecto, a paquetes, a clases e interfaces y a los miembros de estas.
2.2.2. Creando clases.
Las clases se pueden crear de dos formas diferentes:
Utilizando un asistente. Se pulsa con el botón derecho sobre el proyecto − New − Class.
Aparece una ventana como la que se muestra en la figura 20. Los campos interesan por
ahora son: el nombre de la clase, el modificador, y si se quiere que esta clase tenga un
método main(String[] args). Al pulsar sobre Finish (con los datos que se muestran en la
figura 21 se crea un fichero HolaMundo.java con el código mostrado en el listado 1 (no
será exactamente asi ya que yo he personalizado el comentario que aparece). Si se
explora el contenido del directorio c:\tmp\prac1 se vera que además del fichero
HolaMundo.java hay otro fichero HolaMundo.class, este fichero es el que contiene el
código compilado a partir de HolaMundo.java (Eclipse compila el proyecto cada vez que se
guarda).
Escribiendo directamente toda la clase: se pulsa con el botón derecho sobre el proyecto −
New − File . Se abre una ventana como la que se muestra en la figura 21 donde hay que
poner el nombre del fichero. Al pulsar sobre Finish se crea un fichero vació con el nombre
HolaMundo.java.
No se tiene una preferencia por alguno de los dos métodos expuestos. Aunque, como
recomendación, al principio es conveniente escribir toda la clase para saber lo que se esta
haciendo.
Programación orientada a objetos en java
198
Anexo II. El entorno de desarrollo Eclipse
El asistente simplemente a creado un esqueleto ahora falta completar el código. Se
añaden las líneas necesarias para completar el programa. El resultado se muestra en la
figura 22.
2.2.3. Ejecutando el programa
Los programas se pueden ejecutar dentro de Eclipse.
Con la perspectiva Java abierta, seleccionar en el menu: Run − Run...
En la ventana que se abre, pulsar 2 veces sobre Java Application . En el panel Main se
rellena la información tal y como aparece en la figura 23.
Puesto que en el ejemplo propuesto se necesitan argumentos se pulsa sobre el panel
Arguments y se pone el argumento que se va a pasar al programa. Un ejemplo se muestra
en la figura 24.
Una vez proporcionada la información necesaria (hay más paneles pero por ahora no es
necesario conocerlos) se pulsa sobre el botón Run.
Este programa simplemente muestra un mensaje por consola. La consola esta integrada
(es una vista más) dentro de Eclipse. Así tras ejecutar el programa, en la vista Consola se
vera lo que se muestra en la figura 24.
Cuando el programa no requiere ningún ajuste especial (por ejemplo, no se requiere el
paso de argumentos) se puede hacer de forma más rápida pulsando sobre Run − Run as
− Java Application .
Hay barras de tareas para el acceso rápido a algunas funciones (entre ellas ejecutar). La
figura 25 muestra algunas de ellas.
2.2.4. Depuración de programas.
Dentro del entorno de desarrollo de Eclipse se pueden depurar programas desarrollados
en Java. Window − Open perspective − Debug . Aparecen una serie de vistas similares a
las de la figura 26.
Una vez se ha abierto la perspectiva de depuración se puede parar la ejecución del
programa en una determinada línea (poniendo un breakpoint) e inspeccionar las variables
locales.
Para poner un breakpoint, en la vista donde se encuentra el código fuente se seleccionas
la línea donde se quiere que se detenga la ejecución y se selecciona en el menu Run −
Add/remove Breakpoint . Se verá que se muestra un punto azul en la parte izquierda de la
línea. Ahora ya se puede lanzar el depurador.
Se selecciona en el menú Run − Debug . La ejecución del programa se detiene en el
primer breakpoint. Una vez el programa esta detenido, en una de las vistas se puede ver
el valor de las variables o ver los breakpoints que se ha definido. En la figura 27 se
Programación orientada a objetos en java
199
Anexo II. El entorno de desarrollo Eclipse
muestra el programa detenido en una línea y se muestra la vista Variables con el
contenido de una variable local.
Una vez inspeccionado el código donde esta el problema se puede optar por ejecutar el
programa hasta que termine ( Run − Resume ) o terminar el programa inmediatamente
(Run − Terminate )
2.2.5. Otras herramientas interesantes.
El editor de Java ofrece correcciones a problemas encontrados mientras se escribe el
código y tras compilar. El editor muestra que existen propuestas para la corrección de un
problema o aviso mediante una bombilla visible en la parte izquierda del editor. Si se pulsa
con el botón izquierdo sobre esta bombilla (o también mediante ( Edit − Quick Fix ) se
muestran las propuestas para el problema en la posición del cursor.
Si se desean importar recursos a un proyecto se puede realizar del siguiente modo: en la
vista Navigator se pulsa sobre el botón derecho y aparece un menú, se selecciona Import
y aparece una ventana desde la que se puede seleccionar el directorio donde están los
recursos y cuales se desean incorporar al proyecto.
Desde un proyecto se pueden exportar todos o algunos de los ficheros que lo conforman.
Para ello en la vista Navigator se pulsa sobre el botón derecho y aparece un menú, se
selecciona Export y aparece una ventana en la que podemos indicar como se va a exportar
(un fichero zip, tal cual aparecen en el proyecto, ...). La siguiente ventana sirve para
seleccionar los ficheros que se desean exportar y a donde.
Si se coloca el ratón sobre un método (sin pulsar) se muestra la declaración del método
(que devuelve y que parámetros acepta). Si se coloca el ratón (sin pulsar) sobre una
variable aparece información sobre el tipo de la variable. Al escribir código se puede pulsar
Ctrl + espacio y aparece un menú con posibles formas de finalizar la sentencia que se esta
escribiendo. Un ejemplo se muestra en la figura 28.
Figura 17: Primera pantalla de Eclipse
Programación orientada a objetos en java
200
Anexo II. El entorno de desarrollo Eclipse
Figura 18: Selección del tipo de proyecto en Eclipse
Figura 19: Datos sobre el proyecto en Eclipse
Programación orientada a objetos en java
201
Anexo II. El entorno de desarrollo Eclipse
Figura 20: Creación de una clase en Eclipse
Figura 21: Creación de un fichero vació en Eclipse.
Programación orientada a objetos en java
202
Anexo II. El entorno de desarrollo Eclipse
Figura 22: La perspectiva Java con las vistas mostrando una clase en Eclipse
Figura 23: Configuración para ejecutar la aplicación: proyecto y clase con el main en Eclipse.
Programación orientada a objetos en java
203
Anexo II. El entorno de desarrollo Eclipse
Figura 24: Argumentos para enviar al programa y argumentos para enviar a la Maquina Virtual en
Eclipse
Figura 25: Consola con el resultado de la ejecución en Eclipse.
Programación orientada a objetos en java
204
Anexo II. El entorno de desarrollo Eclipse
Figura 26: Barra de Herramientas de Eclipse.
Figura 27: La perspectiva debug en Eclipse.
Programación orientada a objetos en java
205
Anexo II. El entorno de desarrollo Eclipse
Figura 28: La perspectiva debug en acción en Elipse.
Figura 29: Asistente de código (pulsando Ctrl + espacio) en Eclipse.
Programación orientada a objetos en java
206
Referencias bibliográficas
BIBLIOGRAFIA
1. Taylor David.
Object Orient informations systems, planning and implementations.
Ed. Ed. Wiley, Canada, 1992.
2. Larman Craig.
UML y patrones introducción al análisis y diseño orientado a objetos.
Ed. Pretince Hall, México, 1999.
3. Winblad, Ann L. Edwards, Samuel R.
Software orientado a objetos.
Ed. Addison. Wesley/ Díaz Santos USA, 1993.
4. Deitel & Deitel.
Java how to program.
Ed. Prentice Hall.
5. Fco. Javier Ceballos.
Java 2 Curso de Programación.
Ed. Alfaomega.
6. Agustín Froufe.
Java 2 Manual de usuario y tutorial.
Ed. Alfaomega.
7. Laura Lemay, Rogers Cadenhead.
Aprendiendo JAVA 2 en 21 días.
Ed. Prentice Hall.
8. Herbert Schildt.
Fundamentos de Programación en Java 2.
Ed. McGrawHil.
9. J Deitel y Deitel.
Como programar en Java.
Ed. Prentice Hall.
10. Stephen R. Davis.
Aprenda Java Ya.
Ed. McGrawHill.
11. Kris Jamsa Ph D..
¡Java Ahora!
Ed. McGrawHill..
12. Ken Arnold, James Gosling, David colmes
Programación orientada a objetos en java
207
Referencias bibliográficas
“El Lenguaje de Programación Java”
Tercera Edción
Pearson Educación, Madrid.
13. Abraham Otero
Java 2
http://www.javahispano.org/licencias/
14. Javier García de Jalón,José Ignacio Rodríguez,Iñigo Mingo,Aitor Imaz,Alfonso
Brazales, Alberto Larzabal, Jesús Calleja,Jon García
Aprenda Java Como si Fuera en Primero
Editada por Javier García de Jalón ([email protected] y [email protected])
15. Philip Heller, Simon Roberts
Complete Java® 2 Certification: Study Guide
Fifth Edition
16. La Biblia del Java 2 – Español
Anaya Multimedia
16. http:// www.javasoft.com
17. http:// www.javaworld.com
18. http:// www.prenhall.com/deitel
19. http://www.javahispano.org/
20. http://www.java.net/
Programación orientada a objetos en java
208