UNIVERSIDAD DE ORIENTE
NÚCLEO DE ANZOÁTEGUI
ESCUELA DE INGENIERÍA Y CIENCIAS APLICADAS
DEPARTAMENTO DE COMPUTACIÓN Y SITEMAS
GUIA DIDÁCTICA PARA LA ASIGNATURA OBJETOS Y
ABSTRACCIÓN DE DATOS, DICTADA A LOS ESTUDIANTES DE ING. EN
COMPUTACIÓN Y DE ING. DE SISTEMAS, EN LA UNIVERSIDAD DE
ORIENTE
Por:
Prof. Gabriela María Veracierta Tovar
Trabajo Ascenso presentado como requisito parcial para
optar a la categoría de Profesor Asistente
Barcelona, Mayo de 2012
RESUMEN
La asignatura Objetos y Abstracción de Datos es muy importante, base
fundamental en el área de desarrollo de software, usando el paradigma
orientado a objetos que es uno de los más usados actualmente; a los
estudiantes se les dificulta investigar en bibliografías bien sea por la dificultad
de adquirir libros actualizados, encontrarlos en la sala de lectura del
departamento y en la biblioteca; ó porque en internet no encuentran
información adecuada o es expuesta de una forma entendible para
principiantes, por tal motivo se desarrollo una guía didáctica con la
información necesaria para que el estudiante pueda comprender de una
manera precisa todo el contenido de la asignatura; y de esta forma poder
consultarla en cualquier momento y disipar dudas referente a un tema
perteneciente a las unidades, con un lenguaje comprensible para nivel de
conocimiento; también pueden consultarla antes de clases, o simplemente
repasar el contenido discutido.
DEDICATORIA
A mi Dios, como todo cuanto hago en mi vida es ptá dedicado a él.
A mis Padres, todos mis éxitos es por y para ellos.
A mis hermanas, que las amo; y son fuente de inspiración
A mis colegas.
A mis estudiantes, para que se le facilite obtener el conocimiento más
facilmente
AGRADECIMIENTOS
A Dios por TODO cuanto hay en mi vida.
A mis Padres Dora y Alcides, por siempre estar para mí.
A mi hermana querida Aracelis, por siempre estar! muack.
A mis amigos y colegas, por ser fuente de inspiración y ejemplo de
lucha.
A mis profesores que por siempre lo serán, gracias por guiarme.
Al hermano que me regalo la vida Reinaldo Pastrana, por sus sabios
consejos.
TABLA DE CONTENIDO
Pág.
TABLA DE CONTENIDO
TABLA DE CONTENIDO
TABLA DE CONTENIDO
TABLA DE CONTENIDO
TABLA DE FIGURAS
Pág.
TABLA DE FIGURAS
TABLA DE FIGURAS
TABLA DE FIGURAS
ÍNDICE DE TABLAS
Pág
.
INTRODUCCIÓN
La asignatura Objetos y Abstracción de Datos código 0722123, dictada
a los estudiantes de Ingeniería de Sistemas y en Computación, en el cuarto
semestre de dichas carreras, pertenecientes al Departamento de
Computación y Sistema, adscrito a la Escuela de Ingeniería y Ciencias
Aplicadas de la Universidad de Oriente; Núcleo de Anzoátegui; es una
asignatura base para su formación profesional debido a que guía sobre el
paradigma de Programación Orientada a Objetos a un nivel más avanzado
que en la asignatura anterior que lleva por nombre Programación Orientada a
Objetos; conocimientos que le facilitarán a realizar proyectos en las
asignaturas mas avanzadas, fortaleciendo así a un profesional con aptitudes
competentes para las exigencias actuales en el campo laboral.
Los temas abarcados en ésta asignatura son difícilmente encontrados
en una sola bibliografía, aunado a esto, las bibliografías son de difícil acceso,
tanto en librerías de la zona como en bibliotecas y sala de lectura, de la
Universidad.
Con una guía didáctica para la asignatura Objetos y Abstracción de
Datos que abarque las siete unidades que esta comprende, le brindaría la
oportunidad a los estudiantes de tener fácil acceso a la información, bien sea
para consultar un tema en especifico en el cual tengan dudas, o leer antes de
la clase algún tema para obtener conocimientos previos, y de esta forma
facilitar su comprensión. Esta guía la tendrán cada uno de los estudiantes de
la asignatura, que pueden llevarla a donde vayan de esta forma no estar
TABLA DE FIGURAS
dentro del recinto universitario para consultarla, no tendrá restricciones de
horarios, de lugar donde se encuentren, entre otros.
CAPÍTULO I: EL PROBLEMA
1.1 Planteamiento del Problema
Desde el año 2005 se hizo un cambio de pensum en las carreras de
Ingeniería en Computación e Ingeniería de Sistemas, como medida para
formar profesionales actualizados en la evolución de las ciencias
computacionales; y de esta forma capacitarlos adecuadamente a las
exigencias actuales en la sociedad, con respecto a sus areas de trabajo.
En esta reforma curricular, se introdujeron varias asignaturas y se
modificaron otras, con el fin de llevar a cabo el propósito de actualización;
entre ellas se creo la asignatura Objetos y Abstracción de Datos dictada en el
cuarto semestre para ambas carreras, esta asignatura es la segunda en la
rama de programación, la primera es Programación Orientada a Objetos,
donde el estudiante aprende los conceptos básicos de programar, aunado a
la lógica de desarrollar algoritmos para una tarea especifica.
Objetos y Abstracción de Datos es una asignatura muy importante, es
base fundamental en la formación de Ingenieros en computación e
Ingenieros de Sistemas, para desarrollar software de alta calidad, debido a
que el paradigma orientado a objetos es unos de los más usados
actualmente; y en esta asignatura se profundiza en este paradigma
Para esta asignatura cuando los estudiantes investigan se encuentran
con información muy amplia y variada, tanto en bibliografías físicas como en
internet; en las bibliografías no siempre se abarca todas las unidades que la
conforman, se les dificulta adquirir libros actualizados, en la sala de lectura
del departamento y en la biblioteca, también en las librerías de la zona; en
internet no toda la información que esta es veraz o es expuesta de una forma
entendible para principiantes, por tal motivo se plantea desarrollar una guía
didáctica con la información necesaria para que el estudiante pueda
comprender de una manera precisa todo el contenido de la asignatura; y de
esta forma poder consultarla en cualquier momento y disipar dudas referente
a un tema perteneciente a las unidades.
1.2 Objetivos
1.2.1 Objetivo General
Elaborar una guía instruccional que abarque todas las unidades
de la asignatura Objetos y Abstracción de Datos, dictada en el
departamento de Computación y sistemas de la Escuela de
Ingeniería y Cs. Aplicadas de la Universidad de Oriente.
1.2.2 Objetivos Específicos
Revisar todo el contenido de la asignatura
Revisar bibliografías que contengan definiciones para los
conceptos relacionados con los temas de la asignatura
Redactar conceptos ejemplificados para los temas, con
ejemplos claros.
CAPÍTULO II: MARCO TEÓRICO
2.1 Paquete Instruccional:
Según Lobo N., y Fallas V. En 2008. Un paquete Instruccional es el
conjunto de materiales que se ofrecen al estudiante como instrumentos
básicos para el logro de su aprendizaje independiente. Constituye el principal
vehículo para que el estudiante pueda desarrollar el autoaprendizaje y la
autoevaluación, con tal de llevar a cabo el proceso de educación a distancia.
Normalmente, lo conforman las guias de estudio, las unidades didácticas y
otros materiales complementarios, como artículos, revistas, antologías,
etcétera; que mantienen actualizado el tema de estudio abordado.
2.2 Guia de estudio:
Según Lobo N., y Fallas V. En 2008. Una Guia de estudio, concebida
como un proyecto integral de trabajo, orientado de tutores y estudiantes,
debe contener todo lo relacionado con una unidad organizativa (asignatura,
módulo, taller, laboratorio, etcétera), tomando un marco de referencia el
contexto en el que se ubica (por ejemplo, un plan de estudio). Asimismo,
tiene como finalidad encaminar al alumno en el conocimiento de los paquetes
instructivos de apoyo de cada asignatura.
2.3 Unidad Didactica:
Según Lobo N., y Fallas V. En 2008. Una Unidad didáctica es el
material impreso básico que desarrollla los contenidos fundamentales de
cada asignatura. Se trata de un texto con estructura metodológica
especialmente diseñada para facilitar el autoaprendizaje del estudiante, de
manera individualizada. La organización y presentación de los contenidos,
así como los elementos didácticos, cumplen funciones específicas de
orientación para que el alumno aprenda a aprender.
2.4 Guia didáctica:
orienta el estudio, acercando a los procesos cognitivos del alumno el material
Para Mercer
.
Para
trabajo del alumno y su objketivo es recoger todas las orientaciones
necesarias que le permitan al estudiante integrar los elementos didácticos
Para Aguilar, R. en 2006. La guía didácticaes el material educativo que
deja de ser auxiliar, para convertirse en herramienta valiosa de motivación y
apoyo; pieza clave para el desarrollo del proceso enseñanza a distancia,
porque promueve el aprendizaje autónomo al aproximar el material de
estudio al alumno (texto convencional y otras fuentes de información), a
través de diversos recursos didácticos (explicaciones, ejemplos, comentarios,
esquemas y otras acciones similares a la que realiza el profesor en clase).
De ahí la necesidad de que la Guía Didáctica, impresa o en formato
digital, se
avanzar con mayor seguridad en el aprendizaje autónomo.
2.4.1 FUNCIONES BÁSICAS DE LA GUÍA DIDÁCTICA
La Guía Didáctica cumple diversas funciones, que van desde
sugerencias para abordar el texto básico, hasta acompañar al alumno a
distancia en su estudio en soledad. Cuatro son los ámbitos en los que se
podría agrupar las diferentes funciones:
Función motivadora:
Despierta el interés por la asignatura y mantiene la
atención durante el proceso de auto estudio.
Motiva y acompaña al estudiante través de una
Función facilitadora de la comprensión y activadora del
aprendizaje:
Propone metas claras que orientan el estudio de los
alumnos.
Organiza y estructura la información del texto básico.
Vincula el texto básico con los demás materiales
educativos seleccionados para el desarrollo de la
asignatura.
Completa y profundiza la información del texto básico.
Sugiere técnicas de trabajo intelectual que faciliten la
comprensión del texto y contribuyan a un estudio eficaz
(leer, subrayar, elaborar esquemas, desarrollar
preguntas que
1999).
Sugiere distintas actividades y ejercicios, en un esfuerzo
por atender los distintos estilos de aprendizaje.
Aclara dudas que previsiblemente pudieran obstaculizar el
progreso en el aprendizaje.
l cuanto va
aprendiendo, en un permanente ejercicio activo de
Especifica estrategias de trabajo para que el alumno
pueda realizar sus evaluaciones a distancia.
Función de orientación y diálogo:
Fomenta la capacidad de organización y estudio
sistemático.
Promueve la interacción con los materiales y compañeros.
Anima a comunicarse con el profesor-tutor.
Ofrece sugerencias oportunas para posibilitar el
aprendizaje independiente.
Función evaluadora:
Activa los conocimientos previos relevantes, para
despertar el interés e implicar a los estudiantes. (Martínez
Mediano, 1998: p.107)
Propone ejercicios recomendados como un mecanismo de
evaluación continua y formativa.
Presenta ejercicios de autocomprobación del aprendizaje
(autoevaluaciones), para que el alumno controle sus
progresos, descubra vacíos posibles y se motive a superar
las deficiencias mediante el estudio.
Realimenta constantemente al alumno, a fin de provocar
una reflexión sobre su propio aprendizaje.
Especifica los trabajos de evaluación a distancia.
2.4.2 ESTRUCTURA DE LA GUÍA DIDÁCTICA
Cuando se ha elegido trabajar con textos convencionales o de mercado,
como es nuestro caso, es indispensable elaborar Guías Didácticas muy
completas, que potencien las bondades y compensen los vacíos del texto
básico; para lo cual hemos optado por una Guía Didáctica que contemple los
apartados siguientes:
1. Datos informativos.
2. Índice.
3. Introducción.
4. Objetivos generales.
5. Contenidos.
6. Bibliografía.
7. Orientaciones Generales.
8. Orientaciones específicas para el desarrollo de cada unidad.
conducir a la comprensión de los
contenidos de la asignatura.
9. Soluciones a los ejercicios de autoevaluación.
10. Glosario.
11. Anexos.
12. Evaluaciones a distancia.
CAPÍTULO III: MARCO METODOLÓGICO
3.1 Nivel de Investigación
Según Arias, F. en 1999. El nivel de investigación se refiere al grado de
profundidad con que se aborda un objeto o fenómeno. Aquí se indicará si se
trata de una investigación exploratoria, descriptiva o explicativa. En
cualquiera de los casos es recomendable justificar el nivel adoptado.
Según el nivel, la investigación se clasifica en:
Investigación Exploratoria: es aquella que se efectúa sobre un
tema u objeto poco conocido o estudiado, por lo que sus
resultados constituyen una visión aproximada de dicho objeto.
Investigación Descriptiva: consiste en la caracterización de un
hecho, fenómeno o supo con establecer su estructura o
comportamiento.
Investigación Explicativa: se encarga de buscar el por qué de los
hechos mediante el establecimiento de relaciones causa-efecto.
Según las definiciones dadas; esta investigación es descriptiva; ya que
se detallaran todas y cada unas de la unidades de estudio en la asignatura
Objetos y abstracción de datos.
3.2 Diseño de Investigación
El diseño de investigación es la estrategia que adopta el investigador
para responder al problema planteado.
En atención al diseño, la investigación se clasifica en:
Investigación Documental: es aquella que se basa en la
obtención y análisis de datos provenientes de materiales
impresos u otros tipos de documentos.
Investigación de Campo: consiste en la recolección de datos
directamente de la realidad donde ocurren los hechos, sin
manipular o controlar variable alguna.
Investigación Experimental: proceso que consiste en someter a
un objeto o grupo de individuos a determinadas condiciones o
estímulos (variable independiente), para observar los efectos que
se producen (variable dependiente).
Según las definiciones anteriores, esta investigación según su diseño
es documental, puesto que se realizara una consulta bibliográfica para
desarrollar la guía abarcando las unidades de la asignatura.
CAPÍTULO IV: REPASO DE CONCEPTOS
FUNDAMENTALES DE ALGORITMOS Y LA
PROGRAMACIÓN, BASADA EN EL PARADIGMA
ORIENTADO A OBJETOS
4.1. Objetivos de la Unidad
Definir con sus propias palabras la programación orientada a
objetos según los conceptos y características discutidas.
Identificar elementos básicos de la programación orientada a
objetos en la vida cotidiana, con un buen margen de precisión.
4.2. Contenido de la Unidad
Repaso del concepto de algoritmo.
Definición de programación.
Definición de paradigma.
Tipos de paradigma.
Definición programación orientada a objetos.
Definición de elementos básicos de la programación orientada a
objetos.
4.2.1. Repaso del concepto de algoritmo
Algoritmo: una secuencia de pasos finitos, definidos, que permiten
hallar la solución genérica de un problema. Dado un estado inicial y una
entrada, a través de pasos sucesivos y bien definidos se llega a un estado
final, obteniendo una solución. Los algoritmos son objeto de estudio de la
algoritmia [Brassard, Gilles; Bratley, Paul (1997). Fundamentos de
Algoritmia. Madrid: PRENTICE HALL]
Un algoritmo se puede llevar a cualquier lenguaje de programación
Repetitividad, solución genérica de un problema.
Pasos bien ordenados.
Debe ser finito, tener un inicio y un fin.
Los pasos deben ser precisos, no ambiguos.
Deben ser independientes de plataformas computacionales, y
lenguajes de programación.
Eficiencia (espacial, temporal)
Diagramas de flujos: usando figuras que tienen un significado
para procesos, entradas y salidas de datos por diferentes
dispositivos, unidos por flechas que dan el sentido a los pasos
involucrados. Poco usado actualmente.
Pseudocodigo: un lenguaje que se asemeja a un lenguaje de
programación y al lenguaje natural. Es casi un código para
desarrollar un algoritmo, pero se debe manejar las palabras
representan cada sentencia.
Lenguaje Natural: es el lenguaje con el cual nos comunicamos los
seres humanos. No muy recomendable porque se puede tornar
muy largo con la descripción, o poco entendible.
Ejemplos:
Según las características, antes mencionadas podrá ser un manual
de usuario de un reproductor de música un algoritmo? O una receta de
cocina?
La respuesta es no, porque en un manual de usuario los pasos que
se dictan no necesariamente tienen que seguir ese orden para tener un
éxito.
La receta de cocina tampoco es un algoritmo, porque una
pizca de sal o pimienta al gusto no es para nada precisa.
En un algoritmo se hace uso de:
Variables: un nombre simbólico que identifica un determinado
espacio de memoria donde es almacenado un valor que puede
cambiar.
Constantes: un nombre simbólico de un espacio de memoria que
almacena un dato que no varia durante el algoritmo.
Operadores: símbolos que representan una operación, ya sea
aritmética, relacional, lógica, de asignación.
Bloques: son espacios delimitados que hacen tareas específicas.
Ejemplo llaves, o palabras que indiquen el inicio y fin del bloque.
Ámbito: es el ciclo de vida de un elemento, Por ejemplo una
variable.
Estructuras de control: son usadas para condicionar la secuencia
que debe seguir el algoritmo, si según un valor(es) el algoritmo
debe hacer una serie de pasos entonces se utilizan las sentencias
selectivas: SI-SINO, SELECCIÓN-CASO.
Estructuras repetitivas: su uso es para que una serie de pasos se
repitan mientras una(s) expresión booleana(es) sean verdaderas:
MIENTRAS, HACER-MIENTRAS, PARA.
Entrada y salida: para interactuar con datos suministrados desde
fuera del algoritmo es la entrada, y la información que se genera es
la salida.
En el siguiente algoritmo se resuelve el problema de verificar si un
numero n, es ó no primo.
En pseudocódigo:
Observe la Figura 4.1, donde se muestra un algoritmo enxpresado en
pseudocódigo
En Diagrama de flujo de datos:
Obseve en la Figura 4.2, el algoritmo para determinar si un número es
primo o no, expresado en diagrama de flujo
1- Inicio_Algoritmo
2- Contador , n : entero;
3- Contador 0 ; #Asignar 0 a una variable Contador.
4- Leer ( n ) ; # el valor del número y asignárselo a la variable n.
5- Para c 2 hasta n - 1 hacer
6- Inicio_Para
7- Si residuo de n/c = 0 entonces
8- Inicio_Si
9- Contador Contador + 1 ;
10- Fin_Si
11- Fin_Para
12- Si contador <> 0 entonces
13- Inicio_Si
14- Escribir
15- Sino
16- Escribir
17- Fin_Si
Fin_algoritmo
Figura 4.1. Algoritmo en pseudocódigo, para determinar si un número es primo o no.
Fuente: Propia
4.2.2. Definición de programación
Programa: un algoritmo traducido a un lenguaje de programación,
que generalmente tiene una entrada de datos que es necesario para
realizar un(os) proceso(s) y generar una salida como respuesta.
Lenguaje de Programación: Es un lenguaje artificial que puede ser
usado para controlar el comportamiento de una máquina, especialmente
una computadora. Estos se componen de un conjunto de reglas
sintácticas y semánticas que permiten expresar instrucciones que luego
serán interpretadas.
Inicio
Contador 0
N
C 0
R
Si Si
no si
C<N C=0
si no
R residuo de N / C
no
Si
Fin
R=0
si
C C+1
Figura 4.2. Algoritmo en diagrama de flujo, para determinar si un número es primo o
no.
Fuente: Propia
Clasificación de Lenguajes de programación: Existen tres (3) tipos
de lenguajes
De máquina. Cuyas ordenes están compuestas por ceros y unos
interpretación por parte del usuario. Es el lenguaje que interpreta
de modo directo la UCP y sus instrucciones están basadas en
BITS. Este lenguaje no requiere de traductor.
Ej. 0011010101111001 -> Instrucción 1
1111001100001010 -> Instrucción 2
De bajo nivel. Ya que el lenguaje de máquina es de muy difícil
comprensión, los fabricantes de microprocesadores han definido
lenguajes ensambladores que traducen las órdenes dadas por el
usuario a órdenes que puedan ser ejecutadas por la máquina
(lenguaje de máquina). Estas están basadas en etiquetas
nemónicas o simplemente nemónicos.
Ej. Mov A,1C -> Instrucción 1
Add A,B -> Instrucción 2
De alto nivel. Estos lenguajes permiten escribir programas de una
manera semejante a como nos expresamos en lenguaje natural,
con la salvedad de que generalmente las instrucciones están
definidas en Ingles.
Ej. Lenguaje C
Lenguaje Pascal
Lenguaje Java
Estructura de un programa, depende del lenguaje en que se
desarrolle, sin embargo en la mayoría de los lenguajes un programa tiene
la siguiente estructura:
Encabezado o Cabecera: En esta sección, se hace el llamado a
las librerías, o paquetes, sean propias del lenguaje utilizado, o
realizadas por programadores con anterioridad; estas librerías o
paquetes contienen funciones o clases que se necesitaran para
desarrollar el nuevo programa; por ejemplo:
include < nombre_de_la_libreria . h >
Lenguaje C/C++
import nombre_del Paquete . nombre_de_la_clase;
Lenguaje Java:
Inicio: todo programa tiene un inicio, al igual que los algoritmos;
éste inicio puede ser con una palabra que lo represente, o con una
llave de apertura.
Cuerpo: es esta sección van las instrucciones que conforman el
programa.
Fin: al igual que los algoritmos, un programa tiene un fin; partiendo
que todo lo que empieza finaliza, si se tiene un inicio se debe tener
un fin, éste depende del el lenguaje, es representado por una
palabra o una llave de finalización.
Lenguajes tipificados: son aquellos, donde las variables adoptan
un tipo, con el rango de valores que pueden almacenar.
Lenguajes no tipificados: son aquellos que no restringen el rango
de valores que puede tomar una variable.
Para los programas desarrollados en lenguajes de
programación tipificados se deben manejar los siguientes términos.
Datos: Representación formal de hechos, conceptos o
instrucciones adecuada para su comunicación, interpretación y
procesamiento por seres humanos o medios automáticos.
Tipos de datos: Especificación de un dominio (rango de valores) y
de un conjunto válido de operaciones a los que normalmente los
traductores asocian un esquema de representación interna propio,
en memoria.
Clasificación de los tipos de datos:
En función de quien los define.
Tipos de datos primitivos (definidos por el lenguaje de
programación usado, no se construyen a partir de
otros tipos y son entidades únicas).
Tipos de datos definidos por el usuario.
En función de su representación interna
Tipos de datos escalares o simples.
Tipos de datos estructurados.
Programa: Una serie de instrucciones que le indican al
computador la tarea que debe llevar a cabo para poder lograr un
objetivo o solucionar un problema, estas instrucciones deben estar
expresadas en un lenguaje que el computador pueda traducir a su
lenguaje de máquina y así ejecutar las instrucciones dadas. Es una
especie de algoritmo escrito en un lenguaje entendido por el
computador.
Programación: Es la acción de realizar un programa. es
automatizar y definir una serie de procesos para resolver un
problema y obtener un resultado final. Es el proceso de analizar,
escribir y probar, depurar y mantener un código programado.
4.2.3. Definición de paradigma
El concepto paradigma procede del griego paradeigma, que significa
ejemplo modelo
definir su uso en un cierto contexto) y a la retórica (para referirse a una
para definir a un modelo o patrón en cualquier disciplina científica o
contexto epistemológico.
El filósofo y científico estadounidense Thomas Kuhn fue el
encargado de actualizar el término y darle el significado contemporáneo,
al adaptarlo para referirse al conjunto de prácticas que defines una
disciplina científica durante un período específico de tiempo.
De esta forma, un paradigma científico establece aquello que se
debe observar; el tipo de interrogante que hay que formular para hallar las
respuestas en relación al objetivo; cómo deben estructurarse dicho
interrogantes; y cómo deben interpretarse los resultados de la
investigación científica.
Paradigmas de programación: Un paradigma de programación es un
modelo básico de diseño y desarrollo de programas, que permite producir
programas con unas directrices específicas, tales como: estructura
modular, fuerte cohesión, alta rentabilidad, entre otros. Un paradigma de
programación es una colección de modelos conceptuales que juntos
modelan el proceso de diseño y determinan, al final, la estructura de un
programa.
4.2.4. Tipos de paradigma
El paradigma a usar para resolver un problema, debe ser
codificado en un lenguaje de programación compatible con él y capaz
soportar los mismos conceptos del propio paradigma.
Esta compatibilidad hace confundir los conceptos de paradigma y
lenguaje de programación, mezclando al propio paradigma con su
herramienta de proceso. Al respecto, para no caer en este error
conviene destacar que un mismo paradigma puede ser soportado por
más de un lenguaje, y un lenguaje puede soportar más de un
paradigma, como el C++.
El paradigma es el concepto o heurística intangible, mientras que
el lenguaje es su materialización en forma de códigos operacionales.
Los tipos de paradigmas de la programación, son los siguientes:
Programación Imperativa. Propicia un entorno de programación
procedimental, en el que la secuencia de control y el concepto de
variable son sus componentes fundamentales.
Programación Orientada por Objetos. Resuelve problemas
pensando en objetos, y hace posible la reutilización de software.
Programación Funcional. La programación funcional, es un
modelo basado en la evaluación de funciones matemáticas,
entendidas como mecanismos para aplicar ciertas operaciones
sobre algunos valores o argumentos, para obtener un resultado o
valor de la función para tales argumentos.
Programación lógica. Resuelve problemas descriptos como las
relaciones de un conjunto de datos, sobre las que aplica reglas de
deducción y a partir de tales premisas genera conclusiones
aceptadas como validas. Usa la lógica de predicados, o aserciones
lógicas que representan el conocimiento sobre un ámbito.
Programación Concurrente. Éste paradigma se basa en la
capacidad de diseñar y programar tareas que puedan ser
ejecutadas al mismo tiempo, es decir que se pueden efectuar
múltiples acciones simultáneamente.
En esta asignatura, los programas se desarrollaran en el paradigma
orientado a objetos; cabe mencionar que los estudiantes también utilizarán
los demás paradigmas citados
4.2.5. Definición programación orientada a objetos
La Programación Orientada a Objetos (POO u OOP para la sigla
en inglés) es un paradigma de programación que define los
Los objetos son entidades que combinan estado (datos) y
comportamiento (procedimientos o métodos).
La programación orientada a objetos expresa un programa como
un conjunto de estos objetos (en tiempo de ejecución), que se
comunican entre ellos para realizar tareas.
Esto difiere de los lenguajes procedurales tradicionales, en los que
los datos y los procedimientos están separados y sin relación.
Ejemplos: Delphi, Java, C++, Python.
Abstracción. La abstracción de datos permite no preocuparse de
los detalles no esenciales. Las estructuras de datos y los tipos de
datos son un ejemplo de abstracción. En la abstracción se
destacan los aspectos relevantes del objeto e ignorar los aspectos
irrelevantes del mismo (la irrelevancia depende del nivel de
abstracción, ya que si se pasa a niveles más concretos, es posible
que ciertos aspectos pasen a ser relevantes).
Encapsulación. El encapsulamiento consiste en unir en la clase
las características y comportamientos, esto es, las variables y
métodos. Es tener todo esto es una sola entidad. En los lenguajes
estructurados esto era imposible. Es evidente que el
encapsulamiento se logra gracias a la abstracción y el
ocultamiento. La utilidad del encapsulamiento va por la facilidad
para manejar la complejidad, ya que tendremos a las Clases como
cajas negras donde sólo se conoce el comportamiento pero no los
detalles internos, y esto es conveniente porque nos interesará será
conocer qué hace la Clase pero no será necesario saber cómo lo
hace.
Principio de ocultamiento. Es la capacidad de ocultar los detalles
internos del comportamiento de una Clase y exponer sólo los
detalles que sean necesarios para el resto del sistema. El
ocultamiento permite dos (2) cosas: restringir y controlar el uso de
la Clase, restringir porque habrá cierto comportamiento privado de
la Clase que no podrá ser accedido por otras Clases, y controlar
porque se proveerá ciertos mecanismos para que se pueda
modificar el estado de la Clase y es en estos mecanismos dónde
se validarán que algunas condiciones se cumplan. En los
lenguajes de programación que soportan este paradigma el
ocultamiento se logra usando las palabras reservadas que se
pueden traducir como: publica, privada y protegida delante de las
variables y métodos.
Herencia. La herencia es uno de los conceptos más cruciales en la
POO. La herencia básicamente consiste en que una clase puede
heredar sus variables y métodos a varias subclases (la clase que
hereda es llamada superclase o clase padre y la heredada llamada
subclases o clases hijas). Esto significa que una subclase, aparte
de los atributos y métodos propios, tiene incorporados los atributos
y métodos heredados de la superclase. De esta manera se crea
una jerarquía de herencia. La importancia de la herencia radica, en
que es una forma de reutilización de software, con esto se ahorra
tiempo durante el desarrollo de programas; también fomenta la
reutilización de software depurado y probado de alta calidad, el
cual aumenta la probabilidad de que un sistema se implemente con
efectividad.
Polimorfismo. Es la propiedad que tienen los objetos de permitir
invocar genéricamente un comportamiento (método) cuya
implementación será delegada al objeto correspondiente recién en
tiempo de ejecución. La característica del polimorfismo es critica
porque permite que varios tipos (derivados de un mismo tipo base)
sean tratados como si fueran uno sólo, y un único fragmento de
código, se puede ejecutar de igual forma en todos los tipos
diferentes. La llamada a un método polimórfico permite que un tipo
exprese su distinción de otro similar, puesto que ambos se derivan
del mismo tipo base. Esta distinción se expresa a través de
diferencias en comportamiento de los métodos a los que se puede
invocar a través de la clase base.
Estas dos (2) últimas características se ilustrarán en la
unidad 4, mientras las otras en la unidad 2.
4.2.6. Definición de elementos básicos de la programación
orientada a objetos
Elementos Básicos:
Objeto: es una colección de datos y subrutinas o métodos que
operan sobre ellos. Pueden representarse cosas físicas o
abstractas, que tienen un estado y un comportamiento. Ejemplo un
estudiante, un círculo, una fracción, un polinomio entre otros, se
consideran objetos. Ciertas propiedades definen a un objeto y se
conocen como campos de datos o propiedades y el
comportamiento de los objetos se definen como métodos.
Clases: son aquellas estructuras o plantillas que sirven para
describir un objeto. Una clase tiene un nombre y especifica los
miembros que pertenecen a ella, que pueden ser campos de datos
y métodos. Una vez que se define una clase, el nombre de ésta se
convierte en un nuevo tipo de dato y se puede declarar variables
de ese tipo y crear objetos de este tipo.
Mensajes: estos están asociados con un método, de tal forma que
cuando un objeto recibe un mensaje la respuesta a ese mensaje
es ejecutar el método asociado, Por ejemplo, partamos de que una
ventana de Windows es un objeto entonces cuando un usuario
quiere maximizar una ventana de una aplicación Windows, lo que
hace simplemente es pulsar el botón de la misma que realiza esa
acción. Eso, provoca que Windows envíe un mensaje a la ventana
para indicar que tiene que maximizarse. Como respuesta a este
mensaje se ejecutará el método programado para ese fin.
Métodos: Se implementa en una clase de objetos y determina
cómo tiene que actuar el objeto cuando recibe el mensaje
vinculado con ese método. A su vez, un método puede también
enviar mensajes a otros objetos solicitando una acción o
información. En adición, las propiedades definidas en la clase
permitirán almacenar información para dicho objeto.
Diferencia entre objeto y clase:
El objeto es una entidad concreta que existe en tiempo y espacio
mientras una clase representa una abstracción, la esencia de un
objeto.
Diferencia entre mensaje y métodos:
El método es una operación mientras que el mensaje es la
indicación de que se ejecute el método involucrado con éste.
Ejemplos
de objetos
Libro Java cómo programar de Deitel- Deitel.
Libro Java 2 Curso de Programación de Ceballos.
En la Figura 2.4. Se puede observar el ejemplo de objetos
Libro Java cómo Libro Java 2 Curso
programar de de Programación
Deitel- Deitel. de Ceballos.
Figura 2.4. Ejemplo de Objetos
Fuente: Propia
de Clase
Libro
Clase Libro{
}
En la Figura 2.5; se observa el ejemplo de clase Libro
Metodos
De la Figura 2.5 se puede observar evaluar( ) y actualizar ( )
que son métodos de la clase Libro, son operaciones que se le
pueden aplicar a un objeto de ese tipo de dato.
Mensajes
Los mensajes serian los siguientes:
libroDeMatematicas . evaluar ( ) ;
libroDeFisica . actualizar ( ) ;
De estos ejemplos se puede observar, como una clase describe a
instancias, mientras los objetos son entidades con sus propiedades
perteneciente a una clase; también se puede ver que los métodos son
operaciones dentro de una clase y la llamada a estos son los mensajes.
Clase Libro
titulo
autor
editorial
edición
año
evaluar ( )
actualizar ( )
Figura 2.5 Ejemplo de clase Libro
Fuente: Propia
Los programas usados para ilustrar los conceptos de la Programación
orientada a objetos, se crearán con el lenguaje de programación de alto nivel
Java.
CAPÍTULO V: ABSTRACCIÓN Y ENCAPSULACIÓN DE DATOS
5.1. Objetivos
Definir el concepto de abstracción encapsulación de datos con
sus propias palabras, según lo estudiado en clase.
Discutir la abstracción y encapsulación de datos y los tipos de
abstracción, usando ejemplos de la vida cotidiana, basado en lo
estudiado en la clase.
Resolver un problema propuesto por el docente, usando la
abstracción y encapsulación de datos en la programación
orientada a objetos, con un buen margen de precisión.
5.2. Contenido
Definición de abstracción de datos. Definición de
encapsulamiento.
Tipos de abstracción existentes. Ejemplos de aplicación de la
abstracción y encapsulación de datos.
Ejemplos de programas resueltos donde se aprecie la abstracción
y encapsulación de datos de la programación orientada a objetos.
Resolución de problemas usando programación orientada a
objetos, haciendo énfasis en la abstracción y encapsulación de
datos.
5.2.1. Definición de abstracción de datos. Definición de
encapsulamiento.
En cualquier parte del mundo real se puede ver objetos: gente,
animales, plantas, aviones, edificios, computadores, etc. Los seres humanos
piensan en forma de objetos. Los humanos aprenden de los objetos
estudiando sus atributos y observando sus comportamientos, distintos
objetos pueden tener atributos similares y pueden exhibir comportamientos
similares.
La abstracción es la habilidad de generalizar y centrarse en los
aspectos que permitan tener una visión global del problema y no detenerse
en los detalles concretos de lo que no interesa en un momento determinado.
Ejemplo en el estudio de un computador se puede realizar a nivel de
funcionamiento de sus circuitos electrónicos, en términos de corriente,
tensión, etc., o a nivel de transferencia entre registros, centrándose así el
estudio en el flujo de información entre las unidades que lo componen
(memoria, unidad aritmético-lógica, registros, etc.), sin importar el
comportamiento de los circuitos electrónicos que componen estas unidades.
Según la real academia, abstraer es separar por medio de una
operación intelectual las cualidades de un objeto para considerarlas
aisladamente o para considerar el mismo objeto en su pura esencia o noción.
En la abstracción de datos el cliente se preocupa acerca de que
funcionalidad ofrece un objeto dado, pero no acerca de cómo se implementa
esa funcionalidad.
Mientras la encapsulación permite ver un objeto como una caja negra
en la que se ha introducido de alguna manera toda la información
relacionada con dicho objeto. Esto permite manipular los objetos como
unidades básicas, permaneciendo oculta su estructura interna.
La abstracción y encapsulamiento están representadas por la clase. La
clase es una abstracción, porque en ella se definen las propiedades o
atributos de un determinado conjunto de objetos con características
comunes, y una encapsulación porque constituye una caja negra que
encierra tanto los datos que almacena cada objeto como los métodos que
permiten manipularlos.
5.2.2. Tipos de abstracción existentes. Ejemplos de aplicación de
la abstracción y encapsulación de datos.
Abstracción funcional: crear procedimientos y funciones e
invocarlos mediante un nombre donde se destaca que hace la
función y se ignora como lo hace.
Abstracción de datos:
Tipos de datos: La representación usada es invisible al
programador, al cual se permite ver las operaciones
predefinidas para cada tipo.
Tipos definidos por el programador: que posibilitan la
definición de valores de datos más cercanos al problema
que se pretende resolver. Ejemplo estructuras de datos.
Tipos abstracto de datos, para la definición y
representación de tipos de datos, junto con sus
propiedades.
Para mostrar los ejemplos de la aplicación de la abstracción y el
encapsulamiento de datos, se deben manejar algunos conceptos
relacionados con la programación orientada a objetos; también nociones y
reglas del lenguaje de programación Java, a continuación loe elementos de
un programa, luego clases y objetos.
Los identificadores, son los nombres que se le asignan a las
variables, constantes, métodos, clases, paquetes, interfaces, éstos
deben ser descriptivos, y evitar nombres genéricos como lo son
usarse palabras que hagan referencia a lo que representen, el nombre
de una clase debe representar que esta describiendo, al igual para las
variables y métodos.
En el lenguaje Java los identificadores deben comenzar con
letras ó carácter de subrayado ( _ ) ó carácter de dólar ( $ ) no pueden
comenzar con números, no pueden tener espacios en blanco, ni caracteres
especiales que representen algún operador dentro del lenguaje, ni usar
palabras reservadas del lenguaje en uso; en el lenguaje java esta permitido
lenguaje se acostumbra que los nombres de las clases comiencen en
mayúsculas, los de las variables y métodos en minúsculas y las constantes
todas en mayúsculas; en Java se diferencia las minúsculas de las
mayúsculas.
Tipos de Datos: En java los tipos de datos se clasifican en
Primitivos: en éste lenguaje existen ocho (8) tipos de datos
primitivos se dividen en numéricos y el boolean, a su vez los
numéricos se clasifican en números enteros y números reales.
Cada tipo tiene un rango diferente de valores positivos y
negativos excepto el boolean que sólo tiene dos valores (true ó
false). El tipo de datos que se escoja para declarar las variables
de un determinado programa dependerá del rango y tipo de
valores que se vaya a almacenar en cada una. Se les llama
primitivos porque ellos están integrados en el sistema y no son
objetos. A continuación se van a presentar de esta forma: tipo
de dato (descripción, cantidad de bits y rango según la cantidad
de bits usado).
byte número entero de 8 bits, rango: -128, +127
short numero entero pequeño de 16 bits, rango: -
32768,+32767
int números enteros de 32 bits, rango: -2147483648,
+2147483647, se pueden representar en las bases
decimal (10), octal (8), y hexadecimal (16); para la base
10 se puede usar los dígitos de 0 a 9, sin que el primer
dígito del numero sea cero (0), ejemplo: 9852; mientras
para la base 8, son los dígitos de 0 a 7, y debe comenzar
con cero (0), ejemplo 052; y para la base 16 los diogitos
válido son de 0 a 9 y de A F, deben comenzar con un
cero seguido de una equis (0x), ejemplo 0x42B.
long numero entero grande de 64 bits, rango:
9223372036854775808, +9223372036854775807)
char carácter alfabético, numérico o especial,
representado por un número del código Unicode,
comprendidos en el rango de 0, 65535, éste código es
de 16 bits y es un estándar de codificación de
caracteres, el término Unicode proviene de los tres
objetivos perseguidos: Universalidad, uniformidad y
unidad.
float números en coma flotante, con una precisión
aproximada de siete (7) dígitos, y con 32 bits para su
representación en el formato IEEE 754 (este formato
utiliza 1 bit para el signo, 8 bits para el exponente y 24
para la mantisa)
double números en coma flotantes de 64 bits en el
formato IEEE 754 (1 bit para el signo, 11 bits para el
exponente, y 52 bits para la mantisa) y con una precisión
aproximada de 16 dígitos.
boolean se utiliza para indicar si el resultado de la
evaluación de una expresión booleana es verdadero ó
falso. Los dos posibles valores son true ó false (son
palabras reservadas de Java).
Representación de variables de tipos primitivos en
memoria: a continuación se presenta la tabla 5.1 con un
ejemplo de como se representan los datos primitivos en la
memoria, fíjese que el byte se almacena en 1 posición de
memoria, mientras el short en 2 posiciones consecutivas. Es
importante recalcar que este es sólo un ejemplo, para ilustrar
los datos en memoria, realmente cuando son declarados varios
datos no se almacenan en posiciones sucesivas.
Tabla 5.1. Ejemplo de la representación de datos primitivos en memoria (1/2)
Tipo de dato Dirección de Contenido en
memoria memoria
byte b = 95 3452FA 95
3452FB
short s = 2563 2563
3452FC
3452FD
3452FE
int i = 200520 200520
3452FF
345300
345301
345302
345303
345304
long l = 2589256 2589256
345305
345306
345307
345308
345309
34530A
Fuente: Propia
Tabla 5.1. Ejemplo de la representación de datos primitivos en memoria(2/2)
34530B
34530C
float f = 256,562 256,562
34530D
34530E
34530F
345310
345311
52oublé d = 345312
5,623415963
5,623415963 345313
345314
345315
345316
boolean b = true; Depende de la plataforma
Fuente: Propia
Conversiones en Java: Cuando Java tiene que evaluar una
expresión en la intervienen operandos de diferentes tipos,
primero convierte, sólo para realizar las operaciones solicitadas,
los valores de los operandos al tipo del operando cuya precisión
sea más alta. Cuando se trate de una asignación, convierte el
valor de la derecha al tipo de la variable de la izquierda siempre
que no haya pérdida de información. En otro caso, Java exige
que la conversión se realice explícitamente. La figura 2.1
resume los tipos colocados de izquierda a derecha de menos a
más precisos; las flechas indican las conversiones implícitas
permitidas:
char
int long float double
byte short
Figura 5.1.Conversión implícitas de tipos de datos primitivos
Fuente: Propia
Del ejemplo de la Figura 5.1, se puede concluir:
byte bDato = 1 ;
short sDato =0 ;
int iDato = 0 ;
long lDato = 0 ;
float fDato = 0 ;
double dDato = 0 ;
sDato = bDato ;
iDato = sDato ;
lDato = iDato;
fDato = lDato;
dDato = fDato + lDato iDato * sDato / bDato;
Java permite una conversión explícita del tipo de una
expresión mediante una construcción denominada cast, que
tiene la siguiente forma:
(tipo) expresión
Cualquier valor de u tipo entero o real puede ser
convertido a o desde cualquier tipo numérico. No se pueden
realizar conversiones entre los tipos enteros o reales y el tipo
boolean, observe el siguiente ejemplo:
byte bDato = 0 ;
short sDato =0 ;
int iDato = 0 ;
long lDato = 0 ;
float fDato = 0 ;
double dDato = 2 ;
fDato = ( float ) dDato ;
lDato = ( long ) fDato ;
iDato = ( int ) lDato ;
sDato = ( short ) iDato ;
bDato = ( byte ) ( sDato + iDato - lDato * fDato / dDato ) ;
La expresión es convertida al tipo especificado si esa
conversión está permitida; en otro caso, se obtendrá un error.
La utilización apropiada de construcciones cast garantixa una
evaluación consistente, pero siempre que se pueda, es mejor
evitarla ya que suprime la verificación de tipo proporcionada por
el compilador y por consiguiente puede conducir a resultados
inesperados, o cuando menos, a una pérdida de precisión en el
resultado. Por ejemplo:
double d=10.0/3.0; //el resultado de d:
3.33333333333333335
float r= (float)(10/3.0); // el resultado de r: 3.3333333
Referenciados son clases, interfaces y arrays; estos se ilustrarán en
unidades posteriores
Literales: es la expresión de un valor de un tipo primitivo, puede ser
de:
Literales Enteros: si no se especifica el signo es positivo por
defecto; [ +/- ]número-entero. Para los int +4, 25896, -95; para
los long
dentro del rango de un int entonces declararlo que a pesar de
esto es un long;
Literales Reales: están formados por una parte entera,
seguido de un punto decimal y una parte fraccionaria, también
se permite la notación científica; [ +/- ] parte-entera . parte-
parte- - exponente ] Para double
159423698.256; 125.1e+3; estos literales por defecto serán
double
número, 25.8f.
Literales de un solo carácter: son para los char y esta dado
\
Literales de cadenas de caracteres: es una secuencia de
están descrita con una clase llamada String, vea el punto 2.1 de
la Unidad 3.
Comentarios en Java: Un comentario esta dirigido a un programador
o alguna persona que lea el código, más no se ejecutará.
De una línea: esta representado por dos barras ( // ) el
comentario será desde las dos barras hasta el fin de la línea.
//Toda ésta línea
Tradicional o de bloque: esta formado con una barra seguida
de un asterisco ( /* ) que inician el comentario hasta que se
encuentre un asterisco seguido de una barra ( */ ) que indican el
fin del comentario, sin importar cuantas líneas abarque dicho
comentario. Ejemplo:
/* Este es
un
comentario
de más de una línea
*/
De documentación: Este tipo comienza con una barra
seguida de doble asteriscos ( /** ) y finaliza con un
asterisco seguido de una barra
( */ ), son comentarios especiales que se utilizan
para generar la documentación acerca del programa,
aunque también se pueden emplear de manera idéntica
a los comentarios tradicionales.
Operadores: Son símbolos que indican cómo son manipulados los
datos. Se clasifican en:
Aritméticos: Son aquellos usados para realizar la operaciones
matemáticas:
Suma ( + ) de datos que deben ser enteros o reales (int,
short, long, float, double)
Resta ( - ) de datos que deben ser enteros o reales al
igual que en la suma
Multiplicación ( * ) de datos que al igual que en la suma y
resta deben ser enteros o reales
División ( / ) de datos que pueden ser enteros o reales,
aunque si son enteros el resultado también lo será
porque es truncado, en el caso que sean real el
resultado también lo será
Residuo ( % ) de datos que sólo pueden ser enteros.
Ejemplos
int a = 2,b = 3,r = 0;
r = a + b; //r tienen el valor de 5
r = b - a; //r tienen el valor de 1
r = a * b; //r tienen el valor de 6
r = b / a; /* r tienen el valor de 1, fíjese que el
valor tendría que ser 1.5 pero como los dos
operandos son enteros, entonces se trunca el
resultado. Mientras que */
float x = 2.0f, y = 3.0f, r2 = 0.0f;
r2 = y / x; //r tienen el valor de 1.5f aunque
r2 = b / a; /* r tienen el valor de 1.0f, porque los
operandos son de tipo enteros */
Relacionales: permiten evaluar la igualdad y la magnitud. El
resultado de una evaluación de este tipo es un valor booleano
true ó false.
Menor que ( < ), primer operando es mayor que el
segundo?
Mayor que ( > ), primer operando es menor que el
segundo?
Menor o igual que ( <= ), primer operando es menor o
igual que el segundo?
Mayor o igual que ( >= ), primer operando es mayor o
igual que el segundo?
Diferente ( != ), primer operando es diferente que el
segundo?
Es igual a ( == ), primer operando es igual que el
segundo?
Ejemplos:
boolean r;
float x = 5.2f, y = 2.6f;
r = x >= y; // el valor de r es true.
r = x < y; // el valor de r es false.
r = x == y; // el valor de r es false.
r = x != y; // el valor de r es true.
Lógicos: Se utilizan junto a los operadores relacionales cuando
es necesario hacer más de una pregunta, y el resultado de
estas operaciones son de tipo boolean.
AND (&& ó &), para que el resultado sea verdadero
todos los operandos involucrados deben ser verdaderos,
con (&&) si el primer operando evaluado es falso,
entonces los demás no son evaluados.
OR ( || ó | ) El resultado es verdadero si al menos una de
los operandos es verdadero, si se utiliza el (||) y el primer
operando es verdadero entonces los demás no son
evaluados.
NOT (!) es la negación de un operando, si el operando
es verdadero entonces el resultado es falso y viceversa.
XOR (^) es un o exclusivo, si sólo uno de los operandos
es verdadero el resultado es verdadero. Si hay más de
uno verdadero el resultado es falso.
Ejemplos.
int p = 10, q = 0;
boolean r;
r = p != 0 && q != 0; // r = false.
r = p != 0 || q > 0; // r = true.
r = q < p && p <= 10; // r = true;
r = !r; // si r = true, entonces ahora es false y
sino es true.
Unitarios, se aplican sólo a un operando, en esta categoría
puede entrar el NOT ( ! ) que ya se ha visto
Complemento a 1 ( ~ ), este operador cambia ceros por uno y
unos por ceros, el operando debe ser un tipo primitivo entero.
Complemento a 2 ( - ), es para calcular el complemento
a 2, que non es más que el complemento a 1 más 1, el
operador puede ser de un tipo primitivo entero ó real.
Ejemplos:
int a = 2, b = 0, c = 0;
c = -a; // c es igual a -2
c = ~b; // c es igual a -1
A nivel de bits, permiten realizar con sus operandos las
operaciones AND, OR, XOR y desplazamientos, bit por bit. Los
operandos tienen que ser enteros.
AND a nivel de bits ( & ), en binario base 2.
OR a nivel de bits ( | ) , en binario base 2.
XOR a nivel de bits ( ^ ) , en binario base 2.
Desplazamiento a la izquierda rellenando con ceros por
la derecha. ( << )
Desplazamiento a la derecha rellenando con el bit de
signo por la izquierda. ( >> )
Desplazamiento a la derecha rellenando con ceros por la
izquierda. ( >>> )
Los operandos tienen que ser de un tipo primitivo
entero; en la Tabla 5.2. Se presentan algunos ejemplos
Tabla 5.2. Ejemplos de los operadores a nivel de bits
Instrucción Resulta Descripción
int a = 255; a = 255 Asignación de las tres (3) variables
int r = 0; r=0
int m = 32; m = 32
r = a & 017; r = 15. Porque 017 esta expresado en la base 8
entonces (017)8 (15)10 (1111)2, y
(255)10 (11111111)2, luego si se compara con
AND bit por bit, (00001111)AND(11111111), el
resultado es (00001111) 15
r = r | m; r =47 inicialmente r = 15 (001111)2 y
m=32 (100000)2, entonces,
(001111)2OR(100000)2 resulta
(101111)2 (47)10
r = a & ~07; r = 248 Porque inicialmente a=(255) (011111111)2 y
07 (000000111)2, entonces , ~07
(111111000)2, (011111111) AND
(111111000), resulta (011111000) (248)10
r = a >> 7; r=1 Como se ha dicho que a =
(255)10 (011111111)2, entonces se desea
el desplazamiento de 7 bits a la derecha,
por lo tanto (001111111) (000111111) y así
hasta desplazar los 7 bits de la instrucción
hasta (000000001) (1)10
r = m << 1; r = 64 equivale a r = m * 2
r = m >> 1; r = 16 equivale a r = m / 2
Fuente: Propia
De asignación. Almacena el valor en el operando de la
izquierda, aquí se incluyen los de incremento y decremento
porque implícitamente realizan una asignación.
Incremento ( ++ )
Decremento ( -- )
Asignación simple ( = )
Multiplicación más asignación ( *= )
División más asignación ( /= )
Modulo más asignación ( %= )
Suma más asignación ( += )
Resta más asignación ( -= )
Desplazamiento a izquierda más asignación ( <<= )
Desplazamiento a derecha más asignación ( >>= )
Desplazamiento a derecha más asignación rellenando
con ceros ( >>>)
Operación AND sobre bits más asignación ( &= )
Operación OR sobre bits más asignación ( |= )
Operación XOR sobre bits más asignación ( ^= )
Los operandos tienen que ser de un tipo de dato
primitivo. en la Tabla 5.3. Se presentan algunos
ejemplos.
Tabla 5.3. Ejemplos de los operadores de asignación (1/2)
Instrucción Descripción
int x = 0, n = 10, i = 1; Asignación
n ++; //incrementa el valor de n en 1
++ n; //incrementa el valor de n en 1.
x = ++ n; incrementa n en 1 y asigna el resultado a x
x = n ++; Asigna el valor de n a x y después e
incrementa n en 1
Fuente: Propia
Tabla 5.2. Ejemplos de los operadores de asignación (2/2)
i += 2; Realiza la operación i = i + 2.
x *= n 3; Realiza la operación x= x *(n - 3) y no x = x * n
3
n >>= 1; Realiza la operación n = n >> 1, la cual
desplaza el contenido de n 1 bits a la derecha
Fuente: Propia
El operador ( ++ ) y ( -- ) si están antes de la variable
es prefijo, es decir, se ejecuta primero el incremento o
decremento y luego las otras operaciones; mientras si
esta como sufijo, después de la variable, entonces
primero se hacen las otras operaciones y luego se
ejecuta el incremento o decremento.
Condicional ( ?: ), conocido también como operador ternario,
se usa cuando el valor que le asignará a una variable depende
de una condición, de este tipo: (expresión booleana)? valorV :
valorF; la expresión booleana si es verdadera el resultado será
valorV y si es falsa será valorF. Ejemplo
double a = 10.2, b = 20.5, mayor = 0;
mayor = (a > b) ? a : b; //mayor tendrá un valor de 20.5
Prioridad de operadores Se ordenan de mayor a menor prioridad, los
que están en una sola misma línea tienen la misma prioridad. Ver
Tabla 5.4.
Tabla 5.4. Prioridad y asociatividad de todos los operadores (1/2)
Operador Asociatividad
() [] . Izquierda a derecha
- ~ ! ++ -- Derecha a izquierda
new (tipo)expresión Derecha a izquierda
* / % Izquierda a derecha
+ - Izquierda a derecha
Fuente: Propia
Tabla 5.4. Prioridad y asociatividad de todos los operadores (2/2)
<< >> >>> Izquierda a derecha
< <= > >= instanceof Izquierda a derecha
== != Izquierda a derecha
& Izquierda a derecha
^ Izquierda a derecha
| Izquierda a derecha
&& Izquierda a derecha
|| Izquierda a derecha
?: Derecha a
izquierda
= *= /= %= += -= <<= >>= >>>= &= |= ^= Derecha a
izquierda
Fuente: Propia
Sentencias de control en el lenguaje Java: son usadas para
controlar la ejecución de un programa según ciertas condiciones. En el
lenguaje Java existen las siguientes: if-else, switch, for, while, do-
while.
La sentencia if permite a un programa tomar una decisión para
ejecutar una acción u otra, basándose en el resultado de una
expresión, la sintaxis es la siguiente:
if (expresión booleana ) [{]
sentencia 1;
[sentencia 2:
sentencia n;
}]
[else{
sentencia a;
sentencia b;
sentencia m;
}]
donde, el valor de la expresión booleana puede ser
verdadero o falso, si es verdadero se ejecutan la/s
sentencia/s de la 1 a la n sin ejecutarse las del else;
sino, se ejecutan las del else (sino) de a hasta m
obviando las del if; en el caso de necesitar que se
ejecute sólo una instrucción entonces no es necesario
las llaves del if, igual para el else. Es posible que no
exista else porque no hay instrucción/es que necesiten
ser ejecutadas si la/s expresión booleana es falsa. Las
sentencias pueden ser otros if con otra expresión
booleana, a esto se le conoce como if anidados.
La sentencia switch, se utiliza para comparar el valor de una
variable con muchos casos, éstos últimos no tienen limites,
pueden ser muchos casos y según el valor se ejecuten de una
a muchas acciones, su sintaxis:
switch (variable ){
case valor1 : sentencia1;
break;
case valor2 :
case valor3 : sentencia2;
break;
default : sentencia3;
}
donde, variable debe ser de un tipo de dato int, short,
char ó byte, y si esta variable es igual al valor1 entonces
se ejecutara todas las sentencias que estén desde los
dos puntos ( : ) hasta que se encuentre con la sentencia
break. Y así con todos los case
valor3 se ejecutará la sentencia2, porque en case valor2
no se encuentra el break para que rompa la secuencia,
el default se ejecuta en el caso que la variable no tenga
el mismo valor de ninguno de los case default no
necesariamente debe ir al final. El switch debe contener
únicamente los case default que es opcional,
dentro de los case se puede tener cualquier sentencia
de Java.
La sentencia for, permite ejecutar un ciclo de instrucciones
varias veces pero finita, según una o mas variables de control,
esta conformado por tres (3) partes fundamentales; su sintaxis:
for(inicialización(es);expresión_booleana;actualización)
[{]
sentencia 1;
[ sentencia n; ]
[}]
donde, la inicialización(es) es para asignarle valores
iniciales a la(s) variable(s) necesaria(s) e involucrada(s)
en el ciclo; la expresión booleana es para establecer
la(s) condición(es) que va hacer que las sentencias se
vuelvan a ejecutar, porque mientras esa expresión
booleana sea verdadera el for se sigue ejecutando una y
otra vez; y la parte de la actualización es para que
ocurra un incremento o decremento en la(s) variable(s)
involucrada(s) en la(s) expresión booleana garantizando
así que ésta va a tomar el valor de falsa, para que el
ciclo deje de ejecutarse. En el caso de no necesitar una
de las partes entonces se deja en blanco pero se coloca
su punto y coma ( ; ) correspondiente, recordando que
es importante que manejen dentro del for las tareas
correspondientes, si se debe ejecutar una sola
sentencia no hace falta las llaves.
La ejecución de esta sentencia: se inicializa, luego
se evalúa la expresión booleana si es verdadera se
ejecutan las sentencias, luego se actualiza(n) la(s)
variable(s) y se vuelve a evaluar y así sucesivamente
hasta que se haga falsa, cuando esto sucede se pasa a
ejecutar la siguiente instrucción fuera del for.
La sentencia while, ejecuta una o varias sentencias, mientras
una expresión booleana sea verdaera, su sintaxis:
while ( expresión booleana ) [ { ]
sentencia1;
[ sentencia2;
}]
donde, la(s) sentencia (s) se va(n) a ejecutar mientras la
expresión booleana sea verdadera, si el while consta de
sólo una sentencia entonces no es necesario las llaves,
para este ciclo es muy importante el control de las
variables involucradas en la expresión booleana para
que no se haga el ciclo infinito. Si la primera vez la
expresión es falsa no se ejecutará(n) la(s) sentencia(s)
La sentencia do-while, permite ejecutar una serie de
sentencias al menos una vez, hasta que una expresión
booleana sea falsa, su sintaxis:
do{
sentencia1;
}while(expresión booleana);
donde, la sentencia1 se ejecuta al menos una vez sin
importar la evaluación de la expresión booleana, luego
se evalua dicha expresión, si es verdadera se continua
ejecutándose la sentencia1, hasta que se haga falsa.
Fíjese que este ciclo termina con punto y coma (;).
Variables: Como se ha definido en la unidad anterior, es (son) una(s)
posición(es) de memoria con un nombre único asignado que puede
almacenar un dato a la vez, de un tipo especifico, éstas también
tienen un ciclo de vida determinado por el ámbito donde están
declaradas, es recomendable asignarle un valor inicial a cada variable;
existen varios tipos de variables:
Variables locales: se definen y se manipulan dentro de un
ámbito específico, al salir de dicho ámbito las variables
declaradas quedan liberadas, es decir, dejan de existir.
Variables de instancia: son aquellos atributos de una
clase para describir a un objeto, cada uno de éstos tiene
sus propios valores en sus respectivas características,
independientes de los demás objetos, por ejemplo cada
persona tiene su color de ojos, o su color preferido, etc.
Variables de clase: estas son declaradas también
dentro de la clase, pero almacena un valor para todos y
cada uno de los objetos que se declaren de la clase, y
para usarlas no es necesario crear un objeto, con el
nombre de la clase es suficiente, son generales para
todos los objetos de la clase, los objetos se refieren a los
mismos datos. En el lenguaje Java para definirlas se usa
la palabra reservada static
Para la declaración de una variable de instancia o clase es de la
siguiente forma, tomando en cuenta que lo que este dentro de los
corchetes es opcional:
[tipo-acceso] [static] tipo-de-dato identificador-variable [,identificador-
Métodos: Como ya se ha mencionado en la unidad anterior, son
operaciones que se le pueden realizar a objetos, se describen en la
clase y son invocados la mayoría de las veces por objetos
pertenecientes a dicha clase. Existen dos tipos de métodos:
Métodos de instancia: son aquellos que sólo pueden ser
aplicados a una instancia, es decir, pueden ser invocado o
usados sólo por objetos; porque son operaciones dirigidas a los
objetos.
Métodos de clase: son aquellos que pueden ser usados sin
necesidad de instanciar la clase, o sin crear un objeto de dicha
clase, puede ser invocado con el nombre de la clase, y también
por un objeto; éstos no pueden hacer uso de las variables de
instancias porque no están dirigidos a los objetos, por lo tanto
no puede usar atributos que le pertenecen a éstos. Para
definirlos de clase en Java se usa la palabra reservada static.
Parámetros: son valores externos necesarios para llevar a cabo
las operaciones de un método, éstos son recibidos en pareja,
conformadas por el tipo de dato e identificador del parámetro; las parejas
se separan con coma simple ( , ). Cuando se invoca un método se debe
enviar el listado de parámetros que éste espera, el primer valor que se
envía corresponde al primer parámetro del método, el segundo valor al
segundo parámetro, y así sucesivamente con todos. Los parámetros son
variables locales.
El paso de parámetros puede ser:
Por valor: Si en el cuerpo del método se modifica el valor del
parámetro que recibe y esta acción no cambia el valor del
parámetro con que se llama a ejecutar el método, es decir, que
los parámetros enviados son una copia de los originales, por lo
que cualquier modificación que se haga a estas variables
dentro del método no afecta a la variable original. Cuando el
tipo de datos de los parámetros es primitivo, siempre el paso de
los mismos es por valor.
Por referencia: cuando los parámetros recibidos son
referencias, es decir, espacios de memoria; cualquier
modificación que se le haga en el método se vera reflejada en
la variable original. Cuando los parámetros son objetos, o
arreglos siempre el paso de parámetros es por referencia.
Sobrecarga de Métodos: existe cuando en una clase hay más de un
método con igual nombre, y poseen diferencias asociados a los
parámetros. Cantidad y/o tipos, por ejemplo: Supóngase dos (2)
Métodos llamados sumar
sumar ( int , int ) y sumar( int ) en este caso los parámetros
actuales difieren en cantidad.
sumar ( float ) y sumar ( int ) en este caso los parámetros
actuales difieren con respecto al tipo.
sumar ( float , double ) y sumar ( int ) en este caso los
parámetros actuales difieren con respecto a la cantidad y al
tipo.
El compilador es el encargado de ejecutar el método correspondiente.
Constructores: Es un método que se ejecutan automáticamente
cuando se crea un objeto de una clase. Sirve para inicializar los
miembros de la clase.
El constructor tiene el mismo nombre de la clase. Cuando se define no
se puede especificar un valor de retorno, nunca devuelve un valor. Sin
embargo, puede tomar cualquier número de argumentos.
Constructor por defecto: es el que no tiene parámetros,
normalmente inicializa todos los atributos de la clase con
valores por defecto.
Constructores sobrecargados: Al igual que se puede
sobrecargar un método de una clase, también se puede
sobrecargar el constructor de una clase. De hecho los
constructores sobrecargados sdon bastantes frecuentes y
proporcionan diferentes alternativas para inicializar objetos.
Modificadores o tipos de acceso: es el tipo que define el acceso de
las clases así como variables y métodos. En el lenguaje Java existen
cuatro (4) tipos:
public: aquellos elementos que tienen este tipo pueden ser
accedidos desde cualquier clase, por medio de un objeto, o la
clase. Este es usado para la mayoría de los métodos.
protected: Están disponibles para la clase donde están
declarados, otras clases del mismo paquete, y las subclases
(que son aquellas que heredan de ésta, este tema se tratará en
la unidad 4).
private: sólo es accesible desde la clase que es miembro. Este
es usado en la mayoría de los atributos, para proteger sus
valores y así respetar el principio de ocultamiento.
Por defecto: si no se usa un especificador, entonces, el
miembro de la clase es visible a la clase de la que es miembro,
a las clases derivadas de la misma, que están en su mismo
paquete y a otras clases del mismo paquete
Paquete: Es una colección de clases, lógicamente relacionadas entre
sí, agrupadas bajo un nombre; incluso un paquete puede contener
otro(s) paquete(s). Para usar un paquete en Java se debe hacer la
importación de la siguiente forma: (a) import identificador-del-paquete
seguido de un punto, seguido del nombre-de-la-clase-a-usarse, ó (b)
import identificador-del-paquete . *;
(a) import java . io . BufferedReader ;
(b) import java . io . * ;
este último es para importar mas de una (1) clase del mismo paquete.
También se puede crear un paquete con la palabra reservada package
seguido del identificador-del-paquete y por ultimo un punto y coma ( ; ), y así
también se incluyen nuevas clases a un paquete. Ejemplo:
package mi_paquete;
class
Declaración y creación de un objeto: después de realizada una
clase, se puede instanciar, o declarar y crear un objeto de ese nuevo
tipo de dato, para declararlo se hace similar que para una variable:
tipo de dato en este caso el nombre de la clase seguido del nombre
del objeto o identificador y luego un punto y coma (; ).
Observe:
identificador_de_la _clase identificador_del_objeto1;
mientras que para crearlo se debe hacer un llamado al constructor de la
clase que tiene el mismo nombre de ésta, con el operador new que reserva
el espacio necesario en memoria para el nuevo objeto e inicializa los
atributos.
Observe:
identificador_del_objeto1 = new Identificador_de_la _clase ( );
Es importante destacar que para usar un objeto debe estar previamente
declarado y creado, porque sino lo esta, entonces no existe. Esto se debe a
que cuando se declara el objeto no se ha asignado la referencia en memoria
del mismo; observe la Figura 5.2 (a) s
pero no se le asigna un espacio en memoria (c), el objeto1 referencia a null,
es decir, no tiene memoria asignada; luego en la Figura 5.3, se ilustra la
creación del objeto en la (a), en la parte (b) se observa la referencia a
memoria del objeto1, y en la (c) esta en la memoria las posiciones
reservadas para todos los atributos del objeto1.
Los objetos no se almacenan en posiciones secuenciales de la
memoria, aunque los atributos de un objeto si lo hacen.
Clase A{ Clase A objeto1; objeto1;
char x; Referencia = null
byte y;}
(b) sentencia
(a) Declaración de de (c) en memoria
la clase ClaseA declaración del
objeto1
Figura 5.2. Declaración de un objeto y su representación en memoria
Fuente: Propia
objeto1 = new ClaseA(); 25896F0
x
(a) sentencia de creación 25896F1
25896F2
y
objeto1; 25896F03
(b) en memoria
Figura 5.3. Creación de un objeto y su representación en memoria
Fuente: Propia
Para aplicar la abstracción y encapsulamiento de datos, se
debe desarrollar una clase, donde se haga la abstracción de los
detalles que se necesitan para describir un objeto, con las
operaciones que describan el comportamiento de éste.
Composición: una clase puede tener entre sus atributos un objeto de
otra clase; entonces los objetos de la primera clase esta compuesto
por objetos de la segunda clase; como se puede observar la
composición es una relación entre clases; por ejemplo: El cuerpo
humano que esta compuesto por los órganos, músculos, sistema
óseo; si el cuerpo humano es el objeto a abstraer, entonces sus
características o atributos son objetos de otras clases. Otro ejemplo
puede ser un automóvil, que esta conformado por el motor, sistema de
freno, sistema de amortiguación, entre otros; para describir el
automóvil se necesitan declarar antes las clases que describan un
motor, otra para describir el sistema de freno, y otra para el sistema de
amortiguación, y así una clase para cada uno de los componentes
complejos que lo conforman, y al final es que se va a declarar la clase
automóvil. Como se puede observar en las Figuras 5.4 y 5.5
Motor
Automóvil
Figura 5.4 Ejemplo de Composición
Fuente: Propia
Figura 5.5 Ejemplo de Composición
Fuente: Propia
, fíjese
5.2.3 Ejemplos de programas resueltos donde se aprecie la
abstracción y encapsulación de datos de la programación
orientada a objetos.
Como ya se ha mencionado el lenguaje a utilizar en los ejemplos será el
lenguaje Java.
Observe la Figura 5.6, fíjese que hay cinco (5) círculos, las diferencias
entre ellos es el color y el diámetro, es decir, si se quiere describir un circulo
con una clase, los atributos de la misma serán diámetro y color.
Figura 5.6. Representación de círculos
Fuente: Propia
Entonces, los atributos de la clase Circulo en la Figura 5.7:
Clase Circulo
Color
Diámetro
Figura 5.7. Atributos de la clase Circulo.
Fuente: Propia
Ahora bien, que operaciones se le pueden hacer a un círculo? Se
puede cambiar su color, cambiar su diámetro. En Figura 5.8.(a) se puede
apreciar el paso de mensajes a dos de los círculos y en la Figura 5.8.(b) se
puede ver después de ejecutada la primera figura.
Figura 5.8.(a) Operaciones a los círculos.
Fuente: Propia
Figura 5.8.(b) Resultado de la operaciones a los circulos
Fuente: Propia
Entonces los métodos de la clase circulo son: cambiarColor (
nuevocolor ) y cambiardiametro ( nuevodiametro ), observe la Figura 5.9
Clase Circulo
color cadena
diametro numero real
Circulo ( numero real , cadena )
cambiarColor ( cadena ) no retorna valor
cambiarDiametro ( numero real ) no retorna valor
Figura 5.9. Atributos de la clase Circulo
Fuente: Propia
Ahora se codifica la clase circulo, partiendo de la Figura 5.9. Observe la
Figura 5.10.
1 class Circulo {
2 private String color ;
3 private float diametro ;
4 Circulo ( String color , float b ) {
5 this . color = color ;
6 diametro = b ;
7 }
8 public void cambiarColor ( String nuevo ) {
9 color = nuevo ;
10 }
11 public void cambiarDiametro ( float nuevo ) {
12 diámetro = nuevo ;
13 }
14 } //fin de la clase Circulo
Figura 5.10. Código fuente de la clase Circulo en lenguaje Java
Fuente: Propia
De la Figura 5.10. Donde se ilustra el código fuente de la clase Circulo,
se puede ver que la línea 1 corresponde a la declaración de la clase, luego
en las líneas 2 y 3 se definen los atributos de la clase, estos pueden ser
definidos al principio como se observa en éste ejemplo, o al final, lo
importante es que estén dentro de la clase y fuera de los métodos de la
misma.
En las líneas de la 4 a la 7, está el constructor de la clase, que recibe
los valores iniciales para los atributos.
En las líneas 8 y 11 se encuentran los métodos descritos anteriormente,
cambiarColor que recibe un objeto String que trae el nuevo color, y en la
línea 11 esta el método cambiarDiametro que recibe el nuevo valor en un
float. Y así finaliza nuestra clase Circulo
Ahora se quiere que en la clase Circulo, se lleve el control de cuantos
círculos se han creado, la solución a este problema es una variable de clase,
se declara como atributo y se incrementa en el constructor. Ver Figura 5.11.
(Línea 4 y 8)
Si el problema fuera que los círculos por defecto se crearán ce diámetro
4 y color blancos, entonces se necesita otro constructor que no reciba
parámetros y asigne los valores por defecto, ver Figura 5.11 líneas de la 10 a
la 14.
Fíjese que en la Figura 5.11, se añade una variable de clase llamada
cantidad (línea 4), que se incrementa en el constructor(líneas 8 y 12), esto es
para que cada vez que se cree un nuevo objeto la variable cantidad la
cuente; y se añade un método getCantidad para poder visualizar su valor
fuera de la clase(línea 17). También es esta figura se puede apreciar la
sobrecarga del constructor (líneas 5 y 10).
Ahora se presenta otro ejemplo referente a fracciones o números
racionales, donde las características de éstos, son dos valores enteros que
representan el numerador y el denominador; a continuación analizaremos los
objetos asociados a las operaciones aritméticas que se llevan a cabo con las
fracciones. Ver Figura 5.12.
Como se puede observar en la Figura 5.12, cada fracción tiene un
numerador, y un denominador, estas serian las características (atributos) y
entre las fracciones se pueden realizar operaciones aritméticas, como se
observa en la figura que la fracción a se suma con la fracción b, y la fracción
b se multiplica con la c; también se ilustra como un usuario puede interactuar
con las fracciones, fijándole el numerador o denominador. En la Figura 5.12
se representan los objetos y el paso de mensajes entre ellos.
1 class Circulo {
2 private String color ;
3 private float diametro ;
4 private static int cantidad = 0 ;
5 Circulo ( String color , float b ) {
6 this . color = color ;
7 diametro = b ;
8 cantidad = cantidad + 1 ; } // fin del constructor
9 Circulo ( ) {
10
11 diametro = 4.0f ;
12 cantidad = cantidad + 1 ; } // fin del constructor
13 public void cambiarColor ( String nuevo ) {
14 color = nuevo ; } // fin del método
15 public void cambiarDiametro ( float nuevo ) {
16 diámetro = nuevo ; } // fin del método
17 public int getCantidad ( ) {
18 return cantidad ; } } //fin de la clase Circulo
Figura 5.11. Código fuente de la clase Circulo con una variable de clase
Fuente: Propia
2/3
sumar
4/5
setNumerador
multiplica
Usuario setDenominador
1/9
Figura 5.12. Representación de Fracciones o números racionales
Fuente: Propia
Partiendo de la Figura 5.12. se identifican los atributos de la clase
Fraccion, Figura 5.13. y observese que ésta clase debe estar dentro de un
paquete con el nombre de matematicas.
El comportamiento de las fracciones puede ser, sumar dos (2)
fracciones, restar, multiplicar, dividir, simplificar, ejecutar la división. Ver
Figura 5.14.
matematica
Clase Fraccion
numerador
denominador
Figura 5.13 Atributos de la clase Fraccion, dentro del paquete matematicas
Fuente: Propia
matematicas
Clase Fraccion
num entero
den entero
Constructor Fraccion()
sumar(Fracción, Fraccion) no retorna valor
restar(Fraccion) no retorna valor
multiplicar(Fraccion) no retorna valor
dividir(fraccion, Fraccion) Fraccion
simplificar ( ) no retorna valor
resultado ( ) real
Figura 5.14 Atributos y métodos de la clase Fraccion
Fuente: Propia
Codificando la clase Fraccion,
1 package matematicas ;
2 class Fraccion {
3 private int num , den ;
4 Fraccion ( int a , int b ) {
5 this . num = a ;
6 den = b ;
7 }
8 public void sumar ( Fraccion f1 , Fraccion f2 ) {
9 num = f1 . num * f2 . den + f1 . den * f2 . num;
10 den = f1 . den * f2 . den ;
11 }
12 public void restar ( Fraccion f ) {
13 num = num * f . den - den * f . num ;
14 den = den * f . den ;
15 }
16 public void multiplicar ( Fraccion f ) {
17 num = num * f . num ;
18 den = den * f . den ;
19 }
20 public static Fraccion dividir ( Fraccion f1, Fraccion f2 ) {
21 Fraccion f = new Fraccion ( 1 , 1 ) ;
23 f.num = f1 . num * f2 . den ;
24 f . den = f1 . den * f2 . num ;
25 return f ;
26 }
27 public void simplificar ( ) {
28 int n = 0 , menor = 0 ;
29 if ( num > den ) {
30 if ( num % den == 0 ) {
31 num = num / den ;
32 den = 1 ;
33 }
34 else
35 menor = den;
Figura 5.15. Código fuente de la clase Fraccion en lenguaje Java (1/2)
Fuente: Propia
36 }
37 else
38 menor = num ;
39 if ( menor != 0 )
40 for ( n = 2 ; n < menor ; n ++ )
41 if(num % n == 0 && den % n == 0){
42 num = num % n ;
43 den = den % n;
44 }
45 }
46 public float resultado ( ) {
47 float r = ( float ) num / den ;
48 return r ;
49 }
50 public int getDenominador(){
51 return den;
52 }
53 public int getNumerador(){
54 return num;
55 }
56 }//fin de la clase Fraccion
Figura 5.15. Código fuente de la clase Fraccion en lenguaje Java (2/2)
Fuente: Propia
A continuación se explicara detalladamente el código de la Figura 5.15.
En la línea 1 se define que esta clase estará en el paquete con el
nombre de matematicas.
En la línea 2 se declara la clase con la palabra reservada class seguido
del nombre con el cual se definirá la clase.
En la línea 3 se declaran los atributos de la clase, num y den, como
private para definir el tipo de acceso que tendrán como privados solo se
podrán usar dentro de ésta clase, y con int se especifica que van almacenar
valores numéricos enteros.
En las líneas 4 a 7, se define el constructor de la clase que es el
método encargado de inicializar los atributos, se tiene que llamar igual que la
clase, no necesita ni tipo de acceso ni tipo de dato del valor retornado; para
este caso recibe dos (2) enteros para asignárselos a los dos (2) atributos de
la clase. Es importante destacar que existen casos en los cuales no todos los
atributos deben inicializarse con valores enviados desde fuera de la clase.
Un ejemplo seria si ésta clase tuviera un atributo para el resultado de la
fracción, éste valor no se debería recibir. Porque dependería de los valores
de num y den, es decir, se puede calcular con valores que son conocidos en
la clase. La palabra reservada this es para hacer referencia a un atributo o
método perteneciente a la clase; en éste caso particular no es necesario pero
si la variable local a se llamara num igual que el atributo entonces si fuera
absolutamente necesario la referencia this, para diferenciar el atributo de la
variable local que se esta recibiendo como parámetro.
En las líneas de la 8 a 11, se encuentra el método llamado sumar , que
no retorna ningún valor ya que es de tipo void, y recibe dos (2) parámetros
que son objetos de tipo Fraccion, donde se lleva a cabo la suma de dos (2)
fracciones y se almacena en los atributos pertenecientes a el objeto que
invoco éste método.
En las líneas de la 13 a 15 se puede observar el método restar que
no retorna ningún valor, y recibe solo un parámetro que es un objeto de tipo
Fraccion, donde el minuendo es el objeto Fraccion que invoca éste método y
el sustraendo es el objeto f que se está recibiendo como parámetro, y la
resta se almacena en los atributos del objeto que invoca al método.
En las líneas de 16 a 19, se puede observar el método multiplicar ,
muy parecido al anterior el método restar .
En las líneas de la 20 a 25, se encuentra el método dividir , que retorna
un objeto tipo Fraccion, y recibe dos (2) parámetros que son objetos de tipo
Fraccion f1 y f2 ; también éste método es de clase, porque así lo indica la
palabra reservada static, en la línea 21 se declara y crea un nuevo objeto
Fraccion f para almacenar en éste el resultado de la multiplicación de los
objetos f1 y f2 , y así retornar el objeto f que es una variable local
existente solo en éste método.
En las líneas de la 26 a 44, se halla el método simplicar , que no
retorna ningún valor por esta razón es de tipo void y tampoco recibe ningún
parámetro porque este método va a simplificar el objeto Fraccion que lo
invoque, se declaran dos (2) variables de tipo int
verifica si se puede llevar a cabo la división, sino se guarda en la variable
el valor más pequeño entre el numerador y denominador para luego
proceder a partir de la línea 39 a buscar un número que divida tanto al
numerador como al denominador, para simplicar de esta forma el objeto
Fraccion que invocó al método.
En las líneas de la 45 a 48 se encuentra el método resultado , que
debe retornar un valor coma flotante que representará el resultado de la
división del objeto Fraccion que lo invoque, no recibe ningún valor porque los
que necesita son el numerador y denominador, que ya los maneja como num
y den
en ésta dicho resultado, fíjese que la palabra float entre paréntesis es para
hacer una conversión explicita del resultado de la división dos números
enteros a un numero en coma flotante, para luego retornarlo.
Y por último se encuentran los métodos y
(líneas 49 y 52), para que desde otra clase se puedan
obtener los valores de los atributos.
Para ejemplificar la composición, se podría describir un número
complejo, que tienen una parte real y otra imaginaria, hasta aquí no existiría
la composición, aunque si las partes se representarán con fracciones si.
Ejemplo ( a / b ) + ( c / d ) i; para describir éste numero tanto la parte real
como la imaginaria debe ser objetos de tipo Fraccion.
A estos números complejos se le pueden aplicar operaciones como
suma de dos (2) números complejos, o su resta, entre otras; para éste
ejemplo solo se considerarán estas dos (2) operaciones.
matematica
Clase NComplejo
pReal
pImag
Figura 5.16 Atributos de la clase NComplejo, dentro del paquete matematicas
Fuente: Propia
Codificando la representación de la clase de la Figura 5.17, y
considerando la Figura 5.15, observe el siguiente código.
matematicas
Clase NComplejo
pReal Fraccion
pImag Fraccion
Constructor NComplejo()
sumar(NComplejo,NComplejo) no retorna valor
sumar(NComplejo) no retorna valor
Restar(NComplejo,NComplejo) no retorna valor
Figura 5.17 Atributos y métodos de la clase NComplejo
Fuente: Propia
Ahora se explicaran las líneas de código de la Figura 5.18
En la línea 1 se declara que esta clase pertenece al paquete llamado
matematicas, porque ahí está la clase fraccion y de esta forma se puede
tener acceso a ella.
En la línea 2 se declara la clase con el nombre de NComplejo, luego en
la línea 3
objetos de tipo Fraccion, aquí esta presente la composición, puesto que un
objeto NComplejo está conformado por objetos de otra clase.
En las líneas de la 4 a 15, se encuentran el constructor de la clase que
esta sobrecargado, existen tres (3), que se diferencian por la lista de
parámetros que recibe cada uno, y ello es lo que determinará cual se ejecuta
en su debido momento, si un objeto se crea del tipo NComplejo y se le
envían dos (2) objetos de tipo Fraccion se ejecutará el primer constructor,
mientras si no se envía ningún parámetro se ejecutará el segundo, y cuando
se envíen cuatro (4) valores de tipo int, entonces se ejecutará el ultimo pero
no menos importante.
1 package matematicas;
2 class NComplejo {
3 Fraccion pReal, pImag;
4 NComplejo ( Fraccion a , Fraccion b ) {
5 pReal = a;
6 pImag = b;
7 }
8 NComplejo ( ) {
9 pReal = new Fraccion ( 1 , 1 ) ;
10 pImag = new Fraccion ( 1 , 1 ) ;
11 }
12 NComplejo ( int a , int b , int c , int d ) {
13 pReal = new Fraccion ( a , b ) ;
14 pImag = new Fraccion ( c , d ) ;
15 }
16 public void sumar ( NComplejo n1 , NComplejo n2 ) {
17 pReal . sumar ( n1 . pReal , n2 . pReal ) ;
18 pImag . sumar ( n1 . pImag , n2 . pImag ) ;
19 }
20 public void sumar ( NComplejo n ) {
21 pReal . sumar ( pReal , n . pReal ) ;
22 pImag . sumar ( pImag , n . pImag ) ; } //fin del método
23 public void restar ( NComplejo n ) {
24 pReal . restar ( n . pReal ) ;
25 pImag . restar ( n . pImag ) ;
26 }
27 }
Figura 5.18 Código fuente de la Clase NComplejo
Fuente: Propia
En las líneas de 16 a 19, está el método sumar que recibe dos (2)
que
es de tipo Fraccion, y con éste se llama al método sumar de dicha clase,
mandándole las dos (2) objetos de tipo Fraccion que ese método espera, que
son la parte Real la
parte Imaginaria.
En las líneas de la 20 a 22, se puede observar el método sumar pero
éste se diferencia del anterior porque recibe sólo un objeto NComplejo, para
que lo sume con el NComplejo que invoca al método, de esta manera con los
atributos del objeto solicitante de la ejecución de éste método sumar, se
invoca el método sumar de la clase Fraccion enviándole la Real del
objeto que invoca y la pReal
pImag .
En las líneas 23 a 26, se encuentra el método restar recibiendo sólo
pReal del objeto que
invoca éste método se llama el método restar de la clase Fraccion
enviándole la pReal pImag ;
culminando así la clase NComplejo.
5.2.4 Resolución de problemas usando programación orientada a
objetos, haciendo énfasis en la abstracción y encapsulación de
datos.
Cree las clases necesarias para describir un consultorio medico, para
dos (2) pacientes por día, donde se maneje la siguiente información
por cada uno: nombre, numero de historia, edad, día y hora de la cita,
y la cantidad de consultas que ha tenido con el doctor; El consultorio
debe tener el nombre del doctor.
. Deberá desarrollar las siguientes operaciones:
Citar un paciente, se debe evitar choque de horario.
Mostrar a los 2 pacientes ordenados según el número de visitas que
le ha hecho al doctor (descendente).
CAPÍTULO VI: ARREGLOS DE OBJETOS
UNIDIMENSIONALES
6.1 Objetivos
Definir los conceptos básicos de arreglos, según una discusión en
clases.
Identificar los tipos de problemas que se pueden resolver
mediante el uso de arreglos, usando programación orientada a
objetos.
Resolver problemas haciendo uso de arreglos unidimensionales
para desarrollar programas orientados a objetos
6.2 Contenido:
Definición de Arreglos. Declaración y creación de arreglos. Tipos
de Arreglos según sus dimensiones.
Aplicación de arreglos en la programación orientada a objetos
Resolución de problemas con programación orientada a objetos
6.2.1 Definición de Arreglos. Declaración y creación de arreglos. Tipos
de Arreglos según sus dimensiones.
Ya se estudio el ejemplo de la clase Fraccion, y la clase NComplejo,
pero que pasaría si se necesitara manejar muchas Fracciones, o muchos
números complejos donde sus partes fueran fracciones? Se podrían declarar
muchos objetos del tipo necesario, aunque no sería optimo, ya que se harían
líneas de código para cada objeto, tanto para declararlos y crearlos, como
para manejarlos, y si se necesitaran menos objetos o mas, se tendría que
modificar todo, añadiendo o borrando los objetos necesarios y sus líneas de
código; para resolver éste problema se usará un arreglo del tipo necesario,
bien sea Fraccion, NComplejo, o de cualquier clase creada previamente;
entonces observe las definiciones siguientes:
Arreglo: según Javier Ceballos, es una estructura homogénea,
compuesta por varios elementos, todos del mismo tipo y almacenados
consecutivamente en memoria. Cada elemento puede ser accedido
directamente por el nombre de la variable matriz seguido de uno y más
subíndices encerrados entre corchetes ( [ ] ). Ver Figura 6.1
Arreglo
Figura 6.1. Representación gráfica de un Arreglo
Fuente propia
Para referirse a una posición determinada de un arreglo es necesario
usar un subíndice, estos dependiendo del lenguaje a usar comenzarán en
uno (1) ó cero (0), en el lenguaje java al igual que en C++ se comienzan en
cero (0); como se puede observar en la Figura 6.2
A A A A A A A
[0] [1] [2] [3] [4] [5]
Figura 6.2. Representación de un Arreglo A de seis (6) posiciones
Fuente propia
Suponga que el arreglo A es de tipo int entonces en cada una de las
seis (6) posiciones almacenará un int, véase la Figura 6.3; estas posiciones
se almacenan consecutivamente en memoria, suponiendo que el arreglo A
se comenzara a almacenar en la posición 2570, y recordando que los datos
tipo int necesitan 4 bytes de memoria para almacenarse.
Posiciones de 2 2 2 2 2 2
memoria: 570 574 578 57C 580 584
A 2 1 5 9 2
5
8 59 7 9 010
Figura 6.3. Representación de un Arreglo A de tipo int de seis (6) posiciones
Fuente propia
Y así cada una de las posiciones del arreglo va almacenar un valor de
tipo del arreglo; el tipo de dato de las posiciones es determinado por el tipo
con el cual se declara el arreglo,
Para declarar un arreglo se debe colocar el tipo de dato, seguido por el
nombre del arreglo, acompañado por un par de corchetes, bien sea en el tipo
de dato ó en el nombre del arreglo.
Ejemplo:
int A[]ó
int [ ] a.
mientras que para crearlo se le debe definir el tamaño usando el operador de
asignación ( = ) seguido de la operador new (que permite reservar un espacio
de memoria para el nuevo arreglo) y luego el tipo de dato nuevamente y
entre corchetes el tamaño o dimensión del arreglo que debe ser un valor
entero y terminar la sentencia con un punto y coma ( ; ).
Ejemplo:
A=new int [ 7 ];
Antes de la creación de cualquier arreglo es imposible usarlo; también
se puede declarar y crear en una misma línea, observe:
double b [ ] = new double[10];
También se pueden inicializar con los valores que almacenará el
arreglo, asignándoselos entre comillas y separados por coma ( , ), de la
siguiente forma:
char
entonces el arreglo x de tipo char, tendrá x [ 0 ] el valor de , x [ 1 ] el de ,
x [ 2 ] el de y x [ 3 ] el valor de .
Los arreglos no solo se pueden representar de una dimensión, llamados
unidimensionales, pueden ser de dos (2) llamados arreglos bidimensionales,
o de más llamados matrices, deben manejar dos subíndices; y se le definen
la cantidad de filas y las de columnas, como se puede observar en la Figura
6.4
long d [ ] [ ] = new long [ 4 ] [ 3 ];
0 1 2
0 d[0][0] d[0][1] d[0][2]
1 d[1][0] d[1][1] d[1][2]
2 d[2][0] d[2][1] d[2][2]
3 d[3][0] d[3][1] d[3][2]
Figura 6.4 Representación de un arreglo d bidimensional de 4x3
Fuente propia
También pueden ser de tres dimensiones, la declaración sería de la
siguiente forma:
tipo_de_dato [ ] [ ] [ ] nombre_del_arreglo = new
tipo_de_dato[filas][columnas][profundidad];
Profundidad
Filas
Columnas
Figura 6.5 Representación de un arreglo de 3 dimensiones (4x3x3)
Fuente propia
Para declarar y crear el arreglo de la Figura 4.5, supóngase que es de
tipo boolean, y se llamara arreglo1, entonces: boolean arreglo1 [ ] [ ] [ ] =
new boolean [ 4 ] [ 3 ] [ 3 ]; En esta asignatura se estudian sólo los arreglos
de una dimensión.
Para recorrer un arreglo usualmente se usa la sentencia cíclica for para
for por dimensión.
Ejemplo
Partiendo de la Figura 6.3. Supóngase que se desea sumar todos los
valores del arreglo A.
for ( int i = 0, suma = 0; i < 6 ; i ++) // A = {5,28,159,57,99,2010}
suma += A[i];
después, de que se ejecute todo el for
valor de 6,
Java considera los arreglos como objetos que además de tener la
capacidad de almacenar varios elementos, dispone de un atributo length que
maneja el numero de elementos que puede almacenar. Usando éste atributo
las instrucciones anteriores queda de la siguiente forma:
for ( int i = 0, suma = 0; i < A . length ; i ++) // A = {5,28,159,57,99,2010}
suma += A[i];
Los arreglos pueden utilizarse como parámetros en los métodos, en el
método se recibe el tipo de dato del arreglo seguido del identificador del
arreglo o nombre, seguido de un par de corchetes vacios,
public void
Es necesario aclarar que los arreglos pasan por referencia, es decir que
toda modificación que sufra el arreglo en el método se va a reflejar en el
arreglo original. Bien ahora si se desea pasar un elemento del arreglo de un
tipo primitivo, este pasa por valor, es decir se saca una copia del valor y esa
es la que recibe el método invocado; mientras si el arreglo es de objetos y
también se necesita enviar sólo una posición, este paso es por referencia,
dado que todos los objetos usan el paso de parámetros por referencia, por
ejemplo:
int arreglo [ ] = { 1 , 2 , 3 , 4 };
modificarArreglo ( arreglo ) ;
// luego, en el método modificarArreglo
public void modificarArreglo( int a [ ] ){
int i ;
for ( i = 0 ; i < a . lenth ; i ++ )
a [ i ] = a [ i ] + 10 ;
}
//Después de la ejecución del método, el valor de arreglo es {10 , 12 ,
13 , 14}
Ahora si al método se envía sólo una posición, del mismo ejemplo
anterior:
modificarElemento ( arreglo [ 0 ] ) ;
//luego en el método
public void modificarElemento ( int x ) {
x=x*2;
}
//Después de la ejecución del método modificarElemento, arreglo = {10 ,
12 , 13 , 14}
//como se ve, el arreglo original no fue modificado.
Los métodos pueden retornar un arreglo, donde el tipo de dato
retornado será el tipo de dato del arreglo con sus respectivos corchetes
indicando que se trata de un arreglo. Ejemplo
public int [ ] sumar ( int a [ ] , int b [ ] ){
int i, arreglo[ ] ;
arreglo=new int [ a.length ];
for ( i = 0; i < a.length ; i ++ )
arreglo [ i ] = a [ i ] + b [i ] ;
return arreglo;
}
Observe que el método sumar, recibe dos arreglos de tipo int, para
sumar los datos almacenados en todas sus posiciones y almacenarlas en
ejemplo a y b deben tener la misma longitud, y todas sus posiciones deben
tener un elemento, de no ser así ocurrirá un error en tiempo de ejecución,
para evitarlo, se puede pasar como parámetro o argumento la cantidad de
elementos contenidos en cada uno de los arreglos, o después de la ultima
posición ocupada colocar un identificador que represente el final del arreglo.
6.2.2 Aplicación de arreglos en la programación orientada a objetos
Java proporciona unas clases para describir cadenas; recordando que
una cadena es una secuencia de caracteres delimitada entre doble comillas,
de dato primitivo char, trabajan con el código Unicode. Java de todas las
clases que tiene para el manejo de cadenas la más usada es la clase String,
cualquier cadena es considerada un objeto de tipo String. Por ejemplo:
String
String
Un String es muy diferente de un arreglo de char,
String
char
si se quiere mostrar por pantalla el valor de las dos variables, el de la
cadena a se mostrará sin ningún problema, mientras que el segundo del
arreglo b se mostrará su equivalente a la dirección de memoria de la variable
b.
La clase String tiene sobrecarga de constructor, por lo tanto un objeto
de este tipo se puede crear de diferentes formas. Ejemplo:
String a = new String // recibe una cadena
String b = new String ( a ) ; //recibe una cadena
char
String c = new String ( c ) ; // recibe un arreglo de
caracteres.
Algunos métodos de la clase String
Tabla 6.1. Métodos de la clase String
Método Cabecera del método Descripción
length int length() Devuelve la cantidad de caracteres
charAt char charAt(int posicion) Devuelve el carácter cuyo índice es:
posición
compareTo int compareTo(String cad2) Compara alfabéticamente dos
cadenas, la que invoca y cad2 que la
recibe, Devuelve un entero (0 si son
iguales; < 0 si alfabéticamente es
menor la que invoca que cad2; y > 0
si cad2 es mayor alfabéticamente
que la que invoca).
Equals boolean equals(String cad2) Devuelve true si la cadena que invoca
es igual alfabéticamente a cad2, toma
en consideración las mayúsculas y
minúsculas.
equalsIgnoreCase Bolean Parecido al anterior pero ignora
equalIgnoreCase(String mayúsculas y minúsculas.
cad2)
Trim String trim() Devuelve la cadena que invoca sin
espacios en blanco.
Fuente propia
A pesar que en la clase String existe un método llamado concat, que
recibe una cadena para concatenarla a la cadena que invoca, también existe
el operador ( + ) que concatena tantas cadenas como sea necesario. Ejemplo
String
Suponga que es necesario almacenar una serie de nombres para
guardar a los estudiantes de una sección de alguna asignatura, es necesario
declarar un arreglo de String, de la siguiente forma:
String nombres [ ] = new String [ 40 ] ;
Entonces cada una de las 40 posiciones va almacenar un String que
será el nombre de uno de los estudiantes de la asignatura en consideración,
ver Figura 6.6.
0 1 2 3 38 39
nombres
Figura 6.6. Arreglo String de tamaño 40
Fuente propia
Las posiciones Figura 4.6, son objetos de la
clase String por lo tanto, cada una se puede tratar como una cadena, usando
sus métodos.
Como se ilustro en el capítulo 3, con las clases se puede crear tipos de
datos propios, no necesariamente de tipos predefinidos por el lenguaje, como
los primitivos, ahora bien, se pueden crear entonces arreglos de esos nuevos
tipos de datos; consideremos el siguiente problema.
Supóngase que se necesite manejar n-simas fracciones, se debe tener
un arreglo de tipo Fraccion ( ver sección3.2.3 del Capítulo III) para manejar
varios objetos de este tipo, su declaración:
Fraccion [ ] b;
Su creación:
b = new Fraccion [ 6 ] ; // tamaño arbitrario 6.
Su representación gráfica, ver Figura 4.7.(a) representación en
memoria; Figura 4.7.(b) Representación gráfica.
Como se observa en la Figura 6.7 (a), los arreglos se almacenan
secuencialmente en memoria; cuando estos son de objetos, y después de
creados se reserva el espacio en memoria según los atributos de los objetos
que conforman dicho arreglo. De la figura como una Fraccion tiene dos
atributos enteros y por cada uno se necesita 4 bytes, entonces se reserva 8
bytes para cada posición creada del arreglo b.
Para la utilización de los arreglos de objetos, se tiene que tener en
cuenta que se debe crear cada una de las posiciones (objetos) para luego
poder utilizarlos, hacer uso de sus atributos e invocar sus métodos, en el
caso que no se cree una posición y se trate de llamar un método con éste,
producirá un error en tiempo de ejecución, porque el objeto en cuestión aun
no existe, no ha sido creado.
En memoria
A0256
A0257
A0258
Arreglo b A0259
A025A
0 Referencia
A025B
1 Referencia
A025C
2 Referencia A025D
3 Referencia A025E
4 Referencia A025F
A0260
5 Referencia
A0261
A0262
A0263
A0264
A0265
A0266
Figura 6.7.(a) Representación en memoria del arreglo b, después de creadas todas las
posiciones
Fuente propia
Un arreglo de objetos brinda la posibilidad de manejar varios objetos
con un mismo nombre; el recorrido se hace similar a un arreglo de tipo
primitivo. Utilizando un ciclo, el más usado es el for aunque también se
puede hacer con while.
Para crear todas las posiciones del arreglo b de tipo Fraccion, se
recorre el arreglo desde la posición cero (0) hasta la cinco (5), de la siguiente
forma:
for ( int i = 0; i < 6 ; i++ )
b [ i ] = new Fraccion( i , i + 2 );
el arreglo b quedaría con los siguientes valores, observe la Figura 6.8:
0 1 2 3 4 5
B
2 3 4 5 6 7
Figura 6.8. Resultado en el arreglo b
Fuente propia
Supongamos que se desea ubicar cual es el contenido de la posición 3
del arreglo, entonces se utiliza el nombre del arreglo seguido de la posición
entre corchetes, es decir, la siguiente instrucción:
Fraccion f = b [3] ; // después de la instrucción f = 3/5
Una excepción es la indicación de un problema que ocurre durante la
ejecución de un programa. El nombre viene porque la instrucción en la
mayoría de las ejecuciones se hace correctamente, pero es posible que en
una ejecución ocurra un error, entonces será la excepción a la regla.
El manejo de las excepciones le permite al programador desarrollar
programas que puedan resolver las excepciones, evitando que la ejecución
del programa termine abruptamente, y se le notifique al usuario del problema,
y ejecute líneas de código diseñadas para tratar el error. Este manejo ayuda
a que los programas sean más robustos.
Ejemplos comunes de excepciones, índices fuera de rango,
desbordamiento aritmético (es decir, un valor fuera del rango representable
de valores), la división entre cero, la asignación fallida de memoria, entre
otros.
Para manejar una excepción, Java ofrece los bloques try, catch y finally;
en el primero try se escriben las instrucciones que puedan lanzar una
excepción, entre llaves ({}); en el bloque catch se desarrollan las
instrucciones que se realizarán en el caso que ocurra una excepción, entre
llaves ({}), este bloque recibe un parámetro que es un objeto de tipo
Exception o perteneciente a una subclase de ésta con el error ocasionado; y
en el bloque finally que es opcional, va el código que siempre se ejecutará,
ocurra o no una excepción, entre llaves ({}). Por ejemplo, supóngase que se
desea dividir dos números leídos, entonces, se declaran tres variables, una
para el resultado y las otras dos para los números.
float resultado, numero1, numero2;
String
numero1 = leerNumero ( ) ;
numero2 = leerNumero ( ) ;
try {
resultado = numero1 / numero2 ; //instrucción que puede dar un error
}
catch ( AritmethicException ae){ //es de la clase que describe las
excepciones aritméticas
se ejecutará si ocurre la excepción.
}
Fíjese que en el ejemplo anterior, el tipo de excepción que recibe el
catch es AritmethicException, entonces este catch sólo se ejecutará cuando
ocurra una excepción de ese tipo, al ocurrir otra excepción no se ejecutará;
para cada try puede existir un catch por cada tipo de excepción que pueda
ser lanzada; aunque por ahora se puede usar un catch que reciba un objeto
de tipo Exception, con esto se asegura que maneje cualquier tipo de
excepción lanzada, ya que ésta clase es la superclase de la jerarquía de
herencia de las excepciones, tema que se abordara en la unidad siguiente.
Con el uso de la clase Exception el bloque catch del ejemplo anterior
quedaría de la siguiente forma:
try {
resultado = numero1 / numero2 ; //instrucción que puede dar un error
}
catch (Exception ae){ //es de la clase Exception..
ejecutará si ocurre la excepción.
}
6.2.3 Resolución de problemas con programación orientada a objetos
usando arreglos
Para resolver un problema en programación orientada a objetos usando
arreglos, se recomienda desarrollar la clase que describa un objeto, luego
desarrollar una que describa el arreglo de objetos, observe el siguiente
problema:
Desarrolle las clases necesaria para almacenar una serie de puntos de
una gráfica (máximo 10 puntos).
Para resolverlo se debe desarrollar una clase Punto y luego una clase
Serie. Observe la Figura 6.9.
grafica
Clase Punto
coordenadaX entero
coordenadaY entero
Constructor Punto ( )
Constructor Punto (entero, entero)
setX (entero) no retorna valor
setY (entero) no retorna valor
getX ( ) entero
getY ( ) entero
compararCon ( Punto ) booleano
cadena ( ) cadena
Figura 6.9. Atributos y métodos de la clase Punto.
Fuente propia
A continuación observe en la Figura 4.10 la clase Punto, partiendo de la
Figura 6.9 y usando los conocimientos obtenidos hasta ahora. Fíjese que
esta en el paquete grafica.
Luego se desarrolla la clase Serie en la cual se describirá el arreglo de
tipo Punto, con un entero máximo para limitar el arreglo, y un entero índice
para llevar el control de cuantos objetos tiene el arreglo; también se definen
los métodos necesarios como ingresar un punto recibiendo un nuevo punto y
uno recibiendo las dos coordenadas que forman el nuevo Punto, otro método
para eliminar un punto del arreglo que recibe las coordenadas del punto a
eliminar, otro método para que retorne una cadena formada por todos los
puntos de la serie; estos son los que tienen mayor relevancia, los demás son
para poder obtener los valores de los atributos fuera de la clase Serie. A
continuación observe en la Figura 6.11 los atributos y métodos de la clase
Serie.
1 package grafica ;
2 public class Punto {
3 private int x,y;
4 public Punto ( ) {
5 x=0;
6 y=0;
7 }
8 public Punto ( int a , int b ) {
9 x=a;
10 y=b;
11 }
12 public void setX ( int a ) {
13 x=a;
14 }
Figura 6.10. Código fuente de la clase Punto(1/2)
Fuente propia
15 public void setY ( int a ) {
16 y=a;
17 }
18 public int getX ( ) {
19 return x;
20 }
21 public int getY ( ) {
22 return y;
23 }
24 public boolean comparaCon ( Punto p ) {
25 return ( x == p . x && y == p . y );
26 }
27 public String cadena ( ) {
28 return " ( " + x + " , " + y + " ) " ;
29 }
30 }
Figura 6.10. Código fuente de la clase Punto(2/2)
Fuente propia
grafica
Clase Serie
coordenadaX entero
coordenadaY entero
Constructor Serie ( )
Constructor Serie (entero)
getPunto ( ) Punto [ ]
getIndice ( ) entero
getMaximo ( ) entero
ingresarPunto ( Punto ) cadena
ingresarPunto ( entero , entero ) cadena
eliminarPunto ( entero , entero ) cadena
Figura 6.11. Atributos y métodos de la clase Serie.
Fuente propia
A continuación la definición de la clase Serie, su código fuente en la
Figura 6.12.
1 package grafica ;
2 public class Serie {
3 private Punto p [ ] ; //declarando el arreglo p
4 private int indice , maximo ;
5 public Serie ( ) {
6 indice = 0 ;
7 maximo = 10 ;
8 p = new Punto [ maximo ] ; //creando el arreglo p
9 }
10 public Serie ( int m ) {
11 indice = 0 ;
12 maximo = m ;
13 p = new Punto [ maximo ] ; //creando el arreglo p
14 }
15 public Punto [ ] getPunto ( ) {
16 return p ;
17 }
18 public int getIndice ( ) {
19 return indice ;
20 }
21 public int getMaximo ( ) {
22 return maximo ;
23 }
24 public String ingresarPunto ( Punto a ) {
25 if ( indice < maximo ) {
26 p [ indice ++ ] = a ;
27 return "El punto " + p [ indice - 1 ].cadena ( ) + " se ha agregado
28 correctamente a la serie" ;
29 }
30 return " La serie esta completa.. " ;
31 }
32 public String ingresarPunto ( int a , int b ) {
33 if ( indice < maximo ) {
34 p [ indice ++ ] = new Punto ( a , b ) ;
Figura 6.12. Código fuente de la clase Serie.(1/2)
Fuente propia
35 return " el punto " + p [ indice - 1 ] .cadena ( ) + " se ha
36 agregado correctamente a la serie";
37 }
38 return " La serie esta completa.. " ;
39 }
40 public String eliminarPunto ( int a , int b ) {
41 int i ;
42 for ( i = 0 ; i < indice ; i ++)
43 if ( p [ i ] . comparaCon ( new Punto ( a , b ) ) ) {
44
45 for ( ; i < indice - 1 ; i ++ )
46 p[i]=p[i+1];
47 indice -- ;
48 return " El Punto (" + a + " , " + b +") fue eliminado de la serie" ;
49 }
50 return " El punto ( " + a + " , " + b + " ) no se encontró en la serie" ;
51 }
52 public String cadena ( ) {
53 String x = "" ;
54 int i ;
55 for ( i = 0 ; i < indice ; i ++ )
56 x = x + p[ i ] . cadena ( ) + " \n " ;
57 return " { " + x + " } " ;
58 }
59 }
Figura 6.12. Código fuente de la clase Serie.(2/2)
Fuente propia
Como se puede apreciar en la Figura 6.12. En la línea 1 se define que
esta clase pertenece al paquete grafica.
como el arreglo de la clase Punto (Línea 3), también se declaran dos (2)
enteros, uno para controlar cuantos elementos hay en el arreglo ( )y
el otro para guardar el máximo de elementos del arreglo ( ); a estos
se le asigna el tamaño en los constructores que se encuentran en las líneas
de la 5-9 y de la 10-14, también se asigna el valor de cero para el atributo
En las siguientes líneas de la 15-17 y de la 18- 20 y de la 21-23, se
encuentran los métodos get para que desde fuera de esta clase se puedan
utilizar los valores de los atributos ya que son de tipo de acceso privados.
En las líneas 24 a
recibe un nuevo objeto de tipo Punto que es el que se va almacenar en el
arreglo, lo primero que hace en este método es verificar que exista espacio
disponible en dicho arreglo, y retorna un mensaje para notificar si se pudo
ingresar o si todas las posiciones del arreglo están ocupadas, en este ultimo
gres
recibe dos (2) datos tipo enteros.
coordenadas que conforman el punto a eliminar del arreglo, esto se logra
recorriendo el arreglo (línea 42) y comparando si las coordenadas recibidas
son iguales a todas y cada unas a las correspondientes de los puntos del
arreglo (línea 43), en el instante que se halle el punto se recorre el arreglo
desde la posición ocupada por éste hasta la ultima posición que este
ocupada (línea 44), sobrescribiendo el punto a eliminar por el siguiente y así
sucesivamente hasta la ultima posición (línea 45), luego se debe actualizar la
cantidad de objetos del arreglo que esta almacenada en el atributo y/o
ncontrar el
punto se retorna un mensaje informando que la eliminación fue un éxito
(línea 47); en caso contrario, de no hallar dicho punto en el arreglo entonces
se retorna un mensaje informando que el punto no existía en la serie (línea
50).
El ultimo método de la clase es el cadena que retorna todos y cada
uno de los puntos que conforman la serie(Línea 52), para esta tarea se lleva
a cabo un for para recorrer el arreglo (línea 55), y dentro de éste se va
utos de los puntos (línea 56),
para al final 7).
Fíjese que en esta clase Serie se hace uso de composición, por lo tanto
para acceder a los atributos de cada punto es necesario usar los métodos
CAPÍTULO VII: HERENCIA Y POLIMORFISMO
7.1 Objetivos
Definir los conceptos básicos relacionados con herencia en la
programación orientada a objetos, basándose en investigación
previa y discusión en clases.
Identificar las superclases y subclases de problemas resueltos
mediante el uso de herencia en programación orientada a
objetos.
Resolver problemas haciendo uso de herencia para desarrollar
programas orientados a objetos.
Definir los conceptos básicos relacionados con polimorfismo en la
programación orientada a objetos, basándose en investigación
previa y discusión en clases.
Reconocer los elementos básicos relacionados a polimorfismo en
problemas resueltos usando polimorfismo en programación
orientada a objetos.
Resolver problemas haciendo uso de polimorfismo para
desarrollar programas orientados a objetos
7.2 Contenido
Definición de herencia. Definición de superclase y subclases.
Relación entre superclase y subclases en un programa resuelto
usando herencia.
Resolución de problemas con programación orientada a objetos
usando herencia.
A Definición de polimorfismo. Definición de clases y métodos
abstractos
Problemas resueltos con programación orientada a objetos usando
polimorfismo
Resolución de problemas con programación orientada a objetos
usando polimorfismo
7.2.1 Definición de herencia. Definición de superclase y subclases.
Las características fundamentales de la programación orientada a
objetos son abstracción, encapsulamiento, herencia y polimorfismo. Hasta
ahora sólo se ha abordado la abstracción y la encapsulación.
La herencia provee el mecanismo más simple para especificar una
forma alternativa de acceso a una clase existente, o bien para definir una
nueva clase que añada nuevas características a una que ya exista.
La herencia permite definir nuevas clases usando como base las ya
existentes, la nueva clase hereda los atributos y comportamiento de la que
existe.
La herencia es una herramienta poderosa que proporciona un marco
adecuado para producir software fiable, comprensible, de bajo coste,
adaptable y reutilizable.
Esta nueva clase se denomina subclase, clase derivada o clase hija y
la clase existente, superclase, clase base o clase padre.
Con la herencia todas las clases están clasificadas en una jerarquía.
Cada clase tiene la superclase (la clase superior en la jerarquía) que
necesite, y cada clase puede tener una o más subclases (las clases
inferiores en la jerarquía). Las clases que están en la parte inferior en la
jerarquía se dice que heredan de las clases que están en la parte superior.
Existe herencia simple y múltiple; en la simple una subclase sólo puede
tener una superclase, aunque una superclase puede tener más de una
subclase. En la Figura 7.1. Se puede observar como la superclase es
Empleado con los atributos: nombre y numSegSoc , éste último representa
el número del seguro social de los Empleados, mientras las subclases son
Gerente y Supervisor que heredan todos los atributos y todos los métodos de
la clase Empleado.
Mientras en la herencia múltiple se permite que cada subclase pueda
tener más de una superclase. Ver Figura 7.2. En ésta figura se observa que
existen dos superclases Docente y Estudiante, y una subclase Preparador
donde Preparador hereda de las dos superclases.
El lenguaje Java sólo soporta herencia simple, no se puede tener
una subclase que herede de más de una clase como en la Figura 7.2.
Por lo tanto como ese es el lenguaje elegido para ejemplificar la
asignatura, se limitara a estudiar herencia simple.
Clase Empleado
nombre cadena
numSegSoc cadena
Clase Gerente Clase Supervisor
nombre cadena nombre cadena
numSegSoc cadena numSegSoc cadena
Figura 7.1. Jerarquía de herencia simple
Fuente propia
Clase Docente Clase Estudiante
asignatura cadena promGral cadena
salario cadena credAprob cadena
Clase Preparador
Figura 7.2. Jerarquía de herencia múltiple
Fuente propia
es un
7.1. Un Gerente es un Empleado y también un Supervisor es un
Empleado, de la Figuro 5.2 un Preparador es un Docente y también es un
Estudiante. La herencia es transitiva, lo que indica que si en una
jerarquía de herencia como la de la Figura 7.1. se le añade la clase
Persona, para que la clase empleado herede de ella, entonces como:
Se puede observar la transitividad, La herencia es unidireccional, si
empleado hereda de Persona es imposibles que Persona herede de
Empleado.
En el lenguaje Java existe una clase llamada Object, es la clase raíz de
la jerarquía de clases de la biblioteca Java; pertenece al paquete java.lang.
Así mismo, cualquier clase que se implemente pasará a ser automáticamente
una subclase de esta clase. Todos los métodos de Object son heredados por
las clases de la biblioteca Java y por cualquier otra clase que se incluya en
un programa. Tres de estos métodos son wait, notify y notifyAll para el control
de hilos en la programación concurrente tema ajeno a los objetivos de esta
asignatura; otros son getClass (para obtener la clase a la cual pertenece el
objeto) y clone (para sacarle una copia al objeto que lo invoque), equals
(para comparar dos objetos, retorna un boolean), toString (para devolver el
objeto en forma de cadena) y finalize (para el recolector de basura). Todos
estos métodos se pueden sobrescribir en las clases adaptándolo a las
necesidades presentes.
La Funcionalidad de la herencia en ocasiones tiende a confundir a los
aprendices de programación orientada a objetos, puesto que se piensa en
que cuando la subclase hereda los atributos de la superclase, es similar a
que en los atributos de una clase exista un objeto de otra, definida
anteriormente; para diferenciar las características se usan tanto la relación
es un tiene un es un
describir la herencia un objeto de la subclase es un objeto de la superclase, y
tiene un es para describir la composición un objeto de la nueva clase tiene un
objeto de la clase declarada con anterioridad, partiendo de las Figuras 3.4 y
5.1.
1. ¿ Un Automóvil tiene un Motor ?
2. ¿ Un Automóvil es un Motor ?
3. ¿ Un Supervisor tiene un Empleado ?
4. ¿ Un Supervisor es un Empleado ?
Las respuestas a las interrogantes son:
1. si, es composición.
2. no.
3. no.
4. si, es herencia.
Porque un Automóvil no es un Motor es mucho más, aunque el Motor lo
conforma también tiene caja, neumáticos, chasis, entre otros. Mientras que
un gerente no puede tener un Empleado, sin embargo es un Empleado; el
uso de estas relaciones ayuda a visualizar en qué momento se debe usar
herencia o composición, solo se tienen que hacer dos interrogantes, y según
sean las respuestas se usa herencia ó composición.
7.2.2 Relación entre superclase y subclases en un programa resuelto
usando herencia.
Es importante que las superclases y subclases estén o en el mismo
paquete o se importe el paquete donde este la superclase para poder usarla.
Supóngase el siguiente enunciado de problema.
maneja la siguiente información: código y precio. Un producto puede ser de
limpieza ó de alimentación, en los de limpieza se tiene también un
ingrediente activo, y en los de Alimentación se tiene también la año de
vencimiento
Para resolver este ejercicio, lo primero es identificar las clases, es decir
la clasificación, y éstas son: Producto, DeAlimentación y DeLimpieza, para la
jerarquía de herencia, la superclase es Producto y las subclases
DeAlimentación y DeLimpieza. Ver Figura 7.3.
A continuación los códigos fuentes que le corresponde a las clases que
conforman la jerarquía de herencia, en la Figura 7.4. La superclase Producto,
se desarrolla normalmente como se vio en los ejemplos anteriores.
articulos
Clase Producto
codigo cadena
precio real
Producto ( )
Producto(cadena , real )
setCodigo(cadena) no retorna valor
setPrecio(real) no retorna valor
getCodigo() cadena
getPrecio() real
cadena( ) cadena
Clase Delimpieza Clase DeAlimentacion
ingredienteAct cadena añoVenc entero
DeLimpieza( cadena , real , cadena ) DeAlimentacion ( cadena , real , entero
setIngredienteA(cadena) no retorna valor )
getIngredienteA( ) cadena setAñoVenc(entero) no retorna valor
cadena ( ) cadena getañoVenc( ) entero
cadena( ) cadena
Figura 7.3. Jerarquía de herencia del ejercicio propuesto
Fuente propia
1 package articulos ;
2 import caracteristicas ;
3 public class Producto {
4 private String codigo;
5 private float precio;
6 public Producto ( ) {
7
8 precio = 0 . 0 f ;
9 }
10 public Producto ( String c , float p ) {
11 codigo = c ;
12 precio = p;
13 }
14 public void setCodigo ( String a ) {
15 codigo = a ;
16 }
17 public void setPrecio ( float a ) {
18 precio = a ;
19 }
20 public String getCodigo ( ) {
21 return codigo ;
22 }
23 public float getPrecio ( ) {
24 return precio ;
25 }
26 public String cadena ( ) {
27 return
28
29 }
30 }
Figura 7.4. Código fuente de la clase Producto.
Fuente propia
Seguidamente las subclases DeLimpieza (Figura 7.5) y DeAlimentacion
(Figura 7.6), observe que éstas en la línea 1 de cada clase, se puede
observar extends una palabra reservada, que indica que la clase que se esta
declarando es una subclase del nombre de clase que le sigue, en este caso
la superclase Producto, así se codifica la herencia en Java; luego en los
constructores la primera instrucción con la que se topa es { super ( c ,
p ); } (en la línea 5, de las Figuras 7.5 y 7.6 ) que indica la llamada al
constructor de la superclase y se le envía todos los parámetros que recibe.
También en los métodos cadena, se tiene un {super . cadena ()} (Línea 14 de
las Figuras 7.5 y 7.6) esto hace que se ejecute el método cadena de la
superclase y concatene esa cadena con lo demás.
1 package articulos ;
2 public class DeLimpieza extends Producto {
3 private String ingredienteAct;
4 public DeLimpieza (String c , float p , String ing ) {
5 super ( c , p ) ;
6 ingerdienteAct = ing ;
7 }
8 public void setIngredienteA ( String a ) {
9 ingredienteAct = a ;
10 }
11 public String getIngredienteA ( ) {
12 return ingredienteAct ;
13 }
14 public String cadena ( )
15 return super . cadena ( )
16
17 }
18 }
Figura 7.5. Código fuente de la clase DeLimpieza.
Fuente propia
Del ejercicio anterior se puede observar que con respecto a la sintaxis,
la superclase se desarrolla como las clases tradicionales que se han
ilustrado hasta ahora; mientras que las subclases se le coloca la palabra
reservada extends en la declaración de las mismas, y en el constructor de
éstas la primera instrucción tiene que ser el llamado al constructor de la
superclase, enviándole los parámetros necesarios.
1 package artículos ;
2 public class DeAlimentacion extends Producto{
3 private int añoVenc;
4 public DeAlimentacion (String c , float p , int a ) {
5 super ( c , p ) ;
6 añoVenc = f ;
7 }
8 public void setAñoVenc (int a ) {
9 añoVenc = a ;
10 }
11 public int getAñoVenc ( ) {
12 return añoVenc ;
13 }
14 public String cadena ( ) {
15 return super . cadena ( )
16 año de
17 }
18 }
Figura7.6. Código fuente de la clase DeAlimentacion
7.2.3 Resolución de problemas con programación orientada a objetos
usando herencia
Realice las clases necesarias para describir la siguiente jerarquía
persona, Estudiante y profesor, cada una de las clases con al menos
dos (2) atributos y al menos dos (2) métodos diferentes a los
constructores, set, get, y cadena.
7.2.4 Definición de polimorfismo. Definición de clases y métodos
abstractos.
Polimorfismo es la facultad de asumir muchas formas, en el paradigma
de Programación Orientado a Objetos se refiere a la facultad de llamar a
muchos métodos diferentes utilizando una única sentencia.
El polimorfismo permite que diferentes objetos respondan de modo
diferente al mismo mensaje. Éste parte de la herencia, porque existe una
subclase y de una a varias subclases.
Para hacer uso del polimorfismo es necesaria una clase abstracta, que
no es más que la representación de conceptos generales, que engloban las
características comunes de un conjunto de objetos. Por ejemplo Empleado
es un contexto de trabajadores, es una clase general que engloba las
propiedades y métodos comunes a todo tipo de empleado que trabaja en una
empresa. La clase general Empleado, no es necesario que se instancie, es
decir, que se cree un objeto de este tipo, si existe Gerente, Obrero,
Supervisor, entre otros, para que declarar un Empleado mejor se utilizan las
subclases.
Para definir la clase general (superclase) se necesita la palabra
reservada abstract que es un modificador para definir clases y métodos
abstractos; en una clase abstracta debe existir de uno a varios métodos
abstractos, éstos solo se declaran en la superclase, mientras su definición se
desarrolla en las subclases; la clases abstractas también pueden contener
variables de instancia y de clase, al igual que métodos de instancias y de
clases.
Para definir una clase abstracta se hace de la siguiente forma:
abstract class Identificador_de_la_clase { . . . }
Por ejemplo:
abstract class Empleado { . . . }
Mientras que las subclases:
class Gerente extends Empleado { . . . }
como se puede observar las subclases se definen al igual que con herencia.
Esta definición se hace dentro de la clase abstracta, porque estos
métodos pueden estar declarados únicamente en las clases abstractas, y su
definición en las subclases.
Como se puede observar en la Figura 7.7, en la línea 2 se declara la
clase Empleado como abstracta; luego se definen los atributos de la clase
(líneas 3 y 4); en las líneas 5 a 8 esta el constructor de la clase; en las líneas
atributo sueldo desde fuera de ésta clase; en la línea 15 esta la declaración
del método abstracto, que es de tipo de acceso público, no retornara ningún
ver que finaliza con punto y coma porque esta sentencia termino; y por ultimo
en la línea 16 se encuentra el método cadena. A continuación las subclases,
observe la Figura 7.8.
1 package empresa ;
2 abstract class Empleado{
3 private String nombre;
4 private float sueldo;
5 Empleado( String n , float s ) {
6 nombre = n ;
7 sueldo = s ;
8 }
9 public void setSueldo (float s) {
10 sueldo = s ;
11 }
12 public float getSueldo ( ) {
13 return sueldo ;
14 }
15 public abstract void calcularSueldo ( ) ;
16 public String cadena ( ) {
17 return
18 sueldo; } /*fin del método*/ } //fin de la Clase
Figura 7.7. Código fuente del ejemplo de la clase abstracta Empleado.
Fuente propia
1 package empresa ;
2 class Gerente extends Empleado {
3 private String sucursal;
4 Gerente ( String n , float s , String su ) {
5 super ( n , s ) ;
6 sucursal = su;
7 }
8 public void calcularaSueldo ( ) {
9 setSueldo ( getSueldo ( ) getSueldo ( ) * 0.1 + 300 ) ;
10 }
11 public String cadena ( ) {
12 return super .
13 } /*fin del método*/ } //fin de la clase
Figura 7.8. Código fuente del ejemplo de la subclase Gerente.
Fuente propia
En la Figura 7.8. Se puede ver en la línea 1 la declaración del paquete
empresa; luego la línea 2 la declaración de la clase Gerente como subclase
de Empleado; en la línea 3 se declara el atributo sucursal ; en las líneas 4 a
7 el constructor con la primera instrucción invocando al constructor de la
superclase; en la línea 8 se encuentra la definición del método abstracto que
hereda, es decir, con las instrucciones que lo conforman; y por ultimo en la
línea 11 el método cadena.
Si en una subclase no se define el método abstracto de la superclase,
entonces ésta debe ser abstracta también; y la subclase de ésta debe definir
los de la primera superclase y los de la segunda, supóngase
abstracta clase A
abstracto metodo1( ) no retorna valor
clase B
metodo2 ( ) entero
Figura 7.9. Ejemplo de polimorfismo
Fuente propia
Como se observa en la Figura 7.9. La clase B hereda de la clase A que
es abstracta, y en la subclase B no se redefine el método1, esto producirá un
error para solucionarlo (a) se debe redefinir el método o (b) la clase B debe
ser abstracta también, vea Figura 7.10.
abstracta clase A
abstracto metodo1( ) no retorna valor
clase B
metodo2 ( ) int
metodo1 ( ) no retorna valor
Figura 7.10. (a) Solución 1 del Ejemplo de polimorfismo
Fuente propia
abstracta clase A
abstracto metodo1( ) no retorna valor
abstracta clase B
metodo2 ( ) entero
Figura 7.10. (b) Solución 2 del Ejemplo de polimorfismo
Fuente propia
La funcionalidad del polimorfismo será explicada con un ejemplo, de las
Figuras 7.8 y 7.9, supóngase que existen otras dos subclases, una para
Supervisor y otra para Obrero; si la empresa necesita manejar todo el
personal en un arreglo, en éste debe haber Gerentes, Supervisores y
Obreros, entonces se puede hacer un arreglo para cada subclase, pero
también se puede declarar un arreglo de tipo de la superclase abstracta
Empleado, y cada posición crearla como un tipo de dato de las subclase;
luego recorrer el arreglo e invocar el método definido en todas las subclases
calcularSueldo( ), porque el método que se ejecute corresponderá a la
subclase que pertenezca la posición del arreglo en un momento dado.
Observe la Figura 7.11. Donde se tiene un arreglo E de tipo
Empleado, y en cada posición esta un objeto perteneciente a las distintas
subclases, Gerente, supervisor y Obrero, Ejemplo
Empleado E [ ] = new Empleado [ 4 ] ;
E [ 0 ] = new Gerente ( ) ;
E [ 1 ] = new Obrero ( ) ;
E [ 2 ] = new Supervisor ( ) ;
E [ 3 ] = new obrero ( ) ;
int in ;
for ( in = 0; in < E . length ; in ++ )
E [ in ] . calcularSueldo ( ) ; //sin importar de que tipo es E [ in ].
0 1 2 3
Arreglo E Gerente Obrero Supervisor Obrero
Figura 7.11. Representación de un arreglo de Empleados.
Fuente propia
De esta forma se calcula el sueldo de todos los empleados del arreglo.
Para mayor información, Ver el punto 7.2.6.
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ón.
Se trata de declarar métodos abstractos y constantes que
posteriormente puedan ser implementados de diferentes maneras según las
necesidades de un programa.
Declaración
Para declarar una interfaz se utiliza la sentencia interface, de la misma
manera que se usa la sentencia class; observe Figura 5.12.
1 interface MiInterfaz {
2 int CONSTANTE = 100;
3 int metodoAbstracto ( int parametro ) ;
4 }
Figura 7.12. Código fuente de la interface MiInterfaz
Fuente propia
Se observa en la declaración que las variables adoptan la declaración
en mayúsculas, pues en realidad actuarán como constantes final. En ningún
caso estas variables actuarán como variables de instancia.
Por su parte, los métodos tras su declaración presentan un punto y
coma, en lugar de su cuerpo entre llaves. Son métodos abstractos, por tanto,
métodos sin implementación
Implementación de una interfaz
Como ya se ha visto, las interfaces carecen de funcionalidad por no
estar implementados sus métodos, por lo que se necesita algún mecanismo
para dar cuerpo a sus métodos.
La palabra reservada implements utilizada en la declaración de una
clase indica que la clase implementa la interfaz, es decir, que asume las
constantes de la interfaz, y codifica sus métodos; ver Figura 7.13.
1 class ImplementaInterfaz implements MiInterfaz {
2 int multiplicando = CONSTANTE ;
3 int metodoAbstracto ( int parametro ) {
4 return ( parametro * multiplicando ) ;
5 }
6 }
Figura 7.13. Código fuente de la clase que implementa a la interface MiInterfaz
Fuente propia
En este ejemplo se observa que han de codificarse todos los métodos
que determina la interfaz (metodoAbstracto( )), y la validez de las constantes
(CONSTANTE) que define la interfaz durante toda la declaración de la clase.
Una interfaz no puede implementar otra interfaz, aunque sí extenderla
(extends) ampliándola.
Herencia múltiple de Interfaz
Java es un lenguaje que incorpora herencia simple de implementación
pero que puede aportar herencia múltiple de interfaz. Esto posibilita la
herencia múltiple en el diseño de los programas Java.
Una interfaz puede heredar de más de una interfaz antecesora.
interface InterfazMultiple extends Interfaz1 , Interfaz2 { }
Una clase no puede tener más que una superclase, pero puede
implementar más de una interfaz:
class MiClase extends SuPadre implements Interfaz1 , Interfaz2 { }
El ejemplo típico de herencia múltiple es el que se presenta con la
herencia en diamante, ver Figura 7.14:
Figura 7.14. Ejemplo de herencia múltiple con interfaces
Fuente propia
De la Figura 7.14. Para poder llevar a cabo un esquema como el
anterior en Java es necesario que las clases A, B y C de la figura sean
interfaces, y que la clase D sea una clase (que recibe la herencia múltiple):
interface A{ }
interface B extends A{ }
interface C extends A{ }
class D implements B,C{ }
Colisiones en la herencia múltiple de Interfaces
En una herencia múltiple, los identificadores de algunos métodos o
atributos pueden coincidir en la clase que hereda, si dos de las interfaces
padres tienen algún método o atributo que coincida en nombre; a esto se le
llama colisión.
Esto se dará cuando las clases padre (en el ejemplo anterior B y C)
tienen un atributo o método que se llame igual. Java resuelve el problema
estableciendo una serie de reglas.
Para la colisión de nombres de atributos, se obliga a especificar a qué
interfaz base pertenecen al utilizarlos.
Para la colisión de nombres en métodos:
Si tienen el mismo nombre y diferentes parámetros: se produce
sobrecarga de métodos permitiendo que existan varias maneras de llamar al
mismo.
Si sólo cambia el valor devuelto: se da un error de compilación,
indicando que no se pueden implementar los dos
Si coinciden en su declaración: se elimina uno de los dos, con lo que
sólo queda uno.
7.2.5 Problemas resueltos con programación orientada a objetos
usando polimorfismo.
Desarrolle las clases necesarias para describir la siguiente
jerarquía: Figura Geométrica, Rectángulo, y Circulo; para que
almacene N figuras y calcule el área de cada una.
Para resolver este problema se debe definir las clases a desarrollar,
como se observa en la Figura 7.15, representación de la jerarquía de
herencia de las figuras geométricas, se tiene la superclase abstracta
las subclases
Rectangulo y Circulo, con sus variables, métodos de instancias, y la
Figurageometrica.
Todas las clases tanto la superclase como las subclases pertenecen al
paquete fi
pertenece a éste paquete, en ésta clase se define un arreglo del tipo
FiguraGeometrica aunque esta clase no puede ser instanciada en la
declaración y creación de un arreglo no hay instanciación puesto que un
arreglo es una colección de variables con un mismo nombre, lo que no se
puede hacer es crear una de las posiciones del arreglo como
FiguraGeometrica, porque así si producirá un error, pero mientras las
posiciones del arreglo se creen utilizando una de las subclases que no sean
abstractas, todo marchara bien.
A continuación el código fuente que corresponde a las clases
FiguraGeometrica Figura 7.16
Como se puede observar en la Figura 7.16, en la línea 2, se define la
clase como abstracta, esto indica que debe contener al menos un método
abstracto, que su declaración se encuentra en la línea 10, de tipo de acceso
recibir parámetros.
figuras
abstracta clase FiguraGeometrica
area real
Constructor FiguraGeometrica ( )
getArea ( ) real
abstracto setArea ( ) no retorna valor
clase Rectangulo clase Circulo
base real
altura real radio real
Constructor Rectangulo ( real , real ) Constructor Circulo ( real )
setBase ( real ) no retorna valor setRadio ( real ) no retorna valor
setAltura ( real ) no retorna valor getRadio ( ) real
getBase ( ) real setArea( ) no retorna valor
getAltura ( ) real cadena ( ) cadena
setArea( ) no retorna valor
cadena ( ) cadena
Figura 7.15. Representación de las figuras geométricas
Fuente propia
Los códigos fuentes de las clases Rectangulo y Circulo están
desarrollados en las Figuras 7.17 y 7.18, en estas se puede observar en las
respectivas línea 2 de cada clase que heredan de la clase abstracta con la
palabra reservada para definir la herencia extends, y en la línea 5 esta el
llamado al constructor de la superclase, y en la línea 21 y 14 de cada clase
instrucciones corresponden a la fórmula para calcular el área de cada figura.
1 package figuras;
2 public abstract class FiguraGeometrica {
3 protected float area;
4 public FiguraGeometrica() {
5 area = 0.0f ;
6 }
7 public float getArea ( ) {
8 return area ;
9 }
10 public abstract void setArea ( ) ;
11 public String cadena ( ) {
12 return "tiene un area de " + area ;
13 }
14 }
Figura 7.16. Código fuente de la clase abstracta FiguraGeometrica
Fuente propia
En la clase circulo (Línea 15 de la Figura 7.18) se usa la constante “PI
definida en la clase Math como un double, para multiplicarla con valores float
y almacenarla en uno de ellos existe perdida de precisión por esta razón se
debe hacer una conversión explicita a float.
1 package figuras;
public class Rectangulo extends FiguraGeometrica {
2
private float base , altura ;
3 public Rectangulo( float b , float a) {
super ( ) ;
4
base = b;
5
altura = a;
6
}
7
public void setBase ( float a ) {
8
base = a;
9
}
10
public void setAltura ( float a ) {
11
altura = a;
12
}
13
public float getBase ( ) {
14
return base ;
15
}
16
public float getAltura ( ) {
17
return altura ;
18
}
19
public void setArea( ) {
20
area = base * altura ;
21
}
22
public String cadena ( ) {
23
return "El Rectangulo de " + base+ "x" + altura+ super. cadena ( ) ;
24
}
25
}
26
27
Figura 7.17. Código fuente de la subclase Rectangulo
Fuente propia
1 package figuras;
2 public class Circulo extends FiguraGeometrica{
3 private float radio ;
4 Circulo ( float r ) {
5 super ( ) ;
6 radio = r ;
7 }
8 public void setRadio ( float r ) {
9 radio = r ;
10 }
11 public float getRadio ( ) {
12 return radio ;
13 }
14 public void setArea ( ) {
15 float aux = (float)Math . PI ;
16 area = 2 * aux *radio ;
17 }
18 public String cadena ( ) {
19 return " El Circulo de radio " + radio + super . cadena ( ) ;
20 }
21 }
Figura 7.18. Código fuente de la subclase Circulo.
Fuente propia
En la siguiente figura (Figura 7.19), se encuentra el código fuente de la
clase FigurasG, que pertenece al paquete figuras, en la línea 3 se declara el
arreglo de tipo FiguraGeometrica, para que se puedan almacenar figuras
tanto Rectangulos como Circulos, también se declaran dos enteros uno
para controlar cuantas figuras geometricas almacena el arreglo en un
valor entero que recibe el constructor, también se le asigna este mismo
valor cero (0), porque inicialmente el arreglo no contiene figuras; en la línea
recibe un
objeto declarado como FiguraGeometrica para que pueda almacenar un
objeto creado de cualquier tipo de las subclases de ésta, en este caso
Rectangulo ó Circulo, luego dentro de este método, en las líneas 14 y 16, se
pregunta a que clase pertenece el objeto con los métodos getClass”
perteneciente a la clase Object que retorna la clase con el nombre de los
getSimpleName()” retorna sólo el nombre
de la clas
encuentre, depende a que subclase pertenece, se invoca el método
1 package figuras;
2 public class FigurasG {
3 FiguraGeometrica fg [ ] ;
4 int in , max ;
5
6 public FigurasG ( int n ) {
7 fg = new FiguraGeometrica [ n ] ;
8 max = n ;
9 in = 0 ;
10 }
Figura 7.19. Código fuente de la clase figurasG que describe el arreglo (1/2)
Fuente propia
11 public String ingresarF ( FiguraGeometrica f ) {
12 String x = " " ;
13 if ( in < max )
14 if ( f . getClass ( ). getSimpleName ( ). equals(" Rectangulo ") )
15 x = ingresarR ( ( Rectangulo ) f ) ;
16 else if (f.getClass( ). getSimpleName( ). equals ( "Circulo"))
17 x = ingresarC ( ( Circulo ) f ) ;
18 return x ;
19 }
20 public String ingresarR ( Rectangulo r ) {
21 fg [ in ++ ] = new Rectangulo ( r . getBase ( ) , r . getAltura ( ) ) ;
22 return " El Rectángulo se ha creado satisfactoriamente ";
23 }
24 public String ingresarC ( Circulo r ) {
25 fg [ in ++ ] = new Circulo ( r . getRadio ( ) ) ;
26 return " El Circulo se ha creado satisfactoriamente " ;
27 }
28 public String cadena ( ) {
29 String x = " " ;
30 for ( int i = 0 ; i < max ; i ++ )
31 x = x + fg [ i ] . cadena ( ) + " \n " ;
32 return x ;
33 } /* fin del método */ } //fin de la Clase
Figura 7.19. Código fuente de la clase figurasG que describe el arreglo(2/2)
Fuente propia
7.2.6 Resolución de problemas con programación orientada a objetos
usando polimorfismo.
La Empresa QWX2000 c.a. desea saber el sueldo que se le debe pagar
a un empleado en la semana. Tomando en cuenta lo siguiente:
A un Obrero una hora extra es pagada como el 10% de su sueldo base,
se le descuenta 2% por seguro social, 3% por Ley política habitacional y 5%
por paro forzoso. Mientras que a un Supervisor una hora extra es pagada
como el 4% de su sueldo base, se le descuenta 3% por seguro social, 5%
por Ley política habitacional, 6% por paro forzoso y se le es asignado un
bono de Bs. 50.000 por cumplimiento de horario; y a un Gerente se le asigna
un bono de 10% al mes, por ser personal de confianza, se le descuenta 10%
por seguro HCM, 9% por Ley política habitacional Realizar un programa en
java que calcule el sueldo total que debe percibir un empleado.
CAPÍTULO VIII: USO DE INTERFAZ GRÁFICA DE USUARIO
8.1 Objetivos
Definir Interfaz gráfica de usuario basado en una investigación
previa y discusión en clases.
Definir componentes que conforman la interfaz grafica de usuario,
según discusión en clases.
Identificar componentes que conforman la interfaz grafica de
usuario, usando programación orientada a objetos.
Resolver problemas haciendo uso de interfaz grafica de usuario y
manejo de eventos para desarrollar programas orientados a
objetos.
8.2 Contenido
Definición interfaz grafica de usuario.
Definición de los componentes que conforman la interfaz grafica
de usuario.
Ejemplos de los componentes que conforman la interfaz grafica
de usuario en la programación orientada a objetos.
Resolución de problemas usando interfaz gráfica y manejo de
eventos en programación orientada a objetos.
Definición interfaz grafica de usuario.
8.2.1 Interfaz gráfica de usuario
El concepto de interfaz es un concepto amplio que ha sido definido,
según el ámbito de conocimientos, desde varios puntos de vista: desde la
separa su interior del exterior, desde la electrónica y las telecomunicaciones,
Si vamos al origen de la palabra interfaz se encuentra una palabra
compuesta, por dos vocablos:
lo tanto una traducción literal del concepto de interfaz atendiendo a su
En el contexto de la interacción persona-computador, se habla de
interfaz de usuario, para referirse de forma genérica al espacio que media la
relación de un sujeto y un ordenador o sistema interactivo. La interfaz de
una persona interactuar con él.
Cuando se habla de interfaz gráfica de usuario (GUI), el concepto es
aún más específico en cuanto que interfaz gráfico de usuario al contrario que
interfaz etimológicamente supone la cara o superficie mediadora, el interfaz
gráfico de usuario, supone un tipo específico de interfaz que usa metáforas
visuales y signos gráficos como paradigma interactivo entre la persona y el
computador. La interfaz gráfica, da pistas sobre el modelo de interacción y la
tipología de signos que contiene esta superficie mediadora.
Una interfaz gráfica de usuario (GUI) presenta un mecanismo amigable
al usuario para interactuar con un programa; ya que a este último le
proporciona una apariencia visual única. Al proporcionar distintos programas
en los que componentes de la interfaz de usuario sean consistentes e
intuitivos, los usuarios pueden familiarizarse con un programa incluso antes
de utilizarlo. Esto, a su vez, reduce el tiempo que requieren para aprender a
usar un programa y aumenta su habilidad para utilizar el programa en una
manera productiva.
Uno de los principales objetivos de este tipo de entornos es minimizar el
tiempo de aprendizaje de la aplicación para el usuario. Sin embargo, desde
el punto de vista del programador, ha supuesto un importante giro en la
filosofía tradicional de programación.
API (Application Programming Interface o Interfaces de programación
de aplicación), éstas no son más que colecciones de clases existentes en las
ambién se conocen como
bibliotecas de clase de Java.
La API de Java proporciona una vasta colección de clases que
contienen métodos para realizar cálculos matemáticos, manipulaciones de
cadenas, manipulaciones de caracteres, operaciones de entrada/salida,
comprobación de errores y muchas operaciones útiles. Este conjunto de
clases facilita la escritura de programas, ya que la API de Java proporciona
muchas herramientas que necesitan los programadores.
Por ejemplo la clase String vista en la unidad III, la clase Math que
contiene constantes y funciones matemáticas, como la constante PI,
funciones como para calcular la potencia (pow), la raíz cuadrada (sqrt) entre
otras; las clases de los componentes de la interfaz gráfica de usuario; las
interfaces para el manejo de eventos en las interfaces gráfica de usuario.
Visto de otra forma el API de Java es un conjunto de clases que es
utilizado para generar programas básicos en el lenguaje; utilizando una
analogía, estas clases tienen la misma funcionalidad que las
funciones/clases estándar utilizadas en otros lenguajes C/C++, Perl
Partiendo de estas clases (API de Java) se generan todos los
programas, interfaces y elementos programados en Java, inclusive a partir de
estas clases se puede definir otras clases específicas que serán utilizadas
por su programa o producto.
Definición de los componentes que conforman la interfaz grafica de
usuario.
componentes de la GUI también conocidos como controles o widgets
(accesorios de ventana). Un componente de la GUI es un objeto con el cual
interactúa el usuario mediante el ratón, el teclado u otra forma de entrada,
como el reconocimiento de voz. Varios de los componentes de la GUI se
muestran en la Tabla 8.1.
Tabla 8.1. Algunos de los componentes de la GUI
Componente en Java
Componente del paquete javax . Descripción
swing
Etiqueta JLabel Área en donde pueden mostrarse
iconos o texto no editable.
Campo de texto JTextField Área en la que el usuario introduce
datos desde el teclado. Esta área
también puede mostrar información.
Botón JButton Área que, cuando el ratón hace clic
sobre ella, desencadena un evento.
Cuadro de JCheckBox Componente de la GUI que puede
comprobación estar o no seleccionado.
Área de lista JComboBox Lista desplegable de elementos, de
modificable los cuales el usuario puede
seleccionar uno haciendo clic en él o
posiblemente escribiendo dentro del
cuadro.
Lista de opciones JList Área que contiene una lista de
múltiples elementos, de los cuales el usuario
puede seleccionar cualquiera
haciendo clic en él. Pueden
seleccionarse varios elementos.
Fuente: propia
Son algunos de los más usados; con etiquetas, campos de texto y
botones se puede desarrollar una interfaz gráfica de usuario agradable y de
fácil manejo para probar una(s) clase(s); éstas sirven para probar el buen
funcionamiento de las clases que hasta ahora se han desarrollado.
En la Tabla 8.1 se presentan los componentes que pertenecen al
paquete javax . swing, porque es el más usado actualmente, la mayoría de
los componentes de swing, como se le llama comúnmente, están escritos, se
manipulan y muestran completamente en Java(llamado componentes puros
de Java).
Los componentes originales de la GUI del paquete java . awt del AWT
(Abstract Windows Toolkit) están enlazados directamente con las
herramientas de interfaz gráfica de usuario de la plataforma local(sistema
operativo). Cuando se ejecuta un programa en Java con una GUI de la AWT
en distintas plataformas Java, los componentes de la GUI del programa se
muestran de manera distinta en cada plataforma; por ejemplo un objeto tipo
Button (de la AWT) en una computadora que se ejecute el sistema operativo
Microsoft Windows tendrá una apariencia visual como los botones de ese
sistema operativo, mientras que en una que ejecute el sistema operativo Mac
OS de Apple, el objeto Button tendrá la misma apariencia visual de los
botones del sistema operativo actual. En ocasiones, la forma en que un
usuario puede interactuar con un componente AWT específico es distinta
entre las plataformas.
Los componentes de Swing comúnmente se conocen como
componentes ligeros; están escritos completamente en Java, por lo que no
son
en que se utilicen. Sin embargo, a los componentes de AWT (muchos de los
cuales comparan con los componentes de Swing), que están enlazados a la
plataforma local, se les llama componentes pesados; éstos dependen del
sistema de ventanas de la plataforma local para determinar su funcionalidad,
apariencia visual, y manera en que el usuario interactúa con el programa.
Para utilizar componentes de la GUI efectivamente, se utilizan los
paquetes javax.swing y java.awt, conjuntamente, para obtener un resultado
esperado, porque en el paquete java.awt, existen clases e interfaces
necesarias para el desarrollo de la GUI, sobretodo los componentes escucha
de eventos (oyentes de eventos), mientras que en el paquete javax.swing,
están desarrollados los componentes de escucha de eventos adicionales que
son específicos para los componentes Swing.
En el lenguaje Java las interfaces gráficas de usuario se pueden
desarrollar con:
Un applet es un subprograma que se ejecuta dentro de una página
web, donde la clase que lo describe tiene que heredar de la
superclase JApplet, y se puede redefinir los métodos que se
encuentran en la clase JApplet:
public void init ( )
Este método es llamado una vez por el contenedor de
applets cuando se carga un applet para ejecutarse. Lleva a
cabo la inicialización de un applet. Las acciones típicas que se
realizan aquí son inicializar campos, crear componentes de la
GUI, cargar los sonidos a reproducir, cargar las imágenes a
mostrar.
public void start ()
Este método se llama después de que el método init
termina de ejecutarse. Además, si el navegador visita otro sitio
Web y después regresa a la página de HTML en la que reside
el applet, el método start se llama de nuevo. Este método lleva
a cabo todas las tareas que deben completarse cuando el
applet se carga por primera vez, y que deben de llevarse a
cabo cada vez que se vuelva a visitar la pagina de HTML en la
que reside el applet. Las acciones típicas que se realizan aquí
incluyen el empezar una animación y empezar otros
subprocesos de ejecución. Las animaciones y sonido son
ajenos al objetivo de la asignatura, entonces este método no se
redefinirá en los ejemplos.
public void paint ( Graphics g )
Este método de dibujo se llama después de que el método
init termina de ejecutarse y el método start ha comenzado.
También se llama cada vez que el applet necesita volver a
pintarse. Por ejemplo, si el usuario cubre el applet con otra
ventana abierta en la pantalla y después descubre el applet, se
hace una llamada al método paint. Las acciones típicas que se
realizan aquí incluyen el dibujar con el objeto g tipo Graphics
que se pasa al método paint mediante el contenedor de
applets.
public void stop ( )
Este método se llama cuando el applet debe detener su
ejecución; normalmente, cuando el usuario del navegador sale
de la páginaHTML en la que reside el applet. El método realiza
todas las tareas requeridas para suspender la ejecución del
applet. Las acciones típicas que se realizan aquí son detener la
ejecución de las animaciones y los subprocesos. Las
animaciones y subprocesos son ajenos al objetivo de la
asignatura, entonces este método no se redefinirá en los
ejemplos.
public void destroy ( )
Este método se llama cuando el applet se va a quitar de
memoria; normalmente, cuando el usuario del navegador sale
de la sesión de navegación(es decir, cuando cierra todas las
ventanas del navegador). El método realiza todas las tareas
requeridas para destruir los recursos asignados al applet.
Un Frame es una aplicación que se ejecuta desde el computador,
como una aplicación para un computador personal o para que se
ejecute en un servidor;
A continuación se explicaran los applet.
Para desarrollar un applet ó un frame hay que importar los paquetes
javax.swing , java.awt y java.awt.event para usar los componentes que se
encuentran descritos en las clases pertenecientes a estos, como manejar las
acciones descritas en alguno de estos paquetes. Hay que desarrollar una
clase que herede de las clases JApplet ó de JFrame según sea el caso, y
que implemente unas interfaces definidas en Java, por ejemplo
ActionListener, ItemListener, MouseListener entre otras, éstas definen un
comportamiento para el manejo de los eventos producidos por el usuario, los
cuales el programador debe manejarlos para que el usuario tenga la
respuesta esperada.
Otro componente importante es el contenedor de la clase Container, el
contenedor va a abarcar todos y cada uno de los componentes que
conforman la GUI, también va a definir el orden que tendrán éstos en la GUI;
El orden es especificado por el Administrador de esquemas que proporciona
herramientas básicas de distribución visual, que son más fáciles de usar que
determinar la posición y tamaño exactos de cada componente de la GUI.
Esta funcionalidad permite al programador concretarse en la vista y sentido
básicos, y deja que el administrador de esquemas procese la mayoría de los
detalles de la distribución visual. En Java existen cinco (5) posibles
esquemas, vea Tabla 8.2.
Tablaa 8.2. Administradores de esquemas(1/2)
Administrador
Descripción
de esquemas
Coloca los componentes secuencialmente (de izquierda a
derecha) en le orden en que se agregaron. También es
posible especificar el orden de los componentes utilizando
FlowLayout
el método add de Container, el cual toma un objeto
(componente de la GUI) y una posición de índice entero
como argumentos.
Ordena los componentes en cinco áreas: NORTH, SOUTH,
BorderLayout
EAST, WEST y CENTER
Fuente: propia
Tablaa 8.2. Administradores de esquemas(2/2)
Administrador
Descripción
de esquemas
GridLayout Ordena los componentes en filas y columnas, empezando en la
celda superior izquierda de la cuadricula, y procediendo de
izquierda a derecha hasta que la fila esté llena. Después el
proceso continúa de izquierda a derecha en la siguiente fila, y así
sucesivamente.
BoxLayout Permite ordenar los componentes de la GUI de izquierda a
derecha, o de arriba hacia abajo, en un contenedor. La clase Box
declara un contenedor con BoxLayout como su administrador de
esquema predeterminado, y proporciona métodos estáticos para
crear un objeto Boxcon un esquema BoxLayout horizontal o
vertical
GridBagLayout Es similar al GridLayout. A diferencia de éste, el tamaño de cada
componente puede variar (es decir, pueden ocupar varias filas y
columnas) y pueden agregarse componentes en cualquier orden.
Fuente: propia
De todos los administradores de la Tabla 6.2 el más usado es el
FlowLayout.
Evento: es la interacción del usuario con un componente de la GUI, es
decir, cuando el usuario cliquea a un componente de la GUI; en el instante
que esto suceda, el programa envía un mensaje al applet informando que un
evento ha ocurrido, para que se ejecuten las instrucciones necesarias. En
una interfaz gráfica todas las acciones son desencadenadas por eventos, es
lo que indica los deseos del usuario; Este estilo de programación se conoce
como programación controlada por eventos.
Los manejadores de eventos son aquellos métodos invocados al ocurrir
un evento también se conocen simplemente como manejadores de evento.
Cuando ocurre un evento en la GUI de un programa, el mecanismo
para manejar eventos crea un objeto que contiene información acerca del
evento que acaba de ocurrir, e invoca a un método apropiado para manejar
eventos (declarado en una interfaz del API de Java) en el caso de los
botones el método es actionPerformed, para los radio botones, casillas de
verificación, entre otros es el itemStateChanged.
A cada componente que se le desee manejar un evento se le tiene que
añadir un oyente (Listener) de eventos, para que cuando el usuario
interactúe con éste, se ejecute el método correspondiente a el tipo de oyente
que se le añadió; por ejemplo a los botones en el método init(en el caso del
Applet) después de crearlos, se le añade el oyente de la siguiente forma:
Boton1 . addActionListener
Si fuera a un radio botón, de la siguiente forma:
radioBoton1 . addItemListener
Luego en el applet, para los botones se tiene que redefinir el método
actionPerformed que recibe un objeto de tipo ActionEvent, con toda la
información del evento que recién ocurrió, y así los métodos que le
correspondan a cada componente con el oyente añadido;
Es importante resaltar que si a un componente botón de la GUI no se le
añade un oyente de eventos, al usuario interactuara con éste y no se
procesara la acción, es decir el programa no ejecutara ninguna acción.
, por esta
razón es que se le llama programación controlada por eventos.
Para el manejo de eventos es necesario que la clase implemente las
interfaces necesarias, para los eventos esperados, para seguir con los
botones, la interfaz a implementar es ActionListener; y como no hay límites
en las interfaces que una clase puede implementar, en una misma interfaz
gráfica se pueden manejar muchos eventos de diferentes tipos.
Ejemplos de los componentes que conforman la interfaz grafica
de usuario en la programación orientada a objetos.
Se recuerda la clase Fraccion desarrollada en el Capítulo 5, en la figura
5.4. Si se quiere probar dicha clase con una GUI, se usará un JApplet, la
interfaz constará de siete (7) campos de texto, siete (7) etiquetas y cinco (5)
botones, ver Figura 8.1.
Figura 8.1. GUI para probar la clase Fraccion
Fuente: propia
El código fuente correspondiente de la GUI de la Figura 8.1. Se puede
observar en la Figura 8.2.
1 import java . awt. * ;
2 import java . awt . event . * ;
3 import javax . swing . * ;
4 public class GUI_Fraccion extends JApplet implements ActionListener {
5 JLabel lfraccion1 , lfraccion2 , lBarra1 , lBarra2, lbarra3 , lResul , lIgual ;
6 JTextField tNum1 , tDen1 , tNum2 , tDen2 , tNumR , tDenR , tResul ;
7 JButton bSuma , bResta , bMult , bDiv , bIgual;
8 Container c;
9 public void init ( ) {
10 c = getContentPane ( ) ;
11 c . setLayout ( new FlowLayout ( ) ) ;
12 lfraccion1 = new JLabel ( "Fracción 1 : " ) ;
13 lfraccion2 = new JLabel ( "Fracción 2 : " ) ;
14 lBarra1 = new JLabel ( " / " ) ;
15 lBarra2 = new JLabel ( " / " ) ;
16 lbarra3 = new JLabel ( " / " ) ;
17 lResul = new JLabel ( " Resultado : " ) ;
18 lIgual = new JLabel ( " = " ) ;
19 tNum1 = new JTextField ( "" , 3);
20 tDen1 = new JTextField ( "" , 3);
21 tNum2 = new JTextField ( "" , 3);
22 tDen2 = new JTextField ( "" , 3);
23 tNumR = new JTextField ( "" , 3);
24 tDenR = new JTextField ( "" , 3);
Figura 8.2. Código fuente de la clase GUI_Fraccion(1/5)
Fuente: propia
25 tResul = new JTextField ( "" , 5);
26 bSuma = new JButton ( " + " ) ;
27 bResta = new JButton ( " - " ) ;
28 bMult = new JButton ( " * " ) ;
29 bDiv = new JButton ( " / " ) ;
30 bIgual = new JButton ( " = " ) ;
31 bSuma . addActionListener ( this ) ;
32 bResta . addActionListener ( this ) ;
33 bMult . addActionListener ( this ) ;
34 bDiv . addActionListener ( this ) ;
35 bIgual . addActionListener ( this ) ;
36 c . add ( lfraccion1 ) ;
37 c . add ( tNum1 ) ;
38 c . add ( lBarra1 ) ;
39 c . add ( tDen1 ) ;
40 c . add ( lfraccion2 ) ;
41 c . add ( tNum2 ) ;
42 c . add ( lBarra2 ) ;
43 c . add ( tDen2 ) ;
44 c . add ( bSuma ) ;
45 c . add ( bResta ) ;
46 c . add ( bMult ) ;
47 c . add ( bDiv ) ;
48 c . add ( bIgual ) ;
49 c . add ( lResul ) ;
50 c . add ( tNumR ) ;
51 c . add ( lbarra3 ) ;
52 c . add ( tDenR ) ;
53 c . add ( lIgual ) ;
54 c . add ( tResul ) ;
55 }
56 public void paint ( Graphics g ) {
57 super . paint ( g ) ;
58 }
59 public void actionPerformed ( ActionEvent ae ) {
60 if ( ae . getSource ( ) . equals ( bSuma ) )
Figura 8.2. Código fuente de la clase GUI_Fraccion(2/5)
Fuente: propia
61 sumar ( ) ;
62 else if ( ae . getSource ( ) . equals ( bResta ) )
63 restar ( ) ;
64 else if ( ae . getSource ( ) . equals ( bMult ) )
65 multiplicar ( ) ;
66 else if ( ae . getSource ( ) . equals ( bDiv ) )
67 dividir ( ) ;
68 else
69 resultado ( ) ;
70 }
71 public boolean isLleno ( ) {
72 if( ! tNum1 .getText ( ) .equals( " " ) && ! tDenn1 .getText( ) . equals( "" )
73 && ! tNum2 . getText( ) . equals( " " ) && ! tDen2 . getText( ) . equals( " " ) )
74 try { if ( Integer . parseInt ( tDen1 . getText ( ) ) != 0 &&
75 Integer . parseInt ( tDen2 . getText ( ) ) != 0 )
76 return true ; }
77 catch ( Exception ex ) { return false ; }
78 return false;
79 }
80 public void sumar ( ) {
81 if ( isLleno ( ) ) {
82 Fraccion a = toma ( tNum1 , tDen1 ) ;
83 Fraccion b = toma ( tNum2 , tDen2 ) ;
84 if ( a != null && b != null ) {
85 Fraccion d = null ;
86 d = new Fraccion ( 1 , 1 );
87 d . sumar ( a , b ) ;
88 String aux ;
89 aux = String . valueOf ( d . getNumerador ( ) ) ;
90 tNumR . setText ( aux ) ;
91 int x = d . getDenominador ( ) ;
92 aux = String . valueOf ( x ) ;
93 tDenR . setText ( aux ) ;
94 tResul . setText ( " " + d . resultado ( ) ) ;
95 }
96 }
97 else
Figura 8.2. Código fuente de la clase GUI_Fraccion(3/5)
Fuente: propia
98 JOptionPane . showMessageDialog ( null , " Error los campos
99 son obligatorios " ) ;
100 }
101 public void resta r( ) {
102 if ( isLleno ( ) ) {
103 Fraccion a = toma ( tNum1 , tDen1 ) ;
104 Fraccion b = toma ( tNum2 , tDen2 ) ;
105 if ( a != null && b != null ) {
106 a . restar ( b ) ;
107 tNumR . setText ( String . valueOf ( a . getNumerador( ))) ;
108 tDenR . setText ( String . valueOf ( a . getDenominador( ))) ;
109 tResul . setText ( String . valueOf ( a . resultado ( ) ) ) ;
110 }
111 }
112 else
113 JOptionPane . showMessageDialog ( null , "Error los campos
114 son Obligatorios " ) ;
115 }
116 public void multiplicar ( ) {
117 if ( isLleno ( ) ) {
118 Fraccion a = toma ( tNum1 , tDen1 ) ;
119 Fraccion b = toma ( tNum2 , tDen2 ) ;
120 if ( a != null && b != null ) {
121 a . multiplicar ( b ) ;
122 tNumR . setText ( String . valueOf ( a . getNumerador( ))) ;
123 tDenR . setText( String . valueOf ( a . getDenominador())) ;
124 tResul . setText ( String . valueOf ( a . resultado ( ) ) ) ;
125 }
126 }
127 else
128 JOptionPane . showMessageDialog ( null , " Error los campos
129 son obligatorios " ) ;
130 }
131 public void dividir ( ) {
132 if ( isLleno ( ) ) {
133 Fraccion a = toma ( tNum1 , tDen1 ) ;
134 Fraccion b = toma ( tNum2 , tDen2 ) ;
135 if ( a != null && b != null ) {
Figura 8.2. Código fuente de la clase GUI_Fraccion(4/5)
Fuente: propia
136 Fraccion d ;
137 d = Fraccion . dividir ( a , b ) ;
138 tNumR . setText ( String . valueOf( d . getNumerador ())) ;
139 tDenR . setText ( String . valueOf( d . getDenominador ())) ;
140 tResul . setText ( String . valueOf ( d . resultado ( ) ) ) ;
141 }
142 }
143 else
144 JOptionPane . showMessageDialog ( null , " Error los campos
145 son obligatorios " ) ;
146 }
147 public void resultado ( ) {
148 if( ! tNumR . getText( ) . equals( " " )&& ! tDenR . getText( ) . equals( " " ))
149 if ( Integer . parseInt ( tDenR . getText ( ) ) != 0 ) {
150 Fraccion d = toma ( tNumR , tDenR ) ;
151 tResul . setText ( String . valueOf ( d . resultado ( ) ) ) ;
152 }
153 else
154 JOptionPane . showMessageDialog ( null , " El denominador
155 no puede ser cero ! " ) ;
156 }
157 public Fraccion toma ( JTextField a , JTextField b ) {
158 int x = 0 , y = 0 ;
159 try {
160 x = Integer . parseInt ( a . getText ( ) ) ;
161 y = Integer . parseInt ( b . getText ( ) ) ;
162 return new Fraccion ( x , y ) ;
163 }
164 catch ( Exception ex ) {
165 JOptionPane . showMessageDialog ( null , " Error los campos
166 deben ser números " ) ;
167 return null ;
168 }
169 }
170 }
Figura 8.2. Código fuente de la clase GUI_Fraccion(5/5)
Fuente: propia
A continuación la explicación del código de la Figura 8.2.
En las líneas 1 a 3 se importan todos los paquetes necesarios para
desarrollar el applet, java.awt tiene la clase Container, ButtonGroup,
FlowLayout, el java.awt.event tiene las interfaces ActionListener e
ItemListener, y javax.swing a todas las de los componentes JLabel , JButton ,
JTextField.
En la línea 4 se declara la clase que hereda de JApplet e implementa la
interface ActionListener, con la palabra reservada implements, para el
manejo de eventos.
Luego en las líneas 5 a la 7 se declaran todos los componentes a usar
en el applet, siete (7) etiquetas, siete (7) campos de texto, y cinco (5)
JLabel, con una
JTextField y así para lo demás, para poder identificar de que tipo es
un objeto; en la línea 8 se declara el contenedor de los componentes con el
identificador c .
En la línea 9 se encuentra el método init” que no retorna ni recibe
ningún valor, éste método es heredado de la clase JApplet, y se ejecuta
cuando se carga la pagina web contenedora del applet, así que aquí se crea
el contenedor y todos los componentes de la GUI. Como se observa en la
línea 10, se le asigna al contenedor lo que retorna el método
getContentPane( ), que se hereda de la clase JApplet y devuelve una
referencia al objeto del panel de contenido del applet. El programa utiliza
esta referencia para adjuntar los componentes de la GUI, a la interfaz de
usuario del applet.
Luego en la línea 11 se especifica el administrador de esquema para la
interfaz de usuario del applet, con el método setLayout ( ) de la clase
Container, enviándole como parámetro un objeto de tipo FlowLayout ver
Tabla 8.2. De la línea 12 a la 30 se crean todos los componentes a utilizar en
el ejercicio, fíjese que el constructor usado para los JLabel reciben la cadena
a mostrar, y el usado para los JTextField recibe la cadena inicial y el número
de caracteres que se mostrará, mientras para los JButton recibe la cadena a
mostrar. Es importante mencionar que la clases de los componentes la gran
mayoría tienen sobrecargados los constructores de las mismas.
En las líneas 31 a 35, se le añade a los botones un ActionListener, con
el método addActionListener , indicando que para éstos, va a existir un
oyente de eventos, o se va a escuchar los eventos producidos por el botón,
para el manejo de eventos.
En la línea 36 del método init”, se comienzan a adjuntar los
componentes al panel de contenido del applet, como el administrador de
esquemas es FlowLayout, se deben añadir en el orden que se desea que
aparezcan en la GUI, como en la Figura 6.1 se observa que lo primero que
campo de texto para el numerador de la primera fracción, entonces esa
la GUI.
En las líneas de 56 a 58, se encuentra el método paint”, que es
heredado de la clase JApplet, que recibe un Objeto Graphics, este método es
usado para dibujar en el applet, también se puede escribir cadenas en una
determinada posición. En este caso particular se llama al método paint” de
la superclase, esto es para actualizar el panel.
En las líneas 59 a la 70, está el método manejador de eventos, el
actionPerformed”, que recibe un objeto ActionEvent con toda la información
del evento que acaba de ocurrir, como en este applet hay cinco (5) botones
con oyente de eventos, entonces se debe verificar con cual fue que el
usuario interactúo, para esto se usa el método getSource ( ), para saber la
fuente de donde proviene el evento, con el método equals de la clase Object,
y así se compara con cual de los cinco (5) botones es el origen del evento.
Para cada uno se crea un método en la clase PruebaFraccion, que gestione
las acciones correspondientes con la elección del usuario; en las líneas 80 a
157.
En las líneas 71 a 79, se encuentra el método isLleno ( ) , que no
recibe parámetros pero retorna un valor de tipo boolean; éste método es para
verificar que todos los campos de texto tengan algo escrito, y validar que no
que los denominadores sean diferentes de cero; en la línea 74, esta un
bloque try que se utiliza para manejar excepciones; por ejemplo que el
usuario escriba un carácter alfabético o especial donde debe ir un número,
entonces cuando el código intente traducir esa cadena a entero (con el
método de clase parseInt perteneciente a la clase Integer, que recibe un
objeto tipo String y devuelve un dato int) se lanzará una excepción, para
manejarla y mostrarle al usuario su error, se utilizan los bloques try y catch.
El bloque catch recibe un objeto perteneciente a la jerarquía de herencia de
las Excepciones, donde la superclase es Exception y se encuentra en el
paquete java.lang, que es importado en todas las clases por defecto. El
método getText” devuelve el texto de un campo de texto (casi todos los
componentes de la GUI lo tienen).
En las líneas de la 80 a 157, están los métodos invocados en el método
actionPerformed”, éstos no devuelven ningún valor, ni reciben parámetros;
en la línea 80 esta definido el primero de ellos el método sumar, donde se
manda a ejecutar el método isLleno , y depende del valor devuelto por éste,
se suman las dos fracciones o se muestra un mensaje al usuario diciéndole
que todos los campos son obligatorios (línea 98); en el caso que el valor
que recibe dos
objetos tipo JTextField y los convierte en un objeto de tipo Fracion y lo
retorna (Línea 158); luego se verifica que han sido creados, es decir, que sea
diferente de null, si han sido creados, entonces se declara y crea un objeto
raccion con valores arbitrarios de 1/1(línea 86), para luego mandar
un mensaje al método sumar enviándole las dos Fracciones que ingreso el
usuario (línea 87), ahora se necesita mostrar el resultado de la suma que
ampos de texto tNumR para el
numerador (línea 90), tDenR para el denominador (línea 93) y tResul para el
resultado en números reales(línea 94); el método setText” recibe un String y
lo fija en el texto que se muestra en un JTextField, para convertir un int a
String, se usa el método de clase valueOf de la clase String, este método
está sobrecargado y el valor que reciba lo convierte a String y lo
devuelve(Línea 92), en la línea 89 se puede observar que el int que
, se convierta en String y se le
asigna a una variable aux de tipo String, para luego fijarlo como el texto del
JTextField “ tNumR ; fíjese que para mostrar el denominador de esta
Fraccion se hace paso a paso, primero se guarda el valor en una variable x
de tipo int, luego se convierte a String y se asigna a la variable aux, y por
ultimo se asigna al texto del objeto tDenR ; en la línea 94 se realiza de otra
forma, se concatena una cadena vacía con el float que retorna el método
resultado de la clase Fraccion, porque en Java cuando se usa un String y el
implícitamente a String; en este método se presento tres formas diferentes
de convertir un valor numérico a un String.
En la línea 101 se encuentra el método resta , al igual que el método
anterior(método sumar ), primero se verifica que los campos de texto no
estén vacios (línea 102), con el método isLleno , en el caso de estar todo
como se espera, se envía un mensaje al método restar de la clase Fraccion
mostrar el resultado en los campos de texto tNumR , tDenR y tResul se
hace de una forma directa (líneas 107, 108 y 109).
En la línea 116, esta el método multiplicar , muy parecido al método
restar , pero el método de la clase fracción invocado es multiplicar , de todo
lo demás es muy parecido.
En la línea 131, se encuentra el método dividir , éste es parecido al
método sumar de la línea 80, porque el método dividir de la clase Fraccion
devuelve un objeto Fraccion y es un método de clase, por lo tanto no es
necesario que se invoque con un objeto de ese tipo, sino con el nombre de la
clase (línea 137).
En la línea 147, ésta el método resultado , este método será ejecutado
cuando se escriba una Fraccion en los campos de texto para la Fraccion
resultante estos son tNumR y tDenR , y el usuario presione el botón
bIgual ; lo primero que se hace en éste método es verificar que esos
campos de texto no estén vacios (línea 148), y el denominador sea distintito
de cero (línea 149), luego se declara el objeto Fraccion y se le asigna la
Fraccion devuelta por el método toma, y el resultado se muestra en el
JTextField tResul .
Y por ultimo pero no menos importante se encuentra el método toma ,
que recibe dos objetos tipo JTextField a y b ; y devuelve un objeto tipo
Fraccion conformado por el numerador y denominador de los valores que se
encuentren en los campos de texto que recibe, eso en el caso de que el
usuario haya escrito en los campos de texto valores numéricos, porque si no
muestra un mensaje de error y devuelve un valor nulo.
Y con esto termina el análisis del código fuente de la clase
GUI_fraccion.
Resolución de problemas usando interfaz gráfica y manejo de
eventos en programación orientada a objetos.
Realice las clases necesarias para la siguiente jerarquía de
herencia: medios de comunicación, televisoras y emisoras
radiales. Por cada medio de comunicación se manejan un
nombre; las televisoras tienen una señal (número de canal),
están ubicadas en un país; las emisoras de radio se
encuentran en una región y se pueden sintonizar por una
frecuencia. Las operaciones que Ud. desarrollará, son las
siguientes:
Obtener el total de canales que se hayan creado en
Venezuela.
Obtener en cualquier momento el nombre de la emisora
que tenga la frecuencia mas baja.
Diseñe y desarrolle una GUI usando JApplet(con una interfaz agradable
y de fácil manejo), para probar las clases de la mencionada jerarquía.
CAPÍTULO IX: INTRODUCCIÓN A ALGORITMOS
RECURSIVOS
9.1 Objetivos
Definir que es recursión, según una discusión en clases.
Identificar los tipos de problemas que se pueden resolver
mediante el uso de la recursión, usando programación orientada
a objetos.
Diferenciar funciones recursivas con funciones iterativas,
partiendo de las ventajas y desventajas de cada una.
Reconocer algoritmos resueltos usando funciones recursivas en
programación orientados a objetos.
9.2 Contenido
Definición de recursividad.
Tipos de problemas que pueden resolverse usando recursividad
en programación orientada a objetos.
Comparación de una función recursiva con respecto a una
función iterativa según las ventajas y desventajas de cada
función.
Problemas resueltos con algoritmos en programación orientada a
objetos usando funciones recursivas.
9.2.1 Definición de recursividad
La recursividad es aquella propiedad que posee un método por la cual
puede llamarse a sí mismo.
La recursión es un proceso extremadamente potente, pero consume
muchos recursos, De este análisis se deducirá que aunque un problema por
definición sea recursivo, no siempre será el método de solución más
adecuado.
Antes de poner en marcha un proceso recursivo es necesario demostrar
que el nivel máximo de recursión, esto es, el número de veces que se va a
llamar a sí mismo, es no sólo finito, sino realmente pequeño. La razón es que
se necesita cierta cantidad de memoria para almacenar el estado del proceso
cada vez que se abandona temporalmente, debido a una llamada para
ejecutar otro proceso que es él mismo. El estado del proceso de cálculo en
curso hay que almacenarlo para recuperarlo cuando se acabe la nueva
ejecución del proceso y haya que reanudar la antigua.
En el diseño recursivo siempre se debe avanzar hacia un caso base.
Las llamadas recursivas simplifican el problema y, en última instancia, los
casos base nos sirven para obtener la solución. Los casos base
corresponden a situaciones que se pueden resolver con facilidad, mientras
los demás casos se resuelven recurriendo, antes o después, a alguno(s) de
los casos base.
Un método recursivo es un método que se invoca a sí mismo de forma
directa o indirecta. En recursión directa, el código de un método f ( ) contiene
una sentencia que invoca al método f ( ), mientras que en recursión indirecta,
el método f ( ) invoca a un método g ( ) que a su vez invoca al método p ( ), y
así sucesivamente hasta que se invoca de nuevo al método f ( ).
Un requisito para que un algoritmo recursivo sea correcto es que no
genere una secuencia infinita de llamadas sobre sí mismo. Cualquier
algoritmo que genere una secuencia de este tipo no puede terminar nunca,
es decir se hace infinitas veces. En consecuencia la definición recursiva debe
incluir una condición de salida, que se denomina caso base, en el que f (n)
se defina directamente (es decir no recursivamente) para uno o más valores
de n.
En definitiva, debe existir una forma de salir de la secuencia de
llamadas recursivas.
9.2.2 Tipos de problemas que pueden resolverse usando recursividad
en programación orientada a objetos.
Una de las técnicas más importantes para la resolución de muchos
problemas de computadora es la denominada divide y vencerás. El diseño
de algoritmos basados en esta técnica consiste en transformar (dividir) un
problema de tamaño n en problemas más pequeños, de tamaño menor que
n, pero similares al problema original, de modo que resolviendo los
subproblemas y combinando las soluciones se pueda construir fácilmente
una solución del problema completo (vencerás).
Normalmente, el proceso de división de un problema en otros de
tamaño menor va a dar lugar a que se llegue al caso base, cuya solución es
inmediata. A partir de la obtención de la solución del problema para el caso
base, se combinan soluciones que amplían el tamaño del problema resuelto,
hasta que el problema original queda también resuelto.
Un algoritmo divide y vencerás se define de manera recursiva, de tal
modo que se llama a sí mismo sobre un conjunto menor de elementos.
Normalmente, se implementa con dos llamadas recursivas, cada una con un
tamaño menor. Se alcanza el caso base cuando el problema se resuelve
directamente.
Problemas clásicos resueltos mediante recursividad son la Torres de
Hanoi, el método de búsqueda binaria, la ordenación rápida, la ordenación
por mezclas, entre otras.
Se va a explicar el algoritmo de las torres de Hanoi, los demás quedan
para su investigación.
Este juego (un algoritmo clásico como se menciono) tiene sus orígenes
en la cultura oriental y en una leyenda sobre el Templo de Brahma, cuya
estructura simulaba una plataforma metálica con tres varillas y discos en su
interior. El problema en cuestión suponía la existencia de 3 varillas (A, B y C)
o postes en los que se alojaban discos (n discos) que se podían trasladar de
una varilla a otra libremente, pero con las siguientes condiciones:
Sólo se puede mover un disco a la vez.
No se puede poner un disco encima de otro más pequeño.
Después de un movimiento todos los discos han de estar en
alguno de las tres varillas.
En la Figura 9.1, se ilustra el problema con tres varillas con cuatro
discos en la varilla A, y se desea trasladar a la varilla C conservando la
condición de que cada disco sea ligeramente inferior en diámetro al que tiene
situado debajo de él.
Figura 9.1. Ilustración de las Torres de Hanoi
Fuente: propia
Diseño del algoritmo:
Las varillas se nombrarán: varilla Inicial, varilla Central y varilla Final.
En la varilla Inicial se sitúan n discos que se apilan en orden
decreciente de tamaño con el mayor en la parte inferior. El objetivo del juego
es mover los n discos desde la varilla Inicial a la varilla Final. Los discos se
mueven uno a uno respetando las reglas mencionadas anteriormente. El
método tHanoi( ) declara las varillas como datos de tipo char. En la lista de
parámetros, el orden de las variables es:
varIni, varCent, varFinal
e implica que se están moviendo discos desde la varIni a la final utilizando la
varCent como auxiliar para almacenar los discos. Si n = 1 se tiene el caso
base, se resuelve directamente moviendo el único disco desde la varilla
inicial a la varFinal. El algoritmo es el siguiente:
Si n = 1, entonces
- Mover disco 1 de varIni a varFinal, para
n=1
tHanoi(varIni, varCentral, varFinal, n)=
sino
- Mover n-1discos desde varIni a varCent
utilizando varFinal como auxiliar
- Mover el disco n desde varIni a varFinal.
- Mover n 1 discos desde varCent a
varFinal utilizando como auxiliar varIni.
Es decir, si n es 1, se alcanza el caso base, la condición de salida o
terminación del algoritmo. Si n es mayor que 1, las etapas recursivas son tres
sub-problemas más pequeños, uno de los cuales es la condición de salida.
Observe la Figura 8.2.
Figura 9.2. Representación gráfica de la solución del método tHanoi.
Fuente: propia
9.2.3 Comparación de una función recursiva con respecto a una
función iterativa según las ventajas y desventajas de cada
función.
Tanto la iteración como la recursión se basan en una estructura de
control: la iteración utiliza una estructura repetitiva y la rechijaaaahhursión
utiliza una estructura de selección. Tanto la iteración como la recursión
implican repetición: la iteración utiliza explícitamente una estructura repetitiva
mientras que la recursión consigue la repetición mediante llamadas repetidas
al método. La iteración y la Recursión implican cada una un test de
terminación (condición de parada). La iteración termina cuando la condición
del bucle no se cumple, mientras que la recursión termina cuando se
reconoce un caso base o se alcanza la condición de parada.
La recursión tiene muchas desventajas. Se invoca repetidamente al
mecanismo de llamadas a métodos y, en consecuencia, se necesita un
tiempo suplementario para realizar cada llamada.
Esta característica puede resultar costosa en tiempo de procesador y
espacio de memoria. Cada llamada recursiva produce una nueva creación y
copia de las variables de la función, esto consume más memoria e
incrementa el tiempo de ejecución. Por el contrario, la iteración se produce
dentro de un método, de modo que las operaciones suplementarias en la
llamada al método y en la asignación de memoria adicional son omitidas.
Entonces ¿cuáles son las razones para elegir la recursión? La razón
fundamental es que existen numerosos problemas complejos que poseen
naturaleza recursiva y, en consecuencia, son más fáciles de implementar con
algoritmos de este tipo. Sin embargo, en condiciones críticas de tiempo y de
memoria; es decir, cuando el consumo de tiempo y memoria sean decisivos o
concluyentes para la resolución del problema, la solución a elegir debe ser,
normalmente, la iterativa.
Cualquier problema que se puede resolver recursivamente tiene, al
menos, una solución iterativa. Un enfoque recursivo se elige, normalmente,
con preferencia a un enfoque iterativo cuando resulta más natural para la
resolución del problema y produce un programa más fácil de comprender y
de depurar. Otra razón para elegir una solución recursiva es que una
solución iterativa puede no ser clara ni evidente.
Criterios en la toma de decisión iteración/recursión
1. Considérese una solución recursiva sólo cuando una solución
iterativa sencilla no sea posible.
2. Utilícese una solución recursiva sólo cuando la ejecución y eficiente
de la memoria de la solución está dentro de límites aceptables, considerando
las limitaciones del sistema.
3. Si son posibles las dos soluciones, iterativa y recursiva, la solución
recursiva siempre requerirá más tiempo y espacio debido a las llamadas
adicionales a los métodos.
4. En ciertos problemas, la recursión conduce a soluciones que son
mucho más fáciles de leer y de comprender que su alternativa iterativa. En
estos casos, los beneficios obtenidos con claridad de la solución suelen
compensar el coste extra (en tiempo y memoria) de la ejecución de un
programa recursivo.
9.2.4 Problemas resueltos con algoritmos en programación orientada a
objetos usando funciones recursivas.
entonces
}
Ahora se estudiara un ejercicio recursivo para una función matemática
enteros positivos.
Se puede definir que para n = 1 entonces la suma es s(1) = 1, y para n
=2, s( 2 ) = s( 1 ) + 2; en general y aplicando la inducción matemáticas, se
tiene:
s( n ) = s(n-1)+n
El algoritmo debe tener en cuenta el caso base,
1 si n = 1
s(n) =
s(n-1) si n>1
A continuación en la Figura 9.3 se puede observar el código fuente del
método s(n):
1 public int s ( int n ) {
2 if ( n == 1 )
3 return 1;
4 else if ( n > 1 )
5 return n + s ( n - 1) ;
6 }
Figura 9.3. Código fuente del método “ s” .
Fuente: propia
En la línea 2, está el caso base, que garantiza que el método tiene su
punto de ruptura, es decir, va a dejar de hacer la recursividad, y en la línea 4
se verifica que n sea positivo, y en la línea 5 con la instrucción: s ( n 1 ),
donde se garantiza que n va a llegar a ser uno (1).
Para la ejecución del método s . obsérvese la Tabla 9.1., para n igual
a 4.
Tabla 9.1. Ejemplo de ejecución del método s ( n ), para n = 4.
Número de
Proceso de ida N s(n) Proceso de vuelta
iteración
10
1 s(4) 4 4+s(3) 4+6
2 s(3) 3 3+s(2) 3+3
3 s(2) 2 2+s(1) 2+1
4 s(1) 1 1
Fuente: propia
La forma correcta de ver la Tabla 9.1, es el proceso de ida porque
corresponde a la llamada del método, y fíjese lo que debe retornar el método
el valor de n sumado a lo que devuelva el método s(n-1), entonces se ejecuta
éste ( s(n-1) ), pasa a otra iteración, así hasta que se ejecute el método s(1)
que devuelve el valor de 1, pero este valor es retornado a donde se hizo la
llamada del método con n=1, es decir, a la iteración 3, se suma el valor de n
de esa iteración (2), y así se va regresando hasta llegar a la iteración 1, y
devuelve el valor de 10 a donde invocaron la primera vez a éste método.
Otro ejercicio es calcular el factorial de un número x, recordando que el
factorial de x (x!) es: x!= x*(x-1)*(x-
1 si x=1
factorial (x) =
factorial(x-1) si x>1
El código puede verse en la Figura 9.4.
Este ejercicio es muy parecido al anterior lo único es que en éste se
multiplica, mientras que en el de la Figura 9.1 la operación aritmética que se
realiza es la suma.
1 public int factorial ( int x ) {
2 if ( x == 1 )
3 return 1;
4 else if ( x > 1 )
5 return x * factorial ( n - 1) ;
6 }
Figura 9.4. Código fuente del método factorial
Fuente: propia
Todos los ejercicios que se deseen resolver usando recursividad, se
debe estudiar el caso base, y los demás casos para acertar en la llamada(s)
al mismo método.
Por ejemplo para definir la naturaleza recursiva de la serie fibonacci: 0,
1, 1, 2, 3, 5, 8, 13, 21,..
En esta serie que comienza con 0 y 1, y tiene la propiedad de que cada
elemento es la suma de los dos elementos anteriores. Entonces se puede
establecer que:
fibonacci(0) = 0
fibonacci(1) = 1
fibonacci(n) = fibonacci (n 1) + fibonacci(n 2)
Y la definición recursiva será:
n si n = 0 ó n = 1
fibonacci(n) =
fibonacci(n - 1) + fibonacci(n 2) si n > 1
En la Figura 9.5. Se puede observar el código del método fibonacci ( n).
1 public int fibonacci ( int n ) {
2 if ( n == 0 || n == 1 )
3 return n;
4 else if ( n > 1 )
5 return fibonacci (n 1) + fibonacci ( n 2) ;
6 }
Figura 9.5. Código fuente del método fibonacci.
Fuente: propia
CAPÍTULO X: INTRODUCCIÓN A LAS ESTRUCTURAS DE
DATOS FUNDAMENTALES.
10.1 Objetivos
Definir una estructura de datos.
Definir funciones propias de las estructuras de datos
fundamentales.
Resolver un problema usando estructuras de datos
fundamentales.
10.2 Contenido
Definición de las estructuras de datos fundamentales
Definición de la Funciones propias de las estructuras de datos
fundamentales
Resolución de problemas usando estructuras de datos
fundamentales
10.2.1 Definición de las estructuras de datos fundamentales.
Según Luis Joyanes en Estructuras de datos. Año 2008.
operaciones asociadas. Bajo esta óptica, cualquier representación de datos,
incluso un número entero o un número de coma flotante almacenado en la
computadora, es una sencilla estructura de datos. Es un sentido más
específico, una estructura de datos es una organización o estructuración de
una colección de elementos dato. Así, una lista ordenada de enteros
almacenados en un arreglo es un ejemplo de dicha estructuración.
Una estructura de datos es una agregación de tipos de datos
compuestos y atómicos en un conjunto con relaciones bien definidas. Una
estructura significa un conjunto de reglas que contienen los datos juntos.
Las estructuras de datos pueden estar anidadas: se puede tener una
Una estructura de datos es un conjunto de variables de un(os)
determinado(s) tipo(s) agrupadas y organizadas de alguna manera para
representar un comportamiento. Lo que se pretende con las estructuras de
datos es facilitar un esquema lógico para manipular los datos en función del
problema que haya que tratar y el algoritmo para resolverlo. En algunos
casos la dificultad para resolver un problema radica en escoger la estructura
de datos adecuada. Y, en general, la elección del algoritmo y de las
estructuras de datos que manipulará estará muy relacionada.
Según su comportamiento durante la ejecución del programa
distinguimos estructuras de datos:
Estáticas: su tamaño en memoria es fijo durante la ejecución del
programa. Ejemplo: array.
Dinámicas: su tamaño en memoria es variable durante la ejecución del
programa. Ejemplo: pilas, colas, listas enlazadas con punteros,
ficheros, etc.
Las estructuras de datos que se tratarán son las pilas y las listas; en el
Capítulo 6
ahondara en el tema.
En los arreglos se debe conocer la cantidad de elementos que lo
conformarán, antes de su creación, porque es una estructura de datos
estática, y son almacenados en posiciones secuenciales de memoria;
mientras las estructuras que se estudiarán en esta unidad la cantidad de
elementos que tendrán se definirá en la ejecución, se puede añadir y eliminar
elementos, y con esto aumenta o disminuye la cantidad de elementos en la
estructura, y los elementos no son almacenados en posiciones secuenciales
de memoria.
A continuación las definiciones de pilas y listas.
Una pila es una estructura de datos en la cual solo se pueden hacer dos
operaciones: colocar un elemento al final, o quitar un elemento del final. Lo
único que se puede hacer en una pila es colocar un objeto hasta arriba, o
quitar el objeto que está arriba; es como una pila de platos que se toma el
ultimo que se coloco, ya que si se quita uno de abajo o del centro (lo mismo
que si se intenta añadir uno), la pila colapsaría.
Una pila es una estructura dinámica tipo LIFO ( last in-firts out, ultimo en
entrar- primero en salir). Ver Figura 10.1.
N
N
N
N
Figura 10.1. Ilustración de una pila (de platos).
Fuente: propia
De la Figura 10.1, se puede observar que para retirar un plato debe ser
Cola es una estructura que Una cola es una estructura de datos que
almacena elementos en una lista y permite acceder a los datos por uno de
los dos extremos de la lista, al igual que las pilas, almacena y recupera sus
elementos atendiendo a un orden estricto. Un elemento se inserta en la cola
(parte final) de la lista y se suprime o elimina por el frente (parte inicial,
frente) de la lista. Las aplicaciones utilizan una cola para almacenar
elementos en su orden de aparición.
Las colas se conocen como estructuras FIFO (firts-in, firts-out, primero
en entrar-primero en salir).
Un ejemplo es una fila para pagar en un supermercado, el cajero
atiende primero a la persona que se encuentra al frente de la cola, mientras
los demás clientes entran a la cola por la parte final de la misma. Ver Figura
10.2.
Cajero Primero. Ultimo
Caja
Al frente Parte final
Figura 10.2. Ilustración de una cola (de supermercado)
Fuente: propia
Una lista enlazada es una colección lineal de objetos de una clase
autorreferenciada, conocidos como nodos, que están conectados por enlaces
nodos se componen de dos partes: la primera contiene la información y es,
Ver Figura 10.3.
Primera Segunda
parte parte
Nodo Nodo Nodo
Figura 10.3. Ilustración de una lista enlazada.
Fuente: propia
En la Figura 10.3, se puede ver que cada Nodo esta conformado por las
dos partes descritas anteriormente.
Clasificación de las listas enlazadas:
Listas simplemente enlazadas: Cada nodo contiene un único enlace
que lo conecta al nodo siguiente.
Listas doblemente enlazadas: Cada nodo contiene dos enlaces, uno a
su nodo predecesor y otro a su nodo sucesor.
Lista circular simplemente enlazada: Una lista simplemente enlazada
en la que el último nodo se enlaza al primero, de modo que queda
como un anillo.
Lista circular doblemente enlazada: Una lista doblemente enlazada
donde el último nodo se enlaza al primero, y éste se enlaza al último.
En esta asignatura se estudiarán las dos primeras.
10.2.2 Definición de la Funciones propias de las estructuras de datos
fundamentales.
Para los ejemplos aquí ilustrados, los nodos o elementos que
conforman las estructuras de datos (pilas, colas, y listas) estarán compuestos
por la referencia al siguiente también va a contener un dato, este dato será
de tipo entero, aunque puede ser de cualquier tipo, primitivo (char, boolean,
byte, int, short, long, float, double), o referenciado (String, arreglos, objetos
de clases propias desarrolladas con anterioridad).
Estas clases son una clase referenciada que contiene una variable de
instancia que hace referencia a otro objeto del mismo tipo de clase. Por
ejemplo.
class A{
//atributos
A objeto1;
Las funciones propias de las estructuras de datos, son las operaciones
que sirven para definir y manipular su contenido, aunque no todas se
implementan al definir una estructura de datos.
Funciones de una pila
A continuación en la Tabla 10.1. Ee puede observar las funciones
propias de una Pila
Tabla 10.1. Funciones de una Pila
Función Descripción
Crear pila Inicia (constructor)
Insertar elemento (push) Añade un nodo en la pila
Retirar elemento (pop) Retira un nodo de la pila
Pila vacía Comprueba si la pila no tiene elementos
Limpiar pila Borra todos los elementos, y deja la pila vacía
Cima pila Obtiene el elemento cima o tope de la pila
Tamaño de la pila Número de elementos que contiene la pila.
Fuente: propia
Entonces se debe definir una clase llamada NodoPila, con los datos, y
la referencia al siguiente. Observe Figura 10.4
1 public class NodoPila {
2 //atributos necesarios, para este ejemplo un entero
3 private int dato ;
4 private NodoPila ste ;
5 public NodoPila ( int d ) {
6 dato = d ;
7 //porque por ahora no hay un siguiente.
8 ste = null ;
9 }
10 public void setDato ( int d ) {
11 dato = d ;
12 }
13 public int getDato ( ) {
14 return dato ;
15 }
16 public void setSte ( NodoPila n ) {
17 ste = n ;
18 }
19 public NodoPila getSte(){
20 return ste ;
21 }
22 }
Figura 10.4. Código fuente de la clase NodoPila
Fuente: propia
De la Figura 10.4. Fíjese que es una clase con dos atributos uno tipo
int, y el otro del mismo tipo de la clase (Nodopila), es decir, esta clase es
autorreferenciada. Con su constructor, donde se le asigna un valor al
atributo entero, y se le asigna null
para manipular los atributos desde fuera de esta clase.
También se debe definir la clase Pila, donde estará el tope de la pila,
con las operaciones que se le puedan aplicar. Ver la Figura 10.5
1 public class Pila {
2 private NodoPila tope ;
3 //crear pila
4 public Pila ( ) {
5 tope = null ; }
6 public String push ( NodoPila n ) {
7 if ( pilaVacia ( ) ) {
8 tope = n ;
9 return " El nodo " + tope . getDato ( ) + " es el primero " ;
10 }
11 else {
12 n . setSte ( tope ) ;
13 tope = n ;
14 return "Ahora el nodo " +tope.getDato( )+" es el primero " ;
15 }
16 }
17 public NodoPila pop ( ) {
18 if ( ! pilaVacia ( ) ) {
19 NodoPila x = new NodoPila ( tope . getDato ( ) ) ;
20 tope = tope . getSte ( ) ;
21 return x ;
22 }
23 return null ;
24 }
25 public boolean pilaVacia ( ) {
26 if ( tope == null )
27 return true ;
28 return false ;
29 }
30 public void limpiarPila ( ) {
31 tope = null ;
32 }
Figura 10.5. Código fuente de la clase Pila (1/2)
Fuente: propia
33 public NodoPila cimaPila ( ) {
34 return tope ;
35 }
36 public int tamanoPila ( ) {
37 NodoPila nodo = tope ;
38 int cont = 1 ;
39 while ( nodo . getSte ( ) != null ){
40 cont ++ ;
41 nodo = nodo . getSte ( ) ;
42 }
43 return cont ;
44 }
45 }
Figura 10.5. Código fuente de la clase Pila (2/2)
Fuente: propia
Observe que en la Figura 10.5. Sólo se declara un atributo, un objeto de
la clase NodoPila (Figura 9
tope de la pila, que sólo se modificara en dos de los métodos, el push (Línea
6) y pop (Línea 17).
En la línea 4, esta ubicado el constructor de la clase, que no recibe
n null.
Luego todas las funciones definidas anteriormente; en la línea 6 esta el
método push
se verifica que la pila no este vacía, si lo esta, el nuevo nodo es el tope; y si
la pila no esta vacía, entonces se dice que el tope es el siguiente del nuevo
nodo y este ultimo pasa a ser el tope.
En la línea 17, el método pop ( ), que saca el ultimo nodo insertado en
la pila, para esto se verifica que la pila tenga al menos un elemento, es decir,
el nuevo tope como el nodo que le seguía a éste, y se devuelve el antiguo
tope. En el caso que la pila este vacía se devuelve una referencia nula (null).
En la línea 25, esta el método pilaVacia , que verifica como su nombre
lo indica el estado de la pila en cuanto a elementos se refiere. En la línea 30,
el método limpiarPila , hace lo que su nombre describe, coloca el tope de la
pila en null. Así en la línea 33, el método cimaPila , devuelve el tope de la
pila.
Luego como ultimo método de la clase se encuentra tamanoPila ( ) ,
donde se cuenta cuantos elementos tiene la pila, con la ayuda del objeto
nodo de tipo NodoPila, y se retorna.
Funciones de una cola
En la Tabla 10.2. Se describen las funciones propias para una Cola.
Tabla10.2. Funciones propia de una Cola
Función Descripción
Crear cola Inicia la cola como vacía (constructor)
Insertar Añade un elemento por el final de la cola
Retirar Retira (extrae) el elemento frente de la cola
Cola vacía Comprueba si la cola no tiene elementos
Frente Obtiene el elemento frente o primero de la cola
Tamaño de la cola Número de elementos que contiene la cola.
Fuente: propia
Para definir una cola, se desarrollara una clase ElementoCola, para
luego desarrollar la clase Cola con las funciones descritas anteriormente.
Observe la Figura 10.6. Que se encuentra el código fuente de la clase
ElementoCola.
1 public class ElementoCola {
2 private int dato ;
3 prívate ElementoCola ste ;
4 public ElementoCola ( int d ) {
5 dato = d ;
6 ste = null ;
7 }
8 public void setDato ( int d ) {
9 dato = d ;
10 }
11 public void setSte ( ElementoCola e ) {
12 ste = e ;
13 }
14 public int getDato( ){
15 return dato ;
16 }
17 public ElementoCola getSte ( ){
18 return ste ;
19 }
20 }
Figura 10.6. Código fuente de la clase ElementoCola
Fuente: propia
Como se puede apreciar en la Figura 10.6. La clase ElementoCola es
similar a la clase NodoPila, con un atributo int, y una referencia a un objeto
del mismo tipo de la clase (ElementoCola), con el constructor, y los métodos
para poder manipular los atributos desde fuera de esta clase.
A continuación el código correspondiente a la clase Cola. Ver Figura
10.7.
1 public class Cola {
2 private ElementoCola frente , fin ;
3 public Cola ( ) {
4 frente = null ;
5 fin = null ;
6 }
7 public void insertar ( ElementoCola nuevo ) {
8 if ( colaVacia ( ) ) {
9 frente = nuevo ;
10 fin = nuevo ;
11 }
12 else {
13 fin . setSte ( new ElementoCola ( nuevo . getDato ( ) ) ) ;
14 fin = fin . getSte ( ) ;
15 }
16 }
17 public ElementoCola retirar ( ) {
18 if ( colaVacia( ) )
19 return null ;
20 else {
21 ElementoCola x = new ElementoCola( frente. getDato( ) ) ;
22 frente = frente . getSte ( ) ;
23 return x ;
24 }
25 }
26 public boolean colaVacia ( ) {
27 if ( frente == null )
28 return true;
29 return false;
30 }
31 public ElementoCola Frente ( ) {
32 if ( colaVacia ( ) )
33 return null ;
34 return frente ;
35 }
Figura 10.7. Código fuente de la clase Cola (1/2)
Fuente: propia
36 public int tamañoCola ( ) {
37 ElementoCola x = frente ;
38 int cont = 1;
39 if ( ! colaVacia ( ) ){
40 while ( x != fin ) {
41 cont ++ ;
42 x = x . getSte ( ) ;
43 }
44 return cont;
45 }
46 return -1 ;
47 } /* fin del método*/ } //fin de la clase
Figura 10.7. Código fuente de la clase Cola (2/2)
Fuente: propia
De la Figura 10
constructor (Línea 3) se le asigna una referencia nula a los dos objetos.
El método insertar (Línea 7), se verifica el estado de la cola; si está
vacía, entonces el nuevo elemento será el primero y el ultimo de la cola; en
el caso que la cola tenga al menos un elemento, entonces se agrega al final
de la misma (Líneas 13 y 14).
Para retirar un elemento de la cola se tiene el método retirar en la
línea 17; si la cola no tiene elementos, este método devuelve una referencia
nula; si la cola posee al menos uno, se retira el que se encuentre de primero
en la cola (Líneas 21 y 22) y se retorna.
El método colaVacia , como su nombre lo indica, verifica el estado de
la cola y devuelve un valor de tipo boolean, verdadero si no tiene elementos;
y falso, si tiene al menos uno.
En la línea 31, el método Frente , que devuelve el primer elemento de
la cola, si éta no esta vacía, y una referencia nula si lo está.
Por ultimo se encuentra el método tamañoCola (Línea 36), que
entero, para contar los elementos, y luego devolver esta ultima variable
-1, indica que
la cola no contiene ningún elemento.
Funciones de una Lista
Las funciones de una estructura de datos dinámica como la lista, lo
primero es definir la clase que definirá el nodo, con los datos necesarios y la
referencia o enlace al siguiente; luego la clase para definir la lista con su
tope; la clase Nodo, y las instrucciones de los métodos perteneciente a la
clase lista dependerán de si es simple o doblemente enlazada, se estudiará
primero la simplemente enlazada.
Las funciones básicas en este tipo de estructuras de datos, depende de
las características de la aplicación que se va a realizar con los datos de la
lista. Sin embargo a continuación en la Tabla 10.3, se presentan las
funciones más usadas.
Tabla 10.3. Funciones para una Lista(1/2)
Función Descripción
Crear lista Inicializa la lista como vacía (constructor)
Es Vacia Determina si la lista está vacía
Insertar de primero Inserta un nodo, al principio de la lista
Fuente: propia
Tabla 10.3. Funciones para una Lista(1/2)
Insertar de último Inserta un nodo, al final de la lista
Insertar en medio Inserta un nodo, entre dos nodos existentes de la lista
Localizar Devuelve la posición donde está el campo buscado
Suprimir Elimina de la lista el nodo que se indica
Primero Devuelve la posición del primer nodo de la lista
Anula Vacía la lista
Fuente: propia
A continuación la clase NodoListaS, ver Figura 10.8
1 public class NodoListaS {
2 private int dato ;
3 private NodoListaS ste ;
4 public NodoListaS ( int d ) {
5 dato = d ;
6 ste = null ;
7 }
8 public void setDato ( int d ) {
9 dato = d ;
10 }
11 public void setSte ( NodoListaS s ) {
12 ste = s ;
13 }
14 public int getDato ( ) {
15 return dato ;
16 }
17 public NodoListaS getSte ( ) {
18 return ste ;
19 }
20 }
Figura 10.8. Código de la clase NodoListaS
Fuente: propia
En la Figura 10.8. Observe que la clase NodoListaS, es muy parecida a
las clases nodo o elementos vistos en las Figuras 10.4 y 10.6.
Las funciones de insertar de primero, insertar de último, insertar en
medio y suprimir; con listas enlazadas, se ilustran gráficamente, para facilitar
su comprensión.
El método insertar de primero: supóngase la lista simplemente
enlazada de la siguiente figura con los elementos 5, 8, 6, y se desea insertar
el elemento 1.
Paso 1
nuevo 1
5 8 6
primero
Paso 2
nuevo 1
5 8 6
primero
Paso 3:
nuevo 1
5 8 6
primero
El código de este método puede apreciarlo en la Figura 10.9, línea 11.
Para el método insertar de último, de la lista anterior, supóngase que
se desea insertar el elemento (9), entonces
Paso 1:
1 5 8 6
primero
Paso 2:
nuevo 9
1 5 8 6
primero
Paso 3:
nuevo 9
1 5 8 6
primero
El código de este método puede ser apreciado en la Figura 10.9, línea
19.
Para el método insertar en medio, de la lista anterior, supóngase que
se desea insertar el elemento (4) después del elemento (5), entonces
Paso 1:
1 5 8 6 9
primero
Paso 2:
nuevo 4
1 5 8 6 9
primero
Paso 3:
nuevo 4
1 5 8 6 9
primero
Paso 4:
nuevo 4
1 5 8 6 9
primero
El código de este método puede ser apreciado en la Figura 10.9, línea
29.
Para el método suprimir, son posibles cuatro casos:
1.- El elemento a eliminar este de primero
2.- El elemento a eliminar sea el último nodo
3.- El elemento este entre dos elementos más, y
4.- El elemento a eliminar no se encuentre en la lista.
Caso 1. El elemento a eliminar es el (1)
Paso 1:
1 5 4 8 6 9
primero
Paso 2:
1 5 4 8 6 9
primero
Paso 3:
5 4 8 6 9
primero
Caso 2. El nodo a eliminar es (9)
Paso 1:
5 4 8 6 9
primero
Paso 2:
5 4 8 6 9
primero
Paso 3:
5 4 8 6
primero
Caso 3. El elemento a eliminar es el (8)
Paso 1:
5 4 8 6
primero
Paso 2:
5 4 8 6
primero
Paso 3:
5 4 6
primero
Caso 4 elemento a eliminar no existe en la lista
En este caso el m´todo devuelve null.
A continuación, se define la clase ListaS en la Figura 10.9. Con todas
las funciones antes mencionadas.
1 public class ListaS {
2 private NodoListaS primero ; //primer elemento de la lista
3 public ListaS ( ) {
4 primero = null ;
5 }
6 public boolean esVacia ( ) {
7 if ( primero == null )
8 return true ;
9 return false ;
10 }
11 public void insertarPrimero ( NodoListaS n ) {
12 if ( esVacia ( ) )
13 primero = n ;
14 else{
15 n . setSte ( primero ) ;
16 primero = n ;
17 }
18 }
Figura 10.9. Código fuente de la clase ListaS (1/3)
Fuente: propia
19 public void insertarFinal ( NodoListaS n ) {
20 if ( esVacia ( ) )
21 primero = n ;
22 else{
23 NodoListaS x = primero ;
24 while ( x.getSte ( ) != null )
25 x = x . getSte ( ) ;
26 x . setSte ( n ) ;
27 }
28 }
29 public void insertarMedio ( NodoListaS despuesDe , NodoListaS n )
30 {
31 if( !esVacia() ) { //inserta en nodo n, después del nodo despuesDe
32 NodoListaS x = localizar ( despuesDe . getDato ( ) ) ;
33 if ( x != null ){
34 n . setSte ( x . getSte ( ) ) ;
35 x . setSte ( n ) ;
36 }
37 }
38 }
39 public NodoListaS localizar ( int d ) {
40 NodoListaS x = primero ;
41 if ( !esVacia() )
42 while ( x != null) {
43 if ( x . getDato() == d)
44 return x ;
45 x = x . getSte() ;
46 }
47 return null ;
48 }
45 public NodoListaS suprimir ( int d ) {
46 NodoListaS x = localizar ( d ) ;
47 NodoListaS y ;
48 if ( x != null ){
49 if( x . equals( primero)){ //si el nodo a eliminar es el primero
50 y = new NodoListaS ( x . getDato ( )) ;
51 primero = primero . getSte ( ) ;
52 }
Figura 10.9. Código fuente de la clase ListaS (2/3)
Fuente: propia
53 else
54 if( x. getSte()== null){// si el nodo a eliminar es el ultimo
55 y = primero ;
56 while ( !y . getSte ( ) . equals ( x ) )
57 y = y . getSte ( ) ;
58 y . setSte ( null ) ;
59 }
60 else {//si el nodo a eliminar esta en medio de dos nodos
61 y = primero ;
62 while ( !(y . getSte ( ) . equals ( x ) ) )
63 y = y . getSte ( ) ;
64 y . setSte ( x . getSte ( ) ) ;
65 }
66 return x ;
67 }
68 return null ;
69 }
70 public NodoListaS primero ( ) {
71 if ( !esVacia() )
72 return primero ;
73 return null;
74 }
75 public void anula ( ) {
76 primero = null ;
77 }
78 }
Figura10.9. Código fuente de la clase ListaS (3/3)
Fuente: propia
En la Figura 10.9. En el código fuente de la clase ListaS; se puede
primer nodo de la lista, este atributo se inicia con una referencia nula en el
constructor.
Luego en la clase, están desarrollados las funciones descritas
anteriormente ( esVacia() , (NodoListaS) ,
insertarFinal(NodoListaS) , insertarMedio(NodoListaS , NodoListaS) ,
localizar (int) , suprimir (int) , (),y ( ) ). Por la naturaleza de
los métodos insertar , localizar y suprimir , serán estos los explicados, ya
que los demás son muy sencillos, y elementales.
En la línea 11, se
será el primer nodo de la lista; en el caso que la lista tenga al menos un
elemento, entonces el primer nodo (actual) pasa a ser el segundo y el nuevo
En la línea 19, esta el método insertarFinal (NodoListaS) ; ocurre
similar que en el método anterior ( insertarPrimero ), si la lista no tiene
mer elemento; si la lista
tiene al menos un elemento, se recorre toda la lista con la ayuda del objeto
este método la lista debe tener al menos un elemento, recibe el nodo que
buscado y que le seguía, de esta forma se enlaza el nuevo.
En la
(línea 46); para la eliminación de un nodo en una lista, existen tres posibles
casos, que el nodo a eliminar se encuentre de primero en la lista, de ultimo, o
en medio de otros dos nodos. En el primer caso (línea 49) se le asigna al
primer nodo el segundo de la lista. En el segundo caso (línea 54), se recorre
la
del siguiente igual a nulo. El tercer y último caso (línea 60), que el nodo a
hasta el nodo que se encuentre antes del nodo a eliminar, para luego enlazar
Las listas doblemente enlazadas también necesitan una clase
NodoListaD, ésta varía de la anterior que se usan dos enlaces, al siguiente
nodo y al anterior. Ver Figura 10.10.
1 public class NodoListaD {
2 private int dato ;
3 private NodoListaD ant , ste ;
4 public NodoListaD ( int d ) {
5 dato = d ;
6 ant = null ;
7 ste = null ;
8 }
9 public void setDato ( int d ) {
10 dato = d ;
11 }
12 public void setAnt ( NodoListaD a ) {
13 ant = a ;
14 }
15 public void setSte ( NodoListaD s ) {
16 ste = s ;
17 }
18 public int getDato ( ) {
19 return dato ;
20 }
21 public NodoListaD getAnt ( ) {
22 return ant ;
Figura 10.10. Código fuente de la clase NodoListaD (1/2)
Fuente: propia
23 }
24 public NodoListaD getSte ( ) {
25 return ste ;
26 }
27 }
Figura 10.10. Código fuente de la clase NodoListaD (2/2)
Fuente: propia
La clase NodoListaD, varia de la clase NodoListaS en que esta nueva
clase tiene dos referencias a objetos, el nodo que le antecede y el nodo que
sigue.
La clase ListaD, se define en la Figura 9.11
1 public class ListaD {
2 private NodoListaD primero ;
3 public ListaD ( ) {
4 primero = null ;
5 }
6 public boolean esVacia ( ) {
7 if ( primero == null )
8 return true ;
9 return false ;
10 }
11 public void insertarPrimero ( NodoListaD n ) {
12 if ( esVacia ( ) )
13 primero = n ;
14 else{
15 n . setSte ( primero ) ;
16 primero . setAnt ( n ) ;
17 primero = n ;
18 }
19 }
20 public void insertarFinal ( NodoListaD n ) {
Figura 10.11. Código fuente de la clase ListaD (1/3)
Fuente: propia
21 if ( esVacia ( ) )
22 primero = n ;
23 else{
24 NodoListaD x = primero ;
25 while ( x . getSte ( ) != null )
26 x = x . getSte ( ) ;
27 x . setSte ( n ) ;
28 n . setAnt ( x ) ;
29 }
30 }
31 public void insertarMedio ( NodoListaD despuesDe , NodoListaD n )
32 {
33 if( !esVacia() ) {
34 NodoListaD x = localizar ( despuesDe . getDato ( ) ) ;
35 if ( x != null ){
36 x . getSte ( ). SetAnt ( n ) ;
37 n . setSte ( x . getSte ( ) ) ;
38 n . setAnt ( x ) ;
39 x . setSte ( n ) ;
40 }
41 }
42 }
43 public NodoListaD localizar ( int d ) {
44 NodoListaD x = primero ;
45 if ( !esVacia() )
46 while ( x != null) {
47 if ( x . getDato() == d)
48 return x ;
49 x = x . getSte() ;
50 }
51 return null ;
52 }
53 public NodoListaD suprimir ( int d ) {
54 NodoListaD x = localizar ( d ) ;
55 NodoListaD y ;
56 if ( x != null ){
57 if ( x . equals ( primero ) ){
Figura 10.11. Código fuente de la clase ListaD (2/3)
Fuente: propia
58 y = new NodoListaD ( x . getDato ( )) ;
59 primero = primero . getSte ( ) ;
60 primero . setAnt ( null ) ;
61 }
62 else
63 if ( x . getSte() == null ){
64 y = primero ;
65 while ( !y . getSte ( ) . equals ( x ) )
66 y = y . getSte ( ) ;
67 y . getSte ( ) .setAnt ( null ) ;
68 y . setSte ( null ) ;
69 }
70 else {
71 y = primero ;
72 while ( !(y . getSte ( ) . equals ( x ) ) )
73 y = y . getSte ( ) ;
74 y . setSte ( x . getSte ( ) ) ;
75 x . getSte ( ) . setAnt ( y ) ;
76 x . setAnt ( null ) ;
77 x . setSte ( null ) ;
78 }
79 return x ;
80 }
81 return null ;
82 }
83 public NodoListaD primero ( ) {
84 if ( !esVacia() )
85 return primero ;
86 return null;
87 }
88 public void anula ( ) {
89 primero = null ;
90 }
91 }
Figura 10.11. Código fuente de la clase ListaD (3/3)
Fuente: propia
De la Figura 10.11. Se aprecia que están ilustrados los métodos
equivalentes a la clase ListaS, de la Figura 9.9, los métodos que fueron
alterados en esta nueva clase ListaD, son los de insertar, y suprimir, porque
a
enlace al nodo anterior, por esta razón en los métodos donde se ingresa o
elimina un nodo, hay que actualizar las dos referencias de los nodos o
elementos involucrados en el cambio.
10.2.3 Resolución de problemas usando estructuras de datos
fundamentales.
Implemente al concepto de pilas para que permita que el usuario
pueda hacer el llamado de los métodos push y pop según lo desee. El
máximo de la pila será de 10 posiciones.
Realice un programa que usando el concepto de lista doble permita
reproducir el ejemplo mostrado en la Figura 10.12.
12
14
15
25
22
42
Figura 10.12. lista doblemente enlazada
Basándose en las siguientes clases, desarrolle un método que permita
ordenar la lista, tomando como parámetro para esta tarea el atributo
duración (ordene toda la lista utilizando dicho atributo).
class CNodo { class CLista {
String nombre , autor , interprete ; CNodo nodoInicial ;
int duración; CLista ( ) {
CNodo ant , ste; nodoInicial = null ;
CNodo ( ) { }
public void ordenar ( ) {
//Desarrolle aquí.
}
duracion = 0 ; }
ste = null ;
ant = null ; } }
CONCLUSIONES
Se analizo el contenido de la asignatura, para tener las consideraciones
necesarias con cada uno de los temas que conforman las unidades, este
análisis permitió reconocer los temas mas difíciles de explicar y asi darle mas
énfasis a la búsqueda de material relacionado con ellos.
En la revisión bibliografica relacionada al paradigma de programación
orientado a objetos, se recopilo conceptos, definiciones y ejemplos para
ampliar la comprensión del contenido de las unidades de la asignatrura; de
esta forma ilustrar conceptos mas comprensibles para los estudiantes de la
asignatura.
Esta guía didáctica fue desarrollada con altísimo cuidado, referente a la
programación orientada a objetos con la finalidad de que los estudiantes
inscritos en la asignatura cuenten con un material de fácil comprensión, con
el contenido de la asignatura y asi puedan consultar todos los temas en una
sola guía; Se elaboro respetando el paradigma, y sus características,
logrando una alta calidad en su contenido.
RECOMENDACIONES
Fomentar el uso de la guía didáctica en la asignatura de Objetos y
Abstracción de Datos, tanto en el Núleo de Anzoátegui, como en los demás
núcleos de la Universidad de Oriente donde se dicte la carrera de Ingenirería
de Sistemas.
Actualizar la guía didáctica conforme a la publicación de nuevas
ediciones de libros, para que asi siempre este renovado su contenido,
evitando que la información de esta se vuelva obsoleta.
Elaborar una guía de probemas que se adapte a las necesidades de los
estudiantes de dicha asinatura, para asi complementar esta guía didáctica.
Elaborar guias didácticas para las demás asignaturas del Departamento
de Computación y Sitemas, agrupando la información necesaria de los temas
que las conforman.
Convertir la guía didáctica en un material multimedia que sea mas
atractivo a los estudiantes de la asignatura, donde se facilite el conocimiento
y ellos puedan usar varios sentidos reforzando el aprendizaje.
BIBLIOGRAFÍA
Arias, F. (1999). EL PROYECTO DE INVESTIGACION.Guía para su
elaboración. (3RA. EDICIÓN) Editorial Episteme. Caracas.
Bruer, J.T. (1999): Escuelas para pensar, una ciencia de aprendizaje en
el aula, Madrid, Ediciones Paidós.
Ceballos, J. (2003). Java 2 curso de programación. Cuarta
edición.Editorial RA-MA. Madrid.
Deitel, H. y Deitel, P. (2004). Java cómo programar. Quinta edición.
Editorial Pearson. México.
Drozdek, A. (2007).Estructura de datos y algoritmos en Java. Segunda
edición.Mexico.
Edwards, D.; y Mercer, N. (1988). El conocimiento compartido. El
desarrollo de la comprensión en el aula. Barcelona: Paidós/MEC.
García, L. (2002): La Educación a Distancia, de la teoría a la práctica,
Madrid, Ed. Ariel, S.A.
Groussard, T.(2010). Java 6 Las bases del lenguaje y de la
Programación orientada a objetos. Ediciones Eni. Barcelona, España
Martinez, M (1998). El contrato del profesorado. Condiciones para una
nueva escuela. Ed. Desclee de brouwer. Bilbao Solera, L. Araya, F. Hugo, V.
(2008). La Benemérita Universidad estatal a distancia en la sociedad del
conocimiento. Editorial Universidad Estatal a Distancia. San José, Costa
Rica.
Weiss, M. (2000). Estructuras de datos en Java.Editorial Pearson
Madrid.
METADATOS PARA TRABAJOS DE GRADO, TESIS Y ASCENSO:
TÍ TULO GUIA DIDÁCTICA PARA LA ASIGNATURA OBJETOS Y
ABSTRACCIÓN DE DATOS, DICTADA A LOS ESTUDIANTES
DE ING. EN COMPUTACIÓN Y DE ING. DE SISTEMAS, EN LA
UNIVERSIDAD DE ORIENTE
SUBTÍ TULO
A UTOR ( ES) :
A PELLI D OS Y N OM B RES CÓD I GO CULA C / E M A I L
CVLA C: V - 1 4 .6 1 6 .6 8 3
VERA CI ERTA TOV A R, GA BRI ELA
E M A I L:
M A RÍ A
g a b r i e l a v e r a c i e r t a t @h o t m a i l .co m
CVLA C:
E M A I L:
CVLA C:
E M A I L:
PA LÁ BRA S O FRA SES CLA VES:
GUI A I NSTRUCCI ONAL_
PROGRAMACI ÓN ORI ENTADA A OBJETOS
LENGUAJE JAVA
OBJETOS Y ABSTRACCI ÓN DE DATOS_
HERENCI A
POLI MORFI SMO
RECURSI VI DAD
ESTRUCTURAS DE DATOS
M ETA D A TOS PA RA TRA BA JOS D E GRA D O, TESI S Y A SCEN SO:
À REA SUB À REA
Profesor Asist ent e
Trabaj o de Ascenso
RESUM EN ( A B STRA CT) :
La a si g n a t u r a Ob j e t o s y A b st r a cci ó n d e D a t o s e s m u y
i m p o r t a n t e , b a se f u n d a m e n t a l e n e l á r e a d e d e sa r r o l l o d e
so f t w a r e , u sa n d o e l p a r a d i g m a o r i e n t a d o a o b j et o s q u e e s u n o
d e l o s m á s u sa d o s a ct u a l m e n t e ; a l o s e st u d i a n t e s se l e s d i f i cu l t a
i n v e st i g a r e n b i b l i o g r a f ía s b i en s e a p o r l a d i f i cu l t a d d e a d q u i r i r
l i b r o s a ct u a l i za d o s, e n co n t r a r l o s e n l a sa l a d e l ect u r a d e l
d e p a r t a m e n t o y e n l a b i b l i o t e ca ; ó p o r q u e e n i n t e r n e t n o
e n cu e n t r a n i n f o r m a ci ó n a d e cu a d a o e s e x p u e st a d e u n a f o r m a
e n t e n d i b l e p a r a p r i n ci p i a n t e s, p o r t a l m o t i v o se d e sa r r o l l o u n a
g u ía d i d á ct i ca co n l a i n f o r m a ci ó n n e ce sa r i a p a r a q u e e l
e st u d i a n t e p u e d a co m p r e n d e r d e u n a m a n e r a p r e ci sa t o d o el
co n t e n i d o d e l a a si g n a t u r a ; y d e e s t a f o r m a p o d e r co n su l t a r l a e n
cu a l q u i e r m o m e n t o y d i si p a r d u d a s r e f e r e n t e a u n t e m a
p e r t e n e ci e n t e a l a s u n i d a d e s, co n u n l e n g u a j e co m p r e n si b l e p a r a
n i v e l d e co n o ci m i e n t o ; t a m b i é n p u e d e n co n su l t a r l a a n t e s d e
cl a se s, o s i m p l e m e n t e r e p a sa r e l co n t e n i d o d i scu t i d o .
M ETA D A TOS PA RA TRA BA JOS D E GRA D O, TESI S Y A SCEN SO:
CON TRI BUI D ORES:
A PELLI D OS Y N OM B RES ROL / CÓD I GO CVLA C / E_ M A I L
ROL CA AS TU x JU
CVLA C:
E_ M A I L
E_ M A I L
ROL CA AS TU JU x
CVLA C:
E_ M A I L
E_ M A I L
ROL CA AS TU JU x
CVLA C:
E_ M A I L
E_ M A I L
ROL CA AS TU JU
CVLA C:
E_ M A I L
E_ M A I L
FECH A D E D I SCUSI ÓN Y A PROB A CI ÓN :
2012 05
AÑO M ES DÍ A
LEN GUA JE. SPA
M ETA D A TOS PA RA TRA BA JOS D E GRA D O, TESI S Y A SCEN SO:
A RCH I VO ( S) :
N OM BRE D E A RCH I V O TI PO M I M E
Guia Didáct ica Para La Asignat ura Obj et os Y Application/ m sword
Abst racción De Dat os, Dict ada A Los Est udiant es De
I ng. En Com put ación Y De I ng. De Sist em as, En La
Universidad De Orient e
CA RA CTERES EN LOS N OM BRES D E LOS A RCH I VOS: A B C D E F G H I J K
L M N O P Q R S T U V W X Y Z. a b cd e f g h i j k l m n o p q r st u v w x y
z. 0 1 2 3 4 5 6 7 8 9.
A LCA N CE
ESPA CI A L: _ __________________________________ ( OPCI ON A L)
TEM PORA L: _ __________________________________ ( OPCI ON A L )
TÍ TULO O GRA D O A SOCI A D O CON EL TRA BA JO:
Trabaj o de Ascenso a la Cat egoría de Profesor Asist ent e
N I VEL A SOCI A D O CON EL TRA B A JO:
Trabaj o de Ascenso
Á REA D E ESTUD I O:
Depart am ent o de Com put ación y Sist em as
I N STI TUCI ÓN :
Universidad de Orient e Núcleo Anzoát egui
Ga b r i e l a M a r ía Ve r a ci e r t a To v a r
_______________ _______________
JURA D O JURA D O
______________
JURAD O