Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ed. Garceta Programación Isabel Jimenez
Ed. Garceta Programación Isabel Jimenez
Ed. Garceta Programación Isabel Jimenez
DAM y DAW
10
:Ü>
i
Técnico Superior en Desarrollo de Aplicaciones Multiplataforma y Web
DAM y DAW
10
:Ü>
i
Programación
M
94
:! i
Sh
m
i'ii
Técnico Superior en Desarrollo de Aplicaciones Muitipiataforma y Web f.'
DAM y DAW
Programación
ISBN; 978-84-1545-259-1
IBERGARCETA PUBUCACIONES, S.L., Madrid 2013
Edición; 1."
Impresión: 1.®
N.° de páginas: 500
Formato: 20 x 26 cm
Reservados ios derechos para todos los países de lengua española. De conformidad con io dispuesto en el artículo 270 y siguientes del
código penal vigente, podrán ser castigados con penas de multa y privación de libertad quienes reprodujeren o plagiaren, en todo o en
parte, una obra literaria, artística o científica fijada en cualquier tipo de soporte sin la preceptiva autorización. Ninguna parte de esta
publicación, incluido ei diseño de la cubierta, puede ser reproducida, almacenada o trasmitida de ninguna forma, ni por ningún medio
sea éste electrónico, químico, mecánico, electro-óptico, grabación, fotocopia o cualquier otro, sin ia previa autorización escrita por parte
de ia editorial.
obra^^^ ^ CEDRO (Centro Español de Derechos Reprográficos), www.cedro.org, si necesita fotocopiar o escanear algún fragmento de esta
Programación
Impresión:
PRINT HOUSE, marca registrada de Copiar, S. A.
Nota sobre enlaces a páginas web ajenas: Este libro puede incluir referencias a sitios web gestionados por terceros y ajenos a IBERGAR
CETA PUBLICACIONES, S.L., que se incluyen sólo con finalidad informativa. IBERGARCETA PUBLICACIONES, S.L., no asume ningún tipo
de responsabilidad por ios daños y perjuicios derivados del uso de los datos personales que pueda hacer un tercero encargado del man
tenimiento de las páginas web ajenas a IBERGARCETA PUBLICACIONES, S.L., y del funcionamiento, accesibilidad y mantenimiento de
los sitios web no gestionados por IBERGARCETA PUBUCACIONES, S.L., directamente. Las referencias se proporcionan en ei estado en
que se encuentran en el momento de publicación sin garantías, expresas o implícitas, sobre ia información que se proporcione en ellas.
INDICE GENERAL
CAPITULO 1. INTRODUCCION
1.1. Introducción 2
1.2. Conceptos básicos 2
1.2.1. Algoritmo vs programa 2
1.2.2. Características de un programa 4
1.2.3. Lenguaje de programación 5
1.2.3.1. Clasificación en función de la cercanía a la máquina 6
1.2.3.2. Clasificación en función del propósito del lenguaje 7
1.2.3.3. Clasificación en función de la evolución histórica 7
1.2.3.4. Clasificación en función de la forma de ejecución 8
1.2.3.5. Clasificación en función de cómo afrontan las tareas a realizar 8
1.2.3.6. Clasificaeión en función del estilo de programación empleado 9
1.2.3.7. Clasificación en función de la capacidad de generar procesos concurrentes
o no 9
1.2.3.8. Clasificación en función de la interactividad 10
1.2.3.9. Clasificación en funeión de si son o no visuales 10
1.2.4. Código 10
1.2.5. Palabras reservadas del lenguaje 11
1.3. Diseño de un programa 11
1.3.1. Fase de análisis del problema 11
1.3.2. Fase de diseño del algoritmo 12
1.3.3. Fase de programación (codificación) 13
1.3.4. Fase de pruebas y depuración 14
1.3.5. Fase de documentación 15
1.3.6. Ejemplo de creación de un programa 15
1.4. Diagramas de flujo 20
1.4.1. Reglas para diseñar diagramas de flujo 20
1.5. Pseudocódigo 22
1.6. Proceso de compilación 22
1.6.1. Nuevas tendencias en el proceso de creación de código objeto 25
1.7. Entornos de desarrollo integrado de software o IDE 26
1.8. Microsoft Visual Studio 2012 Express 26
1.8.1. Registro de Visual Studio 2012 Express para escritorio 28
1.8.2. Página principal de Visual Studio 2012 Express 30
1.8.3. Crear un nuevo proyecto en Visual Studio 2012 Express 31
1.8.4. Estructura de un proyecto en Visual Studio 2012 Express 32
1.8.5. Guardar y abrir un proyecto existente en Visual Studio 2012 Express 33
1.8.6. Ejecutar un proyecto compilado sin errores 34
1.9. Entorno de desarrollo Netbeans 34
1.9.1. Instalación de Netbeans 7.3 + JDK 35
1.9.2. Pantalla inicial de Netbeans 7.3 36
1.9.3. Crear un nuevo proyecto en Netbeans 7.3 37
1.9.4. Estructura de un proyecto en Netbeans 7.3 39
1.9.5. Guardar y abrir un fichero existente Java Netbeans 7.3 39
1.9.6. Ejecutar un proyecto compilado sin errores en Netbeans 7.3 39
COMPRUEBA TU APRENDIZAJE 40
ACTIVIDADES DE AMPLIACIÓN 40
CAPITULO 4. FUNCIONES
Este libro está diseñado para ser el libro de texto del módulo profesional Programación que
se imparte en los ciclos fonnativos de grado superior Desarrollo de Aplicaciones
Multiplatafomia y Desarrollo de Aplicaciones Web. Incluye los contenidos mínimos que
indican los RD 450/2010, de 16 de abril y 686/2010, de 20 de mayo, ampliando estos a los
contenidos mínimos expresados en los Decretos y Ordenes de algunas comunidades autónomas.
Es un libro enfocado a su uso diario en clase, con una secuencia de contenidos lógica y
personalizada en función de mi propia experiencia profesional. Cada capítulo está estructurado
de forma que veremos:
■ Contenido teórico.
■ Conceptos básicos relacionados con el software, como qué se entiende por programa o
algoritmo y qué diferencia existe entre programa y proceso, lenguaje de programación,
clasificación de los lenguajes de programación, compilación del software o entornos de
desarrollo preparados para la creación de software. Centraremos nuestra atención en
lenguajes como C# y Java y los IDE Visual Studio y Netbeans.
■ Metodología de la programación. Antes de comenzar a programar en C# o Java se
realizarán pequeños algoritmos al mismo tiempo que se estudian los componentes
principales de un programa estructurado. Creación de diagramas de flujo y
pseudocódigos.
■ Una vez se conocen los elementos que componen un programa estructurado se pasarán
a codificar estos en C# y Java. Variables, identificadores, tipos de datos simples y
compuestos, sentencias de control alternativas o bucles, etc., consiguiendo construir
aplicaciones funcionales.
■ Programación orientada a objetos. Los conceptos principales que confonnan este
paradigma de la programación. Clases, objetos, herencia, polimorfismo, interfaz, etc.
xiv Programación
Para fmalizar, quisiera hacer hincapié en que éste documento refleja claramente la parte de
contenidos y secuencia de contenidos de la programación didáctica que realizaría para el
módulo profesional Programación. Se ha realizado con mucho esmero, teniendo en cuenta los
Resultados de Aprendizaje y Criterios de Evaluación establecidos en los Reales Decretos
indicados al comienzo del texto.
CAPÍTULO 1
INTRODUCCIÓN
j CONTENIDOS / OBJETIVOS
Algoritmo vs Programa. Saber qué es un algoritmo,
Características de un progi^ama. diferenciación con el ténuino
programa. Características.
Lenguajes de programación.
¿Qué son? Tipos Saber qué es un lenguaje de
programación y tipos que existen.
Código. Fases de desarrollo del
software. Proceso de compilación Conocer las fases por las que pasa
Diagramas de flujo y
un programa antes de salir al
mercado y ser usado. Entender el
pseudocódigo
proceso de compilación.
Entornos de desarrollo
Iniciar el uso de IDEs, Visual
integrados (IDE). Visual Studio y
V Studio y Netbeans.
\ Netbeans.
Hoy día, todos estamos acostumbrados a usar un sistema informático y las diferentes
aplicaciones instaladas en él, los procesadores de texto, hojas de cálculo, vemos el correo o
ficheros gráficos, etc., todos tenemos ordenador en casa o acceso a algún PC.
Cuando se comienza a estudiar informática se inicia estudiando qué es un sistema
informático. Un sistema informático es un conjunto formado por tres partes: hardware, sofirware
y el hombre.
■ HARDWARE. Es la parte tangible del sistema, parte física. Se denomina hardware a
todos los componentes físicos que forman el sistema informático, todas aquellas
piezas que forman "la torre" del ordenador junto a la pantalla, impresora, y demás
elementos que aún no incluyéndose en "la torre" interactúan de algún modo con ella.
■ SOFTWARE. Es la parte no tangible. La forman todas aquellas aplicaciones o
programas instalados en el equipo. El software se clasifica en software base y
software de aplicación. El primero de ellos referencia al sistema operativo, necesario
para que podamos usar el PC, sin él el equipo no sería más que un conjunto de
componentes anclados a la placa base. El software de aplicación hace referencia a
todas aquellas aplicaciones diseñadas para realizar una operación concreta y que
pueden ser usadas sobre un software de aplicación concreto.
■ EL HOMBRE. Es una parte importante del sistema ya que es quien usa el mismo.
Sin la iteración del hombre de nada serviría que tuviéramos un hardware y un
software.
En este libro vamos a dedicamos al estudio del software, concretamente al desarrollo del
mismo. Se estudiarán conceptos básicos sobre desarrollo de aplicaciones, entornos de desarrollo
y lenguajes de programación como C# y Java.
Antes de comenzar a desarrollar software es necesario que el lector tenga claro una serie de
conceptos básicos. Entre estos conceptos el término inicial a describir seria Algoritmo. Según la
RAE (http://www.rae.es) un Algoritmo es un conjunto ordenado y finito de operaciones que
permite hallar la solución de un problema. Imaginemos que queremos realizar un viaje a
Capítulo 1. Introducción 3
Londres y necesitamos comprar los billetes de avión, esta situación sería el problema que
debemos resolver. Para comprar' los billetes debemos:
1. Localizar las direcciones de varias agencias de viajes.
2. Usar algún medio de transporte e ir a la primera de las agencias en horario comercial.
3. Una vez en la agencia plantear vuestras necesidades al agente.
4. Atender a las explicaciones que os aporta el empleado de la agencia, horarios,
precios, etc.
5. Volver al paso 2 hasta que se hayan visitado todas las agencias.
6. Escoger entre todas las ofertas aquella que más nos interesa.
7. Volver a la agencia que tiene la mejor oferta o bien realizar una llamada telefónica (si
es posible).
8. Concretar forma de pago.
Para solucionar nuestro problema (comprar los billetes para realizar un viaje a Londres) se
deben seguir una serie de pasos u operaciones. Este conjunto de operaciones es finito y
naturalmente ordenado, la secuencia debe ser tal y como se indica, por ejemplo no podemos
concretar formas de pago si antes no se ha ido a una agencia. Asi, acabamos de desarrollar un
algoritmo, de hecho de fonna cotidiana estamos continuamente generando algoritmos ya que
continuamente se plantean problemas que debemos solucionar.
Ahora bien, cuando este problema debe ser resuelto en un ordenador, el algoritmo se
convierte en lo que se denomina programa. Seguimos usando una secuencia ordenada y finita de
pasos pero escrita en un lenguaje que la máquina es capaz de entender.
La unidad mínima de almacenamiento de un ordenador se denomina bit. Un bit puede
adquirir los valores 1 o O, ya que el sistema de numeración usado es el sistema binario. Un
conjunto de bits representan tanto los números como las letras que posterionnente veremos en
nuestra pantalla. Al conjunto de 8 bits se le denomina byte. Debido a que cada vez es mayor la
infonnación que se almacena en un equipo no usamos simplemente bytes para definir esta,
debemos utilizar los prefijos Kilo, Mega, Giga, etc., para representarla, de forma que:
1 byte
1 KB (Kilobyte) r"= 1024 bytes
1 MB (Megabyte) 2-°= 1024 KB
1 GB (Gigabyte) 2^°= 1024 MB
1 TB (Terabj^e) 2^°= 1024 GB
1 PB (Petabyte) 2^°= 1024 TB
1 EB (Exabyte) 2®°= 1024 PB
1 ZB (Zettabyte) 2™= 1024 EB
1 YB (Yottabyte) 2®°= 1024 ZB
Supongamos que realizamos la compra de forma tradicional dirigiéndonos a una agencia de viajes.
1.2.2. CARACTERISTICAS DE UN PROGRAMA
■ Debe ser finito. Estar formado por un conjunto finito de líneas de fomia que en algún
punto ve alcanzado su fin.
■ Debe ser legible. Es importante crear códigos "limpios" y fáciles de leer, con
tabulaciones y espacios que diferencien las partes del programa. Si desarrollamos
códigos bien estmcturados nos será más fácil la corrección de errores y modificación
del mismo.
Busing Systemj
using Systera.Collections.Generic;
using System.Linq;
using Systein.Text;
Figura 1.1. Código fuente con lineas de código mal estructuradas. Poco legible.
Busing System;
using System.Collections.Generic;
using System.Linq;
using Systera.Text;
Bnamespace HolaMundo{
B class Prograir{
B static void Hain(string[] args){
Consolé.WriteLine("Hola mundo");
Consolé.ReadLine();
}
Figura 1.2. Código fuente con iíneas de código bien estructuradas. Fácil de entender, detectar errores y
modificar.
■ Debe ser fácilmente modlficable, es decir, debe estar diseñado de fonna que debe ser
sencillo el proceso de actualización o modificación del mismo ante las nuevas
necesidades del usuario final.
■ Debe ser eficiente. El usuario acabará usando programas que solucionen sus
problemas de la mejor y más rápida forma posible, así debemos crear programas que
ocupen poco espacio en memoria y se ejecuten rápidamente.
■ Deben ser modulares. Esta característica ayuda a que el programa sea más legible y
fácil de entender. Debemos perseguir realizar algoritmos que se encuentren divididos
en subalgoritmos de forma que se disponga de un grupo principal desde el que
llamaremos al resto. Al usar subprogramas además incitamos la reutilización de
código y evitamos la repetición de este.
■ Deber estar estructurado. Esta característica engloba de alguna fonna las anteriores,
ya que un programa estructurado será fácil de leer, de modificar y estará compuesto
de subprogramas que permitirán la reutilización de código.
NOTA: A la hora de realizar las actividades que encontrará en los capítulos que
fonnan el libro se aconseja al lector que sus diferentes códigos fuente posean las
características mencionadas. Para ello:
Habitualmente el ser humano se comunica a través del uso del lenguaje, es decir, es capaz de
generar una serie de sonidos que fonnan lo que conocemos como fonemas, pasadas al papel son
las letras de nuestro alfabeto, qué combinadas constituyen las sílabas, palabras y frases. A este
lenguaje se le conoce como lenguaje natural.
Lenguaje natural = comunicación hombre •(-> hombre.
Un ordenador comunica sus componentes hardware mediante la emisión de señales eléctricas,
pulsos que vienen a fonnar los valores O (no se aplica voltaje) y 1 (si se aplica voltaje). Así, la
CPU da una orden a la memoria mediante una combinación de ceros y unos, algo similar a
1101001. A esta fonna de comunicación se le denomina lenguaje máquina.
Lenguaje máquina = comunicación máquina^ máquina.
Un lenguaje de programación es similar al lenguaje humano o lenguaje máquina, la diferencia
estriba en que la comunicación se realiza entre hombre y ordenador, es decir, im lenguaje de
programación es aquel por el que el PC es capaz de entender qué esta diciéndole el ser humano
que haga.
Lenguaje de programación = comunicación hombre <-> ordenador.
A la hora de combinar los diferentes sonidos en el lenguaje natural seguimos una serie de
reglas. Una frase está fonnada por sujeto + verbo + predicado, a su vez, cada verbo está
representado en una forma verbal concreta, sabemos que se ha finalizado una frase porque se
realiza una pausa antes de comenzar con la siguiente y existe un número limitado de letius y
palabras. En un lenguaje de programación pasa exactamente igual:
Persona encargada de escribir en un lenguaje de programación concreto un programa que posee cierta
finalidad.
Capítulo 1. Introducción 7
Podemos clasificar un lenguaje de programación en función del tipo de programas que son
capaces de generar;
■ Lenguajes de propósito general. Son lenguajes diseñados para realizar cualquier
tipo de programa, desde software base a software de aplicación. Un lenguaje de este
tipo es C.
■ Lenguajes de propósito específico. Lenguajes que se diseñan para actuar en una
determinada área y generar programas con una finalidad determinada. Estos lenguajes
dispondrán de palabras reservadas y funciones propias para la explotación del área de
trabajo concreta.
Sabías que...
FORTRAN (Formula Translating System) aparece debido a la necesidad de
agilizar las tareas y la dificultad que suponía trabajar con el lenguaje máquina o lenguaje
ensamblador. A finales de 1953, John W. Backus propone a sus superiores de IBM
comenzar a trabajar en un nuevo proyecto por el que se desarrollara un lenguaje de
programación más sencillo y cómodo de utilizar para programa el IBM 704. Fue a
mediados de 1954 cuando se consolida el primer borrador de la especificación y en
octubre de 1956 cuando aparece el primer manual de FORTRAN. Fue usado
ampliamente por la comunidad científica, desarrollando potentes programas de análisis
matemático. i
'Conjunto de programas, desarrollados por otros, que podemos usar en nuestros propios programas.
Capítulo 1. Introducción 9
que se debe llegar. En ellos no se indica de forma expresa los pasos a seguir para
alcanzar la solución, solo se plantean una serie de reglas y en función de estas se van
describiendo los pasos. Se usan normalmente en inteligencia artificial.
A la hora de crear un programa podemos optar por escribir todo el código, línea a línea, como
un solo bloque, realizar pequeños bloques incluidos en el programa principal a los que se hace
referencia desde este o bien crear ficheros independientes con subprogramas a los que
accederemos según nuestras necesidades. Así, según lo explicado encontraremos:
■ Lenguajes de programación estructurados. En estos lenguajes encontraremos el
código tal que se haya estructurado en un conjunto de funciones. Suelen poseer una
función principal que es llamada en el momento de ejecución. Esta función hará uso
del resto según decida el programador. Podemos hablar además de programación
modular en los casos en los que se usan otros ficheros, llamados módulos, en los que
se agrupan funciones diseñadas para trabajar con el mismo tipo de datos o están
relacionadas según algún criterio establecido por la persona que crea la aplicación.
■ Lenguajes de programación orientada a objetos. En este tipo de lenguajes se usan
elementos denominados clases de fonna que se pretende con ellos reflejar al máximo
posible la realidad que rodea el software. Así, si en el tipo anterior se agrupan en
funciones líneas de código según tareas o acciones a realizar, en la programación
orientada a objetos la agrupación se realiza en función del objeto que se quiere
plasmar en el programa. Por ejemplo, si queremos realizar un programa que gestione
un concesionario de vehículos programaremos una clase que llamaremos vehículo, en
ella (en este conjunto de líneas) incluiremos todo lo que rodea a un coche, desde sus
características a las funciones que pueden desarrollarse sobre él.
1.2.3.7. CLASIFICACIÓN EN FUNCIÓN DE LA CAPACIDAD DE GENERAR
PROCESOS CONCURRENTES O NO
La concurrencia es la ejecución de varios procesos a la vez. Generalmente usamos de forma
errónea los ténninos programa y proceso. Debe quedar claro que;
■ Programa. Es el código que hemos generado, que es correcto y está listo para
ejecutarse pero aún no está en ejecución.
■ Proceso. Una vez damos la orden de ejecutar nuestro programa y este se coloca en
memoria y es decodificado instrucción a instrucción por el procesador se le denomina
proceso.
Los lenguajes de programación usan una serie de palabras o símbolos que desempeñan una
función específica dentro un programa. A este conjunto se signos o combinación de ellos se les
denomina palabras reservadas.
Estas palabras solo pueden usarse en un concepto detenninado, nunca libremente por el
usuario.
Así, a la hora de construir un programa se deben seguir una serie de pautas o fases:
■ Análisis del problema.
■ Diseño del algoritmo.
■ Codificación.
■ Prueba y depuración.
■ Documentación.
Así, nonnalmente, cuando una persona individual o una empresa nos encarga la realización de
un programa debemos concertar una entrevista de fonna que de ella obtengamos ima visión
particular de las necesidades del usuario o la empresa y de las tareas que debe realizar el
software.
La fase de análisis en una parte fundamental del proceso de desarrollo de un programa, una de
las más importantes, ya que un mal análisis puede hacer que un programa ya codificado y
probado deba realizarse de nuevo.
entrevista CON
EL USUARIO FINAL
PROGRAMADOR
en esta se identifican soluciones a los problemas planteados, así como pasos de ejecución para
concretar las tareas.
Figura 1.6. A la izquierda se muestra el pseudocódigo ejemplo del apartado anterior. A la derecha
vemos el programa de este algoritmo escrito en C++.
1. La definición de la función se realiza mediante void notaAsignatura, concretamente
son tipo de dato devuelto y nombre de la función.
2. Se establece el entorno, es decir, los elementos de almacenamiento de infonnación
(variables) que debemos usar. En nuestro programa a este componente se llama Nota.
3. Se escribe en pantalla el mensaje "'''Introduce una notd\ C y C-h- usan la función
printf para mostrar información al usuario mediante el display o dispositivo hardware
de salida por defecto.
4. Llegados a este punto el programa se detiene a la espera de que el usuario escriba la
información pedida. Se recoge el dato en el componente Nota antes declarado. Una
de las fimciones que utilizan C y C-H- para la lectura de infonnación es scanf. Esta
función necesita saber qué tipo de información va a recoger, es decir, si será un
número, un texto, un valor decimal o un carácter, de ahi el %¡.
Al llegar a la condición vemos que esta dice algo como "si nota es mayor que 5 escribe
Suspenso", nuestra nota es 8, mayor que 5, así la palabra Suspenso es lo que se visualizará,
pero, ¿es correcta la solución? Evidentemente no, ya que una nota de 8 es muy aceptable y para
nada se considera suspenso. Dada esta situación, el desarrollador del programa sustituirá el
símbolo > por < y seguirá realizando nuevas pruebas.
Cuando todos los valores de entrada posible se hayan analizado y se hayan observado todas
las salidas obtenidas, si estas son correctas daremos por finalizada la fase de depuración y
pruebas.
Sl'-l Salida 1
Salida 2
Salida 3
Entrada 1
Entrada 2
Entrada 3
Entrada n
^ Los ejemplos usados en estos apartados son muy sencillos ya que interesa que el lector entienda los
conceptos estudiados y no la programación en sí.
16 Programación
Concertamos una entrevista con la persona encargada en la empresa que pueda hablamos
sobre el tipo de software que necesita. En esta entrevista preguntaremos qué tipos de datos de
entrada se deben usar, una vez se procese un dato qué salida se debe obtener, si se produce un
error qué se espera visualizar, etc.
Tras el encuentro queda claro que:
1. El programa solicitará un número. Solo se pueden comprobar los 100 primeros
números. El cero no es un valor válido.
2. En caso de que el número sea par se visualizará en la pantalla "El número introducido
es par".
3. En caso de que el número sea impar se visualizará en la pantalla "El número
introducido es impar".
4. Si el número a comprobar es el cero se visualizará por pantalla el mensaje "Valor
incorrecto, el cero no es un valor válido".
5. Si el número introducido es menor que O o mayor de 100 se mostrará en pantalla el
mensaje "Número introducido fuera de rango. Rango de número válido para
comprobar 1 - 100".
FASE 2. DISEÑO DEL ALGORITMO
Ya tenemos los datos necesarios para comenzar a trabajar. Sabemos qué desea el usuario final
que ocurra en determinadas situaciones de ejecución así que construiremos el diagrama de flujo
del programa y su pseudocódigo. Ejemplos de ambos elementos podrían ser los expuestos a
continuación.
(1)PROGRAMA: numeroPar
(2)ENTORNO: Numero^, Modulo son números entero
(3)ALGORITMO:
(4)escribir "Introduce un numero"
(5)leer Numero
(6)SI Numero = O ENTONCES
(7)escribir "Valor incorrecto, el cero no es un valor
válido"
(8)SI Numero < O |
| Numero > 100 ENTONCES
(9)escribir "Número introducido fuera de rango. Rango de
número válido para comprobar 1 - 100"
(lO)SI NO
(11)Modulo = Resto de Numero/2
(12)SI Modulo = O ENTONCES
(13)escribir "El número introducido es par"
(14)SI NO
(15)escribir "El número introducido es impar"
(16)FIN SI
(17)FIN SI
(18)FIN PROGRAMA
^ Aunque estamos escribiendo pseudocódigo y este se asemeja al lenguaje que usamos normalmente,
evitaremos usar letras acentuadas, así como la ñ, en ningún elemento del programa ya que en la mayoría de
lenguajes de programación no se aceptan estas singularidades.
el resto de la división entera de Numero entre
dos.
FASE 3. CODIFICACIÓN
La base anterior es una de las más complejas ya que concretamos exactamente las partes del
algoritmo. En esta todo es más sencillo ya que solo debemos "traducir" el algoritmo a un
lenguaje de programación concreto. En realidad esta fase será más o menos compleja en función
del lenguaje de programación que usemos.
Veamos línea a línea como será el código de nuestro programa teniendo en cuenta que
usaremos C-H- como lenguaje de programación.
(1)PROGRAMA: numeroPar void numeroParO {
(2)ENTORNO: Numero", Modulo son
int Numero, Modulo;
números entero
(3)ALGORITMO:
printf ("Introduce un numero");
(4)escribir "Introduce un numero"
scanf ("%i",Numero);
(5)leer Numero
if (Numero ==0) {
(6)51 Numero = 0 ENT0NCE5
printf ("Valor incorrecto, el
(7)escribir "Valor incorrecto, el cero
cero no es un valor válido");
no es un valor válido"
)
(8)51 Numero < 0|
| Numero > 100 else if (Numero < 0 |1 Numero > 100) {
ENT0NCE5 printf("Número introducido
(9)escribir "Número introducido fuera fuera de rando. Rango de número válido
de rando. Rango de número válido para para comprobar 1 - 100");
comprobar 1 - 100" }
else {
(10)51 NO
Modulo = Numero mod 2;
(11)Modulo = Resto de Numero/2
if (Modulo == 0){
(12)51 Modulo = 0 ENTONCES
printf ("El número
(13)escribir "El número introducido es
introducido es par");
par"
)
(14)51 NO
else {
(15)escribir "El número introducido es
printf ("El número
impar"
introducido es impar");
(16)FIN 51
}
(17)FIN 51
}
(18)FIN PROGRAMA }
^ Aunque estamos escribiendo pseudocódigo y este se asemeja al lenguaje que usamos normalmente,
evitaremos usar letras acentuadas, así como la fi,en ningún elemento del programa ya que en la mayoría de
lenguajes de programación no se aceptan estas singularidades.
Capítulo 1. introducción 19
void numeroParO {
int Numero, Modulo;
printf ("Introduce un numero");
scanf Numero);
if (Numero == 0) {
printf ("Valor incorrecto, el cero no es un valor válido");
else {
Modulo = Numero mod 2;
if (Modulo == 0){
printf ("El número introducido es par");
else {
printf ("El número introducido es impar");
Esta es la función completa escrita en C-H-. Se ha comprobado que está libre de fallos
sintácticos, léxicos y semánticos.
FASE 4. PRUEBAS Y DEPURACIÓN
A partir de ahora comenzamos a ejecutar el software. Se debe comprobar que ante
detenninadas entradas las salidas son las esperadas. Las entradas que pueden presentar
problemas son:
■ Número 0.
■ Número negativo.
■ Número superior a 100.
Al ejecutar la aplicación visualizaremos un entorno en modo texto como el que se observa en
la Figura 1.10.
Introduce un numero Escribiremos un cero. Debe aparecer el texto
Valor incorrecto, el cero no es un valor válido
Introduce un numero
Figura 1.10. Programa sin entorno visual Figura 1.11. Ejecución del software y comprobación
en ejecución. de las salidas en función de ios valores de entrada.
Realizaremos este proceso con todos los valores de entrada posibles. Observaremos las
salidas, y si son las que se plantearon en el algoritmo el programa estará listo para ser usado. Si
se produce algún fallo, o alguna salida no es la esperada para el valor introducido volveremos al
código fuente y localizaremos el lugar donde se produce el error en ejecución. Ya estudiaremos
cómo visualizar los cambios que se dan en los valores introducidos durante la ejecución mediante
la depuración en los diferentes entornos de programación que utilizaremos.
El código planteado realiza las funciones tal y como la empresa detalló de forma que
pasaremos a la fase de documentación.
FASE 5. DOCUMENTACION
Antes de entregar el software a la empresa que nos lo encargó realizaremos un breve manual
sobre el mismo. Este podría ser similar al que se muestra a continuación.
Los elementos del diagrama de flujo deben estar concatenados mediante flechas que
indican la dirección de ejecución.
Disco magnético.
Salida. Visualización de los datos de salida por pantalla. Este suele ser
siempre el periférico de salida por defecto.
■ Debemos evitar el cruce de líneas, para eso se define la forma conector. El uso de
conectores debe producirse cuando no exista otra opción.
■ Todas las líneas de flujo deben estar conectadas a algún objeto.
■ A la hora de escribir texto en las formas, este debe ser escueto y legible.
■ Todos los símbolos de decisión deben tener más de una línea de salida, es decir,
deben indicar qué camino seguir en función de la decisión tomada.
Existen otras fonnas que pueden usarse en un diagrama de flujo pero no creemos que sea
necesario profundizar en ellas.
22 Programación
Dado el siguiente organigrama, indica qué Realiza el diagrama de flujo tal que se de
tarea realiza. un dato de entrada X. Si la X es igual a 1
mostraremos el texto "Has pulsado 1". En caso
de que sea 2 el texto a visualizar será "Has
pulsado 2".
1.5. PSEUDOCODIGO
La palabra pseudocódigo puede ser traducida como falso lenguaje, y no hay nada más
acertado que su definición. Un pseudocódigo es una descripción informal de un programa, siendo
de gran utilidad a la hora de diseñar el algoritmo del mismo. En pseudocódigo usamos lenguaje
natural o similar para representar estructuras propias del lenguaje de programación que usaremos
en la codificación, es decir, simulamos un lenguaje de programación.
El pseudocódigo, aunque usa el lenguaje natural, no utiliza su amplia variedad de palabras, se
seleccionan una serie de palabras como reservadas para representar todas las estructuras que
posteriormente deberán ser codificadas mediante el lenguaje de programación.
Se han visto ejemplos de pseudocódigo en los apartados 1.3.2 y 1.3.6. Estudiaremos en más
profundidad las palabras reservadas en pseudocódigo cuando empecemos a conocer las
diferentes estructuras de control y su significado en el Capítulo 2.
Un compilador está formado por dos partes fundamentales, cada una de ellas se divide en
otras tantas necesarias para cubrir todos los pasos del proceso. Así, dispone de: Análisis y
Sintesis.
3. Los tokens analizados son correctos. Algunos como int, =,+ se encuentran en la tabla
de símbolos con anterioridad, el resto se agrega a esta.
4. Al ser correcto el análisis léxico pasamos al análisis sintáctico. I— a —i
En este paso debemos aseguramos de que la frase o instrucción |||
sea correcta. Se genera un árbol sintáctico por el que se b + 2
deduce si la instrucción está bien formada en el lenguaje de Figura 1.14.
1.14. Árbol
Árbol
programación que estamos usando. En todo momento el sintáctico
sintáctico de
de la
la
manejador de errores estará alerta por si se produce algún tipo instrucción C++.
instrucción C++.
de error en alguna etapa.
5. Si no se han producido fallos en la estructura de la frase pasaremos a comenzar el
análisis semántico. Los errores sintácticos son errores de estructura, frases o
instmcciones mal formadas en un lenguaje concreto, por ejemplo si nuestra
instmcción hubiera sido int a=b+2; se hubiera producido un error sintáctico, ya que
en una asignación tras el igual debe aparecer valor o variable y no otro igual. El
análisis semántico analizará el significado de la frase. La palabra int indica que
Instrucción C++
Capítulo 1. Introducción 25
estamos creando una variable de tipo entera, así, b debe serlo para que al realizar la
suma el resultado sea entero y pueda almacenarse en a.
6. Si la fase semántica es superada correctamente se generará un código intemiedio.
7. A continuación se producirá la optimización del código intermedio.
8. Para finalizar el compilador obtendrá el código objeto, código máquina, listo para ser
linkado" o unido a diferentes librerías, y así obtener el fichero final a ejecutar.
La siguiente figura muestra el proceso completo de generación de software a partir de un
lenguaje compilado.
I > 7y. 1
' 'Mi
Programa ^
ejecutable
Figura 1.15. Diagrama representativo de las fases de creación de un programa ejecutable a partir de un
código fuente expresado en algún lenguaje de programación.
"El proceso de linkar o enlazar consiste en agregar a nuestro código fuente aquellas librerías externas
usadas en nuestro programa.
26 Programación
■ El código intermedio es interpretado cuando pasa a ser ejecutado sobre una máquina
concreta.
O bien los entornos incluyen analizadores capaces de compilador o interpretar código de diferentes
lenguajes o se pueden agregar complementos al entomo de desarrollo.
GUI = Graphical User Interface, interfaz gráfica de usuario.
Capítulo 1. introducción 27
ACTIVIDAD 1.3
Accede a la web oficial de Microsoft Visual Studio. Localiza una tabla comparativa de todas
las versiones y observa las características de la versión Premium con MSDN.
En cuanto a la versión Express podemos elegir entre 5 opciones, cada una de ellas orientada al
tipo de dispositivo donde se va a ejecutar la aplicación o el entorno donde se visualizará. Así, en
la web de Microsoft encontraremos Visual Studio Express 2012 para:
■ Web. Diseñado para el desarrollo de aplicaciones web.
■ Windows 8. Esta versión pennite la creación de aplicaciones para Windows 8.
Sabemos que el entorno visual de este nuevo sistema operativo de Microsoft ha
cambiado drásticamente de forma que se ajusta más a las necesidades de usuario con
sistemas de pantalla táctil, así, las aplicaciones tal y como conocemos en Windows 8
tienden a desaparecer. Aprende a programar en este nuevo entorno con esta
herramienta.
La instalación del software es sencilla. Una vez montada la unidad virtual o introducido el CD
en la unidad lectora de CD/DVD, debemos acceder al contenido y hacer doble clic sobre el
fichero wdexpress_full.exe.
28 Programación
Tras acabar con la instalación y ejecutar el software debemos registramos para poder usar la
versión de evaluación de forma indefinida más allá de 30 días. Al ejecutar por primera vez
Visual Studio se visualiza una ventana en la que se indica la necesidad de registro como usuario,
en ella podemos directamente acceder al registro o cancelar. En el primer caso el programa nos
redirige a la web de registro, en el segundo accedemos a la ventana principal para comenzar con
el uso de Visual Studio Express 2012. Si no registramos en primer lugar el software podremos
hacerlo posteriormente haciendo clic en Ayuda Registrar producto.
1.8.1. REGISTRO DE VISUAL STUDIO EXPRESS 2012 PARA
escritorio
Para registrar Visual Studio Express es necesario mostrar la pantalla de registro. Si es la
pnmera vez que ejecutamos el programa aparecerá por defecto en primer lugar, en caso
contrario, si cancelamos el registro en la primera ejecución accederemos a ella tal y como se
indica al finalizar el apartado anterior(Ayuda -> Registrar producto).
Esta pantalla requiere que se introduzca un número o clave del producto. Esta clave la
concederá Microsoft tras el registro en línea. Así, para obtener el número identificativo del
producto seguiremos los siguientes pasos.
1. Clic en Registrar en línea.
2. Debemos registramos en la web como usuario msn. Si tenemos una cuenta msn válida,
por ejemplo Hotmail, accederemos al sistema con ella.
3. Rellenar el formulario de registro, está compuesto por varias pantallas. Los campos cuyo
nombre esté precedido por un asterisco (*) son obligatorios. A la hora de introducir la
información:
Capítulo 1. Introducción 29
Et r>e<esano registrarte para continuar usando Microsoft Visual Studio 4. Clic en Continuar.
Ejcpress 2012 para escmono de Windows.
Clave del producto: 5. Aún no ha finalizado el registro:
■ En la lista Identifique su rol
académico actual,
seleccionaremos Estudiante de
instituto.
6. Clic en Continuar.
7. Finalmente aparecerá la clave de registro. Copiar esta y Pegar en el cuadro Clave del
producto. Véase la Figura 1.18.
clave de producto:
MIVIVJ9-FKy74-W449Y-RB79G-8GJGJ
Figura 1.19. Clave de Visual Studio Express 2012 para la cuenta e información proporcionadas en el
registro de la aplicación.
Desde la misma web de registro podemos descargar una guía de uso del programa.
ACTIVIDAD 1.4
"Este libro está destinado a ser libro de texto del módulo profesional Programación de los ciclos
formativos de grado superior Desarrollo de Aplicaciones Multiplatafonna y Desarrollo de Aplicaciones
Web, así el fonnulario de registro se rellena en función a esta infonnación. Si el lector ha adquirido el libro
sin ser alumno de ciclo, se aconseja que se rellenen estos campos con los datos que crean oportunos y se
acerquen más a su realidad profesional o personal.
30 Programación
-v
r*t AnM .
*tevt^4íd« f" %/V*»» C* •
)i;«vrtfad«s ce A«a*«<4
VWv*»«A rarvw
^
:
f r! drw'cAo dri 4
Recjrtot dr «T'e'idzJ^
RecufWí de «ipíeívíiíjje
•yr^. « *. (?I (*< , ^dCcr^Ck* tt* A9} p«r« /«eJJ
wéi Anpv« '
d» ifl P»rj »fJ' MíOOe-. .".T*
fc*crcMi« 0c API p#f« ••
.: j* R ^ »jc;«»c«>» * »r,;r4' íti*i6A dcptrei*—tn y icor ec . .v-rf ^.ív
Vid««»dc tty^' 'Aytúft m CK«iVic; e
teu UKV-e(<e • l'U **'
y
Figura 1.20. Página principal de Visual Studio Expresa 2012 para aplicaciones de escritorio Windows.
Al ejecutar la aplicación, sobre todo si es la primera vez que se accede al software y no se ha
configurado aún este, se muestra el entorno con una página de inicio llamada Página Principal.
Esta página pretende servir de ayuda al usuario de forma que pueda contar con todo tipo de
recursos y así mejorar sus aplicaciones, solventar problemas y sacar el máximo partido al IDE.
Si cerramos la página podemos volver a hacerla visible haciendo clic en Ver -> Página
principal.
La Figura 1.20 representa una captura de la página principal de Visual Studio. Las zonas
señaladas como ', v2/ y'..3. proporcionarán información al usuario sobre diversos aspectos:
1. Muestran información sobre las novedades de los diferentes lenguajes de
programación que se pueden usar en el DDE.
2. Zona de ayuda con instmcciones de cómo compilar y operar con la aplicación.
3. Zona de estudio y aprendizaje. Desde aquí podremos conocer los objetos que
posteriormente usaremos en nuestro código y solucionar problemas.
/"7^
La zona enmarca la barra de menús y herramientas. A lo largo del libro iremos utilizando
sus funciones de depuración, ejecución, etc.
En la zona v5/ encontraremos accesos directos para la creación de proyectos o apertura de
aquellos que se hayan generado con anterioridad. Además, los programas modificados
recientemente se visualizarán también aquí.
Finalmente, la zona "-I/ está compuesta por dos casillas de verificación que penniten
personalizar el inicio de Visual Studio Express 2012. Si permanecemos activa la casilla Cerrar
la página después de cargar el proyecto la página principal se cerrará para dejar paso a la
Capítulo 1. Introducción 31
nueva aplicación. En caso de mantener activa la casilla de verificación Mostrar página al inicio
estaremos confirmando que deseamos visualizar la página principal cada vez que accedamos al
programa. Estas características serán configuradas a gusto por el lector.
WindcwsApplicationl v ^
Aceptar |
j Cancelar
'1
1. Escogemos el tipo de proyecto que vamos a realizar en la zona Como ya se ha
estudiado en párrafos anteriores este IDE permite programar en Visual Basic, C-H- y
C#, así estos son los tres tipos de proyectos entre los que podremos elegir. Clic en
Visual C# y Windows.
2. Los iconos de la zona central variarán. La diferencia entre los proyectos que podemos
crear en Visual Basic y C# es mínima, básicamente el lenguaje de programación que
usaremos, sin embargo, si escogemos C++ para programar el abanico de posibilidad
se amplía pudiendo crear incluso archivos MAKE.
ACTIVIDAD 1.5
ACTIVIDAD 1.6
Accede a Visual Studio Express 2012 y crea un nuevo proyecto, aplicación de consola,
denominado HolaMundo. El nombre debe ser tal y como se indica, sin espacios en blanco.
que foirnan el proyecto y la solución a la que está asociado. Es similar al explorador de Windows
que conocemos ampliamente.
Entre los elementos que fonnan el proyecto
(2 'Q - í? « QÜ @1 A[P encontramos:
Euscjr en el E>plcradcr de sclucicnes (CtrI* }
Solución'HolaMundo' Proyecto) ■ Properties. Propiedades de los
elementos del proyecto. Es una
t> Properties
í> References caipeta. Si estamos generando una
Q App.config aplicación de consola solo
> C" Program.cs
encontraremos en esta carpeta el
fichero AssemblyInfo.es.
■ Rreferences. Referencias extemas,
código generado con anterioridad y
que podemos usar libremente en
nuestro proyecto.
Figura 1.23. Explorador de soluciones de Visual
Studio Express 2012.
■ Java EX.
Capítulo 1. Introducción 35
Para poder usar Java como lenguaje de programación, además del paquete de Netbeans
debemos descargar el JDK actual, acorde con la versión del IDE que hayamos descargado.
Las siglas JDK proceden de Java Development Kit, es decir Kit de Desarrollo para Java. Es
un software que incluye hen-amientas de desarrollo para la creación de aplicaciones Java. Así,
cuando vayamos a proceder con la instalación de Netbeans en primer lugar debemos haber
instalado el JDK correspondiente en nuestro equipo.
Podemos descargar el JDK actual desde el sitio URL que nos aconseja la web oficial de
Netbeans, http://java.sun.com/javase/downIoads/index.jsp. De fonna alternativa, y en lugar de
realizar la descarga de Netbeans y JDK por separado podemos descargar el pack con ambos
elementos desde la web http://java.sun.com/javase/downIoads/widget/jdk_netbeans.jsp.
Dicho todo esto, y presuponiendo que el lector no tiene instalado ni la versión JDK ni
Netbeans, vamos a proceder a descargar el paquete que contiene ambos elementos desde la
segunda dirección web propuesta en el párrafo anterior:
http://java.sun.com/javase/downloads/widget/jdk_netbeans.jsp.
; Java 6 and later versions are required for installmg and running the PHP and C/C++
i NetBeans Bundies, You can download the latest Java at lava con
i -
I JDK 6 and later versions are require/ 1 ^stalling and running the Java SE,Java EE and
, AJI ttetBeans Bundies You can tíownVtad standalone JDK or dovvnioad the latest.ink
: with I lelEeans IDE Java SE Ouncie. ^
4. Aparecerá una ventana informativa en la que entre otras cosas se orienta al usuario
sobre el espacio en disco necesario para la instalación. Hacemos clic en Install y
comenzará el proceso de forma instantánea.
5. Pasado un tiempo que dependerá del equipo que estemos usando podremos comenzar
a usar el entomo de desarrollo.
jRle Edh View Nsvigate Source Refactcr Run Oebug Profiie Team Toob Wíndow Hdp f X ¡
Q d ti : Kí C' B ¿3 I-' i'-i> * *.J)
'
|fac iáe Vaw KtwígMt Sowct Rcf*ctor Rur» Oebug Profiic Tom Tnná^lYirif|riwí Hdp
i f; £J «í % e- • 's 2.Í'•0-
CK** AfpbcaStons
PHP ^t<>{ilie9>0AS
Uotde ano E moeooeo i>ccu»ons
Al Oolne Docvmeruabon »
Cuando ejecutamos Netbeans por primera vez la Figura 1.26 nos indica qué visualizaremos.
Al igual que ocum'a en Visual Studio veremos una Start Page o Página de inicio donde se
proporciona información al usuario sobre el IDE así como la fonna de utilizar este.
Encontraremos enlaces, tutoriales y demos bastante interesantes En la zona superior se ubica
la barra de menús y herramientas desde la que accederemos a toda la funcionalidad del software,
ya estudiaremos cómo hacer uso de algunos de sus comandos para compilar o depurar nuestros
programas ^l'. Para finalizar, la zona representada como solo apunta a la casilla de
verificación por la que podemos hacer que esta pantalla de inicio sea siempre o no visible cuando
accedamos a DDE.
I j 1^ Qt A0pkaaon
I j ^ CaS5 Lfcirary
^ Pro^t mCM Cxstng Soeces
.J. Mívrn
JavARwPOfmProject
1^ MedJes
... u i
I Create* a new Java SC applKaOon n a standard ID6 pro^t, You can alse penefate a man daas
rt the pro)cct. Standard prp^rcts use an IDt-ocnrrated Ant build «cnpt r^,«nd debup
yc«.r provecí-
NOTA: Aún muchos de los conceptos que se están tratando pueden resultar extraños !
e incomprensibles para el lector. Rogamos que tenga paciencia, en este apartado estamos |
estudiando de fonna escueta los IDE que vamos a usar y las funciones principales de j
estos, pero será en otros capítulos cuando todos los contenidos se afiancen. Por lo pronto i
sólo debemos entender dónde hacer clic para generar un nuevo programa, y el tipo de
proyecto y propiedades que activar, más adelante entenderemos el porqué.
6. Estableceremos como nombre de proyecto HoIaMundo (sin espacio en blanco entre
palabras), como ubicación aquella que queramos, sería interesante crear una carpeta
nueva donde albergar todos los proyectos Java. Por último, mantenemos activa la
casilla Crear clase principal (Create Main Class).
7. Clic en Finish. Tras unos segundos veremos en el explorador de proyectos el nuevo
proyecto que acabamos de generar.
ProjectLocabon: C:VJ5ers\:5á)dV>xxmcnt5YíetSedf«Pro)ccts
Líxa-iesFocer:
Figura 1.28. Pantalla de configuración de características del nuevo proyecto del asistente de creación de
proyecto nuevo.
; Explorador de proyecte^J
SmwAmm Cm 0*1^ Uwm IMH W>í<íii
tiEjüCíi
•) Smtitge_ m ¿«WMfidajM
t iJ» j Htfcr» 'li'iy!• ^u &i
Proyecto
HoIaMundo
etwf Hela#
Sabías que...
Muchos especulan el porqué del símbolo de taza de café o grano de café cuando
nos referimos al lenguaje de programación Java. Parece ser que una de las hipótesis
; que pisan con más fuerza es la de que el nombre Java procede de un tipo de café que
i
' tomaban los desarrolladores del lenguaje en una cafetería cercana. Si nos fijamos en los
primeros 4 bytes del fichero .class generado por el compilador observaremos que en
! hexadecimal aparecen como OxCAFEBABE.
Podemos almacenar un fichero concreto sobrescribiendo su eontenido, guardar este con otro
nombre o guardar todos los ficheros que hayan sido modificados al mismo tiempo. Para ello
tenemos desde el menú File las opciones:
■ Save. Almacena el fichero que esté seleccionado.
■ Save as...Para guardar un fichero con otro nombre u otra ubicación.
■ Save all. Pemiite almacenar todos los ficheros que hayan sido modificados
reemplazando sus contenidos por las nuevas modificaciones.
De igual modo podremos abrir un nuevo proyecto a partir de File Open Project...
Además encontraremos opciones de importación y exportación tanto en Netbeans como en
Visual Studio. Son interesantes cuando queramos agregar elementos a nuestros proyectos.
1.9.6. EJECUTAR UN PROYECTO COMPILADO SIN ERRORES EN
NETBEANS 7.3
Netbeans es un entorno de programación que al igual que Visual Studio proporciona
infonnación en tiempo real de los fallos de compilación que se vayan produciendo. Veremos una
linea de color rojo en la zona errónea, subrayando esta, como hacen muchos editores de texto
cuando detectan palabras con faltas ortográficas.
A la hora de ejecutar una aplicación en Netbeans localizaremos
en la barra de herramientas el botón Run Proyect caracterizado con
una flecha de color verde. O bien accederemos al menú Run y Figura 1.31. Botón de
seguidamente Run Project. ejecución.
COMPRUEBA TU APRENDIZAJE
1. ¿Qué diferencia existe entre un algoritmo y un programa?
2. ¿Cuáles son las características de un programa?
3. ¿Qué se entiende por lenguaje de programación? ¿Qué diferencia existe entre un
lenguaje compilado y un lenguaje interpretado?
4. ¿Qué se entiende por código fuente? ¿Y código objeto?
5. ¿Cuáles son las fases de creación de un programa?
6. ¿Qué es un diagrama de flujo? ¿Qué se entiende por falso lenguaje?
7. ¿En qué consiste la fase de análisis léxico en el proceso de compilación?
8. ¿Qué es un IDE?
9. ¿Qué entiende Visual Studio por proyecto y solución?
10. ¿Qué pasos hemos de seguir para crear un nuevo proyecto en NetBeans?
ACTIVIDADES DE AMPLIACION
1. En el capitulo hemos hablado de la existencia de "enlazadores o linkers" en el
proceso de creación del programa ejecutable. Busca un poquito más de infonmación
sobre estos elementos, cómo funcionan, características, etc., y desarrolla un
documento breve donde incluyas todo lo que hayas localizado.
2. Imagina que te llaman de una empresa de venta de vinos para realizar un pequeño
programa. El software debe gestionar los clientes que acceden a la empresa. En la
fase de análisis, ¿qué preguntas realizarías a la persona que te encarga la realización
del trabajo? Desarrolla un pequeño esquema donde expliques con tus palabras qué
acciones ejecutaría el programa, qué información almacenaría, etc.
3. Ahora supón que trabajas para una empresa dedicada a la formación y quieren
comenzar a trabajar con enseñanza on-line. Te piden diseñar un programa para que el
alumno pueda contactar vía web y a partir de ahí comenzar a recibir la clase. ¿Qué
tipo de preguntas realizarías en la fase de análisis para conocer en profundidad lo que
Capítulo 1. Introducción 41
el usuario final te está pidiendo? Desarrolla un esquema donde indiques los elementos
que incorporarlas al programa y cómo lo estructurarías.
4. Crea un proyecto de consola en Visual Studio llamado Proyecto_Pruebal.
5. Realiza la actividad anterior en Netbeans.
METODOLOGIA DE LA PROGRAMACION
CONTENIDOS / OBJETIVOS
Pseudocódigo y diagramas de Conocer los elementos
flujo. fundamentales de los diagramas de
flujo y comenzar a usarlo.
Variables y constantes.
Saber qué son sentencias
Operadores.
alternativas: simple, doble y
Sentenicas de control múltiple.
alternativas.
Conocer las diferentes sentencias
Sentencias de control: bucles. repetitivas que nos podemos
encontrar.
Teorema de la programación
desarrollada. Conocer el teorema de la
\ programación estructurada.
2.1. INTRODUCCION
En el Capítulo 1 se estudiaban conceptos informáticos relacionados con la programación de
aplicaciones, se introducían elementos como diagramas de flujo y pseudocódigo y se empezaban
a instalar los EDE que posteriormente usaremos para la generación de código C# y Java.
En este capitulo que acabamos de comenzar se pretende enseñar al alumno una serie de pautas
para realizar algoritmos que posteriormente puedan ser codificados en cualquier lenguaje de
programación, haciendo uso de diagramas de flujo y pseudocódigo. Además, se estudiarán las
sentencias de control y elementos más comunes en un algoritmo, como variables, constantes,
sentencias condicionales, repetitivas, etc.
Asi, el objetivo de este capitulo es asentar las bases de la programación, de forma que el
lector sepa a ciencia cierta plantear el algoritmo de un problema dado siguiendo una serie de
pasos por los que:
1. Analizará el problema planteado.
2. Diseñará un diagrama de flujo.
3. Traducirá el diagrama de flujo a pseudocódigo.
2.2. PSEUDOCÓDIGO
El pseudocódigo se puede definir como un lenguaje intermedio entre el lenguaje natural y el
lenguaje de programación que usaremos posteriormente para generar nuestro programa. Es un
lenguaje, también denominado falso lenguaje, que permite generar algoritmos dando soluciones a
problemas planteados. Este falso lenguaje, muy similar al lenguaje que usamos non-nalmcnte,
está sujeto a unas reglas concretas.
Sentencias de control.
• Alternativas.
• Bucles.
2.2.1.1. EL ENTORNO
El entorno no es más que un grupo de objetos que usaremos para almacenar información de
algún tipo. Estos objetos se denominan variable y constante.
Una variable es un contenedor donde guardaremos un valor. Este contenedor será
referenciado mediante un identificador o nombre. El valor de este contenedor puede variar
durante la ejecución del programa.
Si usamos un ejemplo de la vida cotidiana podemos comparar una variable con una caja de
cartón sin cerrar. La caja, al iniciar el día puede estar vacía, a las 2 de la tarde contener un par de
libros y a las 8, los libros pueden haber sido extraídos y en su lugar ubicar una muñeca. A su vez
podemos escribir un nombre en el exterior de la caja, por ejemplo "Mis cosas". Así,"Mis cosas"
es el nombre o identifícador de la caja o variable mientras que los libros, la muñeca e incluso el
estado de vacío son los elementos que puede contener o los valores que puede alcanzar.
Una constante es similar a una variable en el contexto de que almacenan un valor y es
referenciada mediante un nombre, sin embargo este valor no variará a lo largo de la ejecución del
algoritmo. Si tenemos una constante llamada PI y al comenzar el pseudocódigo hemos
establecido que su valor es 3.1416 este será el dato que almacenará durante toda la ejecución.
Si volvemos a nuestro ejemplo de la caja de cartón, imaginemos que al despertar hemos
cogido una caja de cartón, hemos metido dentro un libro, se ha realizado una pequeña abertura en
uno de los lados, se ha rotulado con el nombre "Mis cosas" y se ha cerrado con cinta adhesiva.
En esa caja de cartón no podremos ni extraer ni insertar otros objetos, sin embargo siempre
podremos ver su contenido, además se llama "Mis cosas", hemos creado un objeto constante,
cuyo estado no variará a lo largo del tiempo.
A la hora de declarar los objetos del entorno en pseudocódigo':
■ Comenzaremos con la palabra Entorno seguida de dos puntos (:).
■ Tanto constantes como variables deben especificar el tipo de datos^ que van a
almacenar.
■ Para definir una constante usaremos la palabra reservada constante, seguida del tipo
de dato y del nombre. La sentencia finalizará con la asignación del valor deseado.
■ Para definir una variable especificaremos el tipo de datos que va a almacenar seguido
del nombre de la variable. En caso de que queramos asignar un valor inicial a esta
usaremos el símbolo igual seguido del valor correspondiente.
'Existe otra forma definir los objetos en un entorno en pseudocódigo pero se ha escogido esta debido a
que es la que se encuentra más acorde con los lenguajes de programación que se van a estudiar.
^ Tanto Java como C# son lenguajes de programación tipados, es decir, a la hora de declarar las
variables y constantes deben indicarse explícitamente el tipo de datos que van a almacenar. Existen otros
lenguajes que no lo son, por ejemplo PHP. En PHP el tipo de la variable se establece cuando se le asigna
un valor.
Declaración de una constante: i constante tipojiato nombre_constante=valor;
_ , ., j . ., : tipo dato nombre variable;
Declaración de una variable: : . r ~ ,
: tipo dato nombre variable=valor;
En pseudocódigo las líneas se verían del siguiente modo:
Entorno:
constante tipo dato nombre_constante==valor;
tipo_dato nombre;
tipo_dato nombre=valor;
Un ejemplo de algoritmo real sería algo así como lo que se muestra a continuación:
Entorno:
constante real PI=3.1416
entero radio=2;
real area;
; Entorno:
I constante real PI=3.1416
; entero radio=2;
ALGORITMO RESUELTO 1
ENUNCIADO
Imaginemos que se nos pide la ereaeión de un algoritmo que debe contener una constante
llamada gravedad a la que asignaremos el valor 9.8 y las variables velocidad y tiempo, esta
última tendrá asignado el valor de 2.
DESARROLLO - FASE DE ANÁLISIS
Este es nuestro primer algoritmo y debido a que aún no hemos estudiado demasiadas
secuencias o instrucciones es muy simple. Lo primero que debemos hacer es analizar el
problema:
■ Leemos tantas veces como nos sea necesario el enunciado.
■ Una vez lo hayamos entendido pasamos a exponer nuestras conclusiones. Estas son:
—> Tenemos que crear una constante (gravedad) y asignarle 9.8.
Tenemos que crear una variable llamada velocidad.
—> Tenemos que declarar una variable llamada tiempo que tendrá como valor
inicial el número 2.
La comunicación con el usuario será esencial para cualquier programa que diseñemos en un
futuro. Normalmente necesitaremos interactuar con el usuario de fonna que establezca los
valores que quiere usar en el algoritmo a partir de los cuales se generarán diferentes datos de
salida.
^ La variable velocidad se ha establecido como real aunque en el enunciado no se deja claro de que tipo
debe ser. Podemos decir que los tres objetos interactuarán de una forma o de otra en el futuro, y debido a
esto y al existir una constante real la variable velocidad también deberá ser de este tipo.
Capítulo 2. Metodología de la programación 49
ALGORITMO RESUELTO 2
ENUNCIADO
Imaginemos que se nos pide la creación de un algoritmo que debe contener una constante
llamada gravedad a la que asignaremos el valor 9.8 y las variables velocidad y tiempo.
Debemos solicitar al usuario que especifique qué valor de tiempo tenemos que usar.
DESARROLLO - FASE DE ANÁLISIS
Lo primero que debemos hacer es analizar el problema:
■ Leemos tantas veces como nos sea necesario el enunciado.
■ Una vez lo hayamos entendido pasamos a exponer nuestras conclusiones. Estas son:
Tenemos que crear una constante (gravedad) y asignarle 9.8.
—> Tenemos que crear dos variable llamadas velocidad y tiempo.
Debemos pedir al usuario qué dato asignar a la variable tiempo. La petición
siempre estará compuesta de un mensaje indicando que se quiere y la
posterior lectura del dato que el usuario final incluye. Así al pedir debemos
escribir en pantalla que tipo de petición estamos realizando y leer el dato
que el usuario haya introducido.
DESARROLLO - FASE DE CREACIÓN DEL DIAGRAMA DE FLUJO
En el punto realizamos la declaración del
4, entorno como explicábamos en el Algoritmo
resuleto 1. En la zona procedemos a la petición
^ de la infonnación, debemos pedir al usuario el
valor del tiempo, para ello:
j - " Le hacemos saber al usuario que
nwiaHiHHuniaB i i»|i pantalla la frase "Introduce el tiempo".
queremos, es decir, escribimos en
Entorno:
/* Zona (1) del diagrama de flujos */
constante GRAVEDAD=9.8;
real Velocidad;
entero Tiempo;
Inicio:
/*zona (2) del diagrama*/
Escribir "Introduce el tiempo";
Leer Tiempo;
Fin;
^yCohdidón
Verdadera
verdadera
INSTRUCaÓNl INSTHUCCIÓNl
INSTRUC
.^ INSTBUCaÓNZ
IMCTC
INSTRUCaÓN2 *..t'
ucaóN
INSTRUCCIÓN N
JPÍRE^DEl
ÍJsS^ÓRITMO
Figura 2.6. Alternativa múltiple.
Las palabras reservadas en pseudocódigo que se usan para definir alternativas son SI, SI NO,
entonces u OPCION.
Veamos como se configuran alternativas simples, dobles y múltiples en pseudocódigo.
Si CONDICION entonces
Instrucción 1;
Instrucción 2;
Alternativa simple:
Instrucción n;
FinSi;
52 Programación
Si CONDICION entonces
Instrucción I;
Instrucción n;
Alternativa múltiple
Instrucción I.
Instrucción n;
FinSi;
Opción EXPRESION de
valor I: Intrucción/Instrucciones(I);
valor 2:Intrucción/Instrucciones(2);
Alternativa múltiple:
valor n: Inti-uccion/InstruccionesCn);
otro: Intrucción/Instrucciones pot
defecto;
FinOpcion;
Para finalizar véase los siguientes ejemplos de pseudocódigo. Sentencia alternativa simple:
Entorno: Creamos tres variables, denominadas A, B y
entero A,B,Resultado; Resultado.
Inicio:
Comienza el algoritmo. A la variable A se le
A=10;
Escribir "Escribe un asigna el valor de 10. A continuación se pide al
número"; usuario que escriba un número que será
Leer B; guardado en B.
Sentencia de control: alternativa simple. Se
analiza la condición B < A. Si el número
Si B < A entonces
introducido en la variable B es mayor que 10,
Resultado=A-B;
Escribir Resultado; que es el valor que contiene A, entonces
FinSi; realizaremos la resta de A y B y el resultado lo
almacenaremos en la variable Resultado para
posteriormente mostrarlo por pantalla.
Tras comprobar la condición y ejecutar la
Resultado=A+B;
Escribir "A+B=";
sentencia de control seguirá la ejecución
Escribir Resultado; normal del algoritmo. Se almacena en
Fin; Resultado la suma de A y B. Se escribe el texto
literal "A+B="junto al valor de Resultado.
Capítulo 2. Metodología de la programación
NOTA: Al usar la orden Escribir podremos mostrar una frase, una variable, etc., tal y
como se estudiaba en el Apartado 2.2.1.3. Las frases literales se escribirán entre comillas
dobles mientras que si queremos que se visualice el contenido de ima variable
escribiremos tan solo su nombre. Cuando el programa se ejecuta el nombre de la variable
es sustituido por su valor.
Resultado
..
VERDADERO VERDADERO
Resultado=A^B
Resultado=A-B . Resultado=A-(-B
rResuicn
,' Escrlbir.*A-B=t.
^iResultado=A-t-B
Escribir"A+B="
/ Escribir R^ultado Escribir Resultado .
Figura 2.7. Diagrama de flujo del pseudocódigo de p¡gura 2.8. Organigrama de la sentencia alternativa
la sentencia alternativa simple. doble
I;' Escribir"Opción"
leerOp
Otro
Escribir"El resuitadaTés:"
1% : \ EscribirResultado
ENUNCIADO
Imaginemos que se nos pide la creación de im algoritmo que debe contener una constante
llamada gravedad a la que asignaremos el valor 9.8 y las variables velocidad y tiempo.
Debemos solicitar al usuario que especifique qué valor de tiempo tenemos que usar. En caso de
que este valor sea menor o igual a O se mostrará el mensaje "Tiempo incorrecto" y finalizará el
programa. Si el usuario escribe un valor de tiempo correcto, es decir positivo, se calculará el
valor de velocidad (gravedad x tiempo).
DESARROLLO - FASE DE ANÁLISIS
Lo primero que debemos hacer es analizar el problema:
■ Leemos tantas veces como nos sea necesario el enunciado.
■ Una vez lo hayamos entendido pasamos a exponer nuestras conclusiones. Estas son:
/*Zona (1)*/
constante real GRAVEDAD;
real Velocidad;
entero Tiempo;
Inicio:
/*Las siguientes dos lineas forman la zona (2)*/
Escribir "Introduce el tiempo";
Leer Tiempo;
Si Tiempo > O entonces
/*Zona (4)*/
Velocidad=GRAVEDAD*Tiempo;
Escribir Velocidad;
Sino
/*Zona (5)*/
Escribir "Tiempo incorrecto'
FinSi;
ALGORITMO RESUELTO 4
ENUNCIADO
Supongamos que se nos pide hacer un pequeño menú de tres opciones. Este debe visualizarse
como sigue:
1. Calcular diámetro.
2. Calcular circunferencia.
58 Programación
3. Calcular área.
■ La opción que el usuario escoja debe ser almacenada en una variable para
'T"*
posterionuente ser evaluada, por ejemplo Op. Variable declarada junto al resto,
Se usará como expresión en
NOTA: Debemos tener en cuenta que muchos de los problemas a resolver serán
problemas matemáticos de los que no sepamos sus fómiulas o simplemente no las
recordemos. Aconsejamos al lector que ese no sea motivo para desesperar ya que un
programador no tiene por qué saber qué significa una fónnula, solo debe entender cómo
: desarrollar esta en un lenguaje de programación concreto.
J 4
DESARROLLO - FASE DE CREACION DE PSEUDOCODIGO
A partir de ahora solo tenemos que convertir a pseudocódigo cada una de las partes incluidas
en el diagrama de flujo. Hagámoslo en este algoritmo paso a paso;
Entorno:
real Circunferencias-
real Areas-
entero Op;
Inicio:
Escribir "introduce el radio";
Leer Radio;
Escribir "1.Calcular diámetro";
Escribir "2.Calcular
circunferencia";
Escribir "3.Calcular área";
Leer Op;
Opcion Op de:
"1™ 1: Diametro=Radio*2;
Escribir "El diamtero es:";
Escribir Diametro;
2:
Circunferencia=2*PI*RadiOs-
Escribir "La circunferencia
es:";
3:Area=2*PI*Radio*RadiOs-
Escribir "El Area es:";
Escrinir Area;
FinOpcion;
Fin;
!
I
entero Diámetro;
; real Circunferencia;
»
entero Op;
Inicio:
ACTIVIDAD 2.1
DesaiTolla un algoritmo que pida al usuario un número que represente una cantidad expresada
en pesetas. Si tenemos en cuenta que 1 euro = 166,386 pesetas, muestra por pantalla la
conversión a euros de ese número de pesetas.
ACTIVIDAD 2.2
Realiza el ejercicio anterior teniendo en cuenta que el número de pesetas introducido por el
usuario debe ser mayor que cero. Si se introduce un número positivo de pesetas se realizará la
conversión, en caso contrario no se hará ninguna acción.
ACTIVIDAD 2.3
Realiza la Actividad 2.1 de forma que la cantidad de pesetas sea positiva (Actividad 2.2) pero
en esta ocasión, si el número introducido es negativo o igual a cero se debe mostrar al usuario la
frase "El valor de pesetas establecido no es correcto".
ACTIVIDAD 2.4
Imaginemos que queremos desarrollar un algoritmo tal que al escribir un día de la semana
aparezca por pantalla la actividad extraescolar a la que debe acudir nuestro hijo. Por ejemplo, si
ejecutamos el programa y escribimos martes que aparezca "Natación". Las actividades que se
realizan cada día son: lunes - psicomotricidad, martes - natación, miércoles - música, jueves -
natación, viernes - descanso. Los días sábado y domingo no se realizan actividades con lo que si
el usuario escribe por error alguno de estos días de la semana se debe mostrar el mensaje "Día sin
actividades". Si por equivocación, además, se escribe un día inexistente se debe mostrar en
pantalla "Día erróneo".
62 Programación
Figura 2.12. Estructuras de control alternativas concatenadas. Concretamente en una alternativa simple se
ha incluido una serie de alternativas dobles.
Entorno:
entero Numero;
Inicio:
Escribir "Introduce el número";
Leer Numero;
Si Numero > O entonces
Si Numero < 5 entonces
Escribir "El número es menor que 5";
Sino
Si Numero > 5 Y Numero < 10 entonces
Escribir "El número está entre 5 y 10";
Sino
Escribir "El número es mayor que 10";
FinSi;
FinSi;
FinSi;
Fin;
Vemos cómo las sentencias alternativas no terminan hasta el final del algoritmo, indicándose
eon esto que unas están dentro de otras y hasta que la que se encuentra en un nivel más interior
no finalice no finalizará la principal.
En este tipo de algoritmos es esencial el uso de diferentes niveles en el código para detectar
con claridad a qué sentencia de control pertenece cada conjunto de instrucciones, y si se
producen errores o debemos realizar modificaciones será más fácil realizarlas en algoritmos bien
estructurados. Veamos el mismo pseudocódigo pero sin estructura alguna:
Entorno: I
entero Numero; :
Inicio: I
Escribir "Introduce el número"; I
Leer Numero; I
Si Numero > O entonces \
Si Numero < 5 entonces i
Escribir "El número es menor que 5"; :
Sino i
Si Numero > 5 Y Numero < 10 entonces I
Escribir "El número está entre 5 y 10"; j
Sino I
Escribir "El número es mayor que 10 , i
FinSi; i
FinSi; 1
FinSi; ;
Fin; i
Es mucho más complicado saber qué pertenece a qué. En ocasiones, a la hora de establecer
anidaciones se usan líneas de unión entre el eomienzo y fin de cada sentencia alternativa, esto
mismo se observa en la Figura 2.13.
64 Programación
Entorno:
entero Numero;
Inicio:
Escribir "Introduce el número";
Leer Numero;
Si Numero > O entonces
Si Numero < 5 entonces
Escribir "El número es menor que 5";
~ Sino
Si Numero > 5 Y Numero < 10 entonces
Escribir "El número está entre 5 y 10'
Sino
Escribir "El número es mayor que 10";
FinSi;
FlnSi;
FinSi;
Figura 2.13. Sentencias alternativas simples y dobles anidadas con lineas de conexión destacando cada
sentencia de control.
Si CONDICIÓN entonces
Instrucciones;
Sino
Intrucciones;^
Si CONDICIÓN entonces
Instrucciones;
Si CONDICIÓN entonces
Sino
Sino
FinSi;
FinSi;
FinSi;
Podemos encontrar otras instrucciones en la sentencia alternativa además otras sentencias de control.
Capítulo 2. Metodología de la programación 65
ocupen pocos recursos del PC, la menor cantidad de memoria posible, menor tiempo de
procesador, etc.
Para finalizar, en el ejemplo de concatenación que hemos usado, se han utilizado condiciones
compuestas del tipo Si Numero > 5 Y Numero <10 entonces. En esta regla se observa un nuevo
elemento. Y, que pennite realizar varias comprobaciones en una. Al igual que el símbolo < y >,
la Y es un operador en programación denominado OPERADOR LÓGICO.
Existen tres operadores lógicos Y,O y No.
OPERADORES
SIGNIFICADO
LÓGICOS
La condición final será cierta si todas las
reglas que la fonnan lo son
La condición final será cierta si al menos
una de las reglas que la forman lo es
Invierte el significado de la condición. Si
la regla es cierta se convertirá en falsa y
viceversa.
OPERADORES
EJEMPLOS SIGNIFICADO
LÓGICOS
Si R1 Y R2 entonces
hacer A Solo si R1 y R2 son verdaderos se hará A, en
Sino todas las demás posibilidades se ejecutará B.
hacer B
FinSi
Si R1 O R2 entonces Solo necesitamos que una de las dos
hacer A condiciones sea cierta para que se ejecute A, si
Sino R1 es verdadera O R2 es verdadera ejecutaremos
hacer B A. En cualquier otro caso, es decir, cuando R1 y
FinSi R2 sean falsas se ejecutará B.
Si No(Rl)entonces Si R1 es verdadero el No hará que se
hacer A convierta en Falso con lo que si R1 es cierto se
Sino ejecutará B y en caso contrario será A el código a
hacer B ejecutar.
FinSi
Para finalizar se muestra una tabla por cada operador (tabla de verdad )donde se observan
todos los posibles estados que pueden alcanzar las reglas que lo usen estos operadores.
REGLÁl I REGLA2 I ^GLAÍ Y REGLÁ2 P ^G^ "1
Falso Falso Falso Falso
Falso Verdad Falso Verdad
Verdad Falso Falso Verdad
Verdad Verdad Verdad Verdad
Las tablas de verdad suelen usarse en programación declarativa para resolver problemas de lógica y
averigua si un esquema de inferencia es formalmente válido.
REGLAl No(REGLAl)
Falso Verdad
Verdad Falso
ACTIVIDAD 2.5
Tenemos una variable entera llamada Radio. Se le asigna el valor de 4. Según esta premisa,
¿serán verdaderas o falsas las siguientes sentencias? Justifica tu respuesta.
a) Radio > 1 Y Radio < 4.
b) Radio > 1 y Radio <= 4.
c) Radio = 3 O Radio = 5.
d) Radio = 3 O Radio = 4.
e) No (Radio < 10).
f) No (Radio > 10).
Un bucle es un tipo de sentencia de control que hará que una o varias instrucciones se repitan
tantas veces como permita la configuración de dicha sentencia.
Un bucle:
un bucle Para está diseñado para ser ejecutado un número X de veces, sabemos de antemano el
número de veces que se ejecutará el conjunto de instrucciones que lo fonnan.
INSTRUCCIONES
CONDICIÓN
Verdadera
INSTRUCaONES
RESTO DEL
'RESTO DEL ¡
PROGRAMA
RROGRAMA
Figura 2.14. Sentencia de control Mientras. Figura 2.15. Sentencia de control Hacer...Mientras.
Contador= valor
^ : deinliáo
INSTRUCCIONES
A^lor final
>=
Contador
CONDICIÓN
Verdadera
INSTRUCaONES
modificar CONDICIÓN;
DICIÓN; i tipo modificar CONDICION para asegurar la|
Mientras CONDICIÓN; i finalización del bucle. ¡
Capítulo 2. Metodología de la programación
Tenemos una columna donde iremos colocando el número de fila del código que se está
analizando, las columnas para cada variable y la Pantalla.
mm
Figura 2.18. Ordinograma que muestra los pasos a seguir en la construcción de una tabla de seguimiento.
Capítulo 2. Metodología de la programación 71
(3)entero Suma;
(5)Numero=3;
(6)Incremento=2;
Numero Incremento Suma Pantalla
/*Nueva modificación, en esta
ocasión de la variable Incremento.
Nueva fila a nuestra tabla*/
3+2=5
Línea
de Numero Incremento Suma Pantalla
código
(5)
(9) Escribir Suma; (6)
(7) 3+2=5
/*Nuevamente una operación de E/S*/
La suma
La
(9) 3 2 5 Suma
es: 5
La columna Pantalla, en la última fila, indica cuál será el resultado del algoritmo. Finalmente
¿obtenemos lo que queremos? Si la respuesta es positiva querrá decir que el algoritmo está bien
formulado.
Veamos un ejemplo algo más complejo. Supongamos que tenemos que comprobar el
funcionamiento del siguiente pseudocódigo:
72 Programación
(1)Entorno:
(2) entero Nota;
(3)Inicio:
(4) Escribir "Introduce la nota del alumno'
(5) Leer Nota;
(6) Si Nota < 5 entonces
(7) Escribir "Suspenso";
(8) Sino
(9) Escribir "Aprobado";
(10) FinSi;
(11)Fin;
(2)entero Nota;
Línea
/*soIo realizamos una declaración de de Nota Pantalla
variable, la tabla permanece vacia*/ eódiso
Línea
(5) Leer Nota;
de Nota Pantalla
/*En esta operación modificamos el código
contenido de Nota. Supongamos que el Introduce la
usuario introduce un 4*/
nota del alumno
Visto esto, supongamos ahora que tenemos un algoritmo que contiene un bucle. Hagamos la
tabla de seguimiento y así estudiaremos el funcionamiento de la sentencia de control.
(1)Entorno:
(2) constante real PI=3.1415;
(3) entero Radio, Circunferencia;
(4)Inicio:
Hacer:
Escribir "Introduce un Radio. (-1 para
finalizar)
Leer Radio;
Circunferencia=2 x PI x Radio;
Escribir "La circunferencia es:";
Escribir Circunferencia;
Mientras Radio <> -1;
(12)Fin;
3.1415 circunferencia
Línea
de Radio Circunferencia Pantalla
código
(2) 3.1415
Introduce un
(10) Escribir Circunferencia;
Nuevamente una operación de
3,1415 «"<"<>•<->
para
entrada/salida de dados. La finalizar).
tabla de seguimiento se
3.1415
visualizará como se muestra a
la derecha.*/ 3.1415
La
3.1415 circunferencia
3.1415 circunferencia
es; 12
Línea
de Radio Circunferencia Pantalla
La variable Circunferencia es entera de forma que aunque la operación para obtener su valor genere
decimales el resultado debe ser entero. Al multiplicar 2 x 3.1415 x 2 el resultado será 12.56 pero en
Circunferencia solo almacenamos 12.
Capítulo 2. Metodología de la programación 75
La
(10) 2 12 3.1415 circunferencia
es: 12
(2) 3.1415
Introduce un
Radio.(-1
(6) 3.1415
para
finalizar).
(6)Escribir "Introduce un
(7) 2 3.1415
Radio.(-1 para finalizar)";
/*En la pantalla volveremos a (8) 2 12 3.1415
La
(10) 2 12 3.1415 circunferencia
es: 12
Introduce un
Radio.(-1
(6) 2 12 3.1415
para
finalizar).
3.1415
Introduce un
Radio.(-1
3.1415
para
finalizar).
3.1415
(7) Leer Radio;
3.1415
/*Supongamos que es esta
ocasión el usuario indica que
el radio es 5*/ 3.1415 circunferencia
es:
La
3.1415 circunferencia
es: 12
Introduce un
Radio.(-1
3.1415
para
finalizar).
3.1415
La
(10) 2 12 3.1415 circunferencia
es: 12
Introduce un
Radio. (-1
(6) 2 12 3.1415
para
finalizar).
3.1415
3.1415
Introduce un
Radio.(-1
3.1415
para
finalizar).
3.1415
3.1415
La
3.1415 circunferencia
es; 12
Introduce un
Radio.(-1
3.1415
para
finalizar).
3.1415
3.1415
La
3.1415 circunferencia
es:
3.1415
Introduce un
(10) Escribir Circunferencia; Radio.(-1
3.1415
para
finalizar).
3.1415
3.1415
La
3.1415
circunferencia
Capítulo 2. Metodología de la programación 77
La
(10) 2 12 3.1415 circunferencia
es: 12
Introduce un
Radio.(-1
(6) 2 12 3.1415
para
finalizar).
(7) 5 12 3.1415
(8) 5 31 3.1415
La
(9) 5 31 3.1415 circunferencia
es:
La
3.1414 circunferencia
es: 31
3.1415
Introduce un
Radio.(-1
3.1415
para
finalizar).
3.1415
3.1415
3.1415 circunferencia
es:
La
3.1414 circunferencia
es: 31
(6)Escribir "Introduce un
Radio.(-1 para finalizar)"; 3.1415
/*Visualizamos esta frase por Introduce un
pantalla.*/ Radio.(-1
3.1415
para
finalizar).
3.1415 1
12 EIDE89II
12 3.1415
es:
La
12 3.1415 circunferencia
es: 12
Introduce un
Radio. (-1
12 3.1415
para
finalizar).
12 3.1415
31 3.1415
31 3.1415
31 3.1414
es: 31
Introduce un
Radio. (-1
31 3.1415
para
finalizar).
Circunferencia PI Pantalla
Circunferencia PI Pantalla
Introduce un
Línea
de Radio Circunferencia PI Pantalla
código
Introduce un
3.1415
para
finalizar).
(10) Escribir Circunferencia; 3.1415
3.1415
3.1415 circunferencia
3.1415 circunferencia
es: -6
Línea
de Radío Circunferencia PI Pantalla
código
Introduce un
Radio.(-1
3.1415
para
finalizar).
(12) Fin; 3.1415
3.1415
3.1415 circunferencia
Se aconseja al lector que observe la tabla de seguimiento y vea cuándo cambian los valores de
las variables y cómo estas mantienen el valor anterior justo hasta que este es modificado.
El pseudocódigo es susceptible a alguna mejora, ya que en el caso de que escribamos -1 para
acabar la aplicación no deberíamos calcular ni mostrar la circunferencia. Este error se corrige
incluyendo una sentencia alternativa de forma que compruebe si el radio introducido es distinto
de -1. Si es diferente realizaremos el cálculo, en caso contrario saltaremos a la condición del
bucle de forma directa.
ACTIVIDAD 2.6
ACTIVIDAD 2.7
(4) Contador=0;
(5) Contador < 5(Verdad)
(6)Escribir "Hola Mundo"; Hola Mundo
La secuencia (5) - (6) se repetirá de foraia indefinida ya que no existe en el intenor del bucle
ninguna instrucción que modifique la variable Contador. Esta será siempre igual a O con lo que la
condición de Contador < 5 será siempre cierta. Para enmendar este error modificaremos el
código de forma que insertaremos la línea Contador=Contador+l antes o después de la línea
(6). En el pseudocódigo ejemplo que hemos usado la posición dentro del bucle de la nueva
instrucción no altera el algoritmo. Así, el pseudocódigo y la tabla de seguimiento con esta nueva
modificación se verán:
(1)Entorno:
(2) entero Contador;
(3)Inicio:
(4) Contador=0;
(5) Mientras Contador < 5 hacer
(6) Escribir "Hola Mundo'
(7) Contador=Contador+l;
(8) FinMientras;
(9)Fin;
(4) Contador=0;
(7) Contador=Contador+l;
(7) Contador=Contador+l;
(5) Contador < 5(Verdad)
Pasadas unas vueltas más ocurrirá que la condición establecida sea falsa y finalizará el
programa.
Aunque si bien es cierto que confonne vayamos realizando programas optaremos por el uso
de un bucle u otro, además que algunos harán más óptimos el software, es posible usar cualquiera
de ellos en cualquier problema. Veamos a continuación cómo el pseudocódigo anteriormente
analizado puede ser descrito por los bucles estudiados.
Uso del bucle Mientras
(1)Entorno:
(2) entero Contador;
(3)Inicio:
(4) Contador=0;
(5) Mientras Contador < 5 hacer
(6) Escribir "Hola Mundo";
(7) Contador=Contador+l;
(8) FinMientras;
(9)Fin;
82 Programación
ALGORITMO RESUELTO 5
ENUNCIADO
Se precisa realizar un algoritmo que calcule si los número introducidos por el usuario son
pares o impares. Para ello se debe pedir al usuario un número, se comprueba si este es par o
impar mostrando por pantalla los mensajes "El número es par" o "El m'imero es impar" según el
caso. A continuación se preguntará al usuario si desea finalizar la ejecución del software. Si su
respuesta en No (n), repetiremos el proceso descrito pidiendo un nuevo número, en caso
contrario, si especifica Si(s) finalizará el programa.
DESARROLLO - FASE DE ANÁLISIS
Dado el enunciado, pasamos a desglosar y analizar este en profundidad, de forma que quede
totalmente claro qué se debe hacer.
■ El programa repite hasta que el usuario escribe una s el proceso de averiguación de si
un número es par o impar, de forma que necesitaremos usar un bucle. Ya que no
sabemos con exactitud el número de repeticiones de las instrucciones incluidas en la
sentencia de control, usaremos un bucle tipo Mientras o Hacer...Mientras. Creemos
que el último es más aconsejable debido a que al menos una vez se debe procesar un
número y mostrar si es par o impar.
■ Tenemos que pedir al usuario un número, de forma que debemos realizar una
operación de escritura y otra de lectura para almacenar este. A la hora de guardar el
valor necesitaremos una variable que podemos llamar Numero.
Capítulo 2. Metodología de la programación
■ Además, cuando se pide al usuario que escriba si desea finalizar la ejecución, la letra
introducida debe ser almacenada en una variable para ser evaluada, de forma que
debemos crear una variable de tipo carácter.
■ Básicamente la secuencia de ejecución debe ser:
1. Creamos variable Numero y Salir.
2. Entramos en el bucle.
\ NOTA: A la hora de
' realizar comprobaciones con
I caracteres debemos tener
; especial cuidado cuando
' usamos mayúsculas y I—y —
í minúsculas, ya que la letra a ^
I y A no poseen el mismo
I código ASCII, con que
i aunque parezca extraño, no I >
son la misma letra en
programación. Los lenguajes
de programación poseen
funciones que permiten
convertir textos en —
. , , — Si
mayúsculas o minúsculas. —
Inicio:
/*La petición del número se encuentra dentro
del bucle*/
Hacer
Escribir "Introduce un número";
Leer Numero;
Si (Resto{Numero/2))=0 entonces
Mientras SalirO's';
Entorno:
entero Numero;
carácter Salir;
Inicio:
/*La petición del número se encuentra dentro del bucle*/
Hacer
Escribir "Introduce un número";
Leer Numero;
Si (Resto(Numero/2))=0 entonces
Escribir "El número es par";
Sino
Escribir "El número es impar";
FinSi;
Escribir "¿Desea finalizar (S/n)?";
Leer Salir;
Mientras Saliro's';
Fin;
ACTIVIDAD 2.8
ALGORITMO RESUELTO 6
ENUNCIADO
En el siguiente enunciado se pide al programador que realice un algoritmo por él, se solicite al
usuario la introducción de diez números y muestre por pantalla cuántos de ellos eran positivos,
cuántos negativos y cuántos cero.
Inicio
Contador =0
Numero,Contador Negatlvoss:0
Negativos,Positivos,Ceros Posítivos=0
Ceros=0
Escribir'Introduce un
Contador <
número
Numero >0
Figura 2.21. Diagrama de flujo del algoritmo resuelto 6 dividido en zonas para desarrollar el pseudocódigo.
FinPara;
Escribir "Negativos:";
Escribir Negativos;
Escribir "Positivos:";
- Fin del bucle Escribir Positivos;
Escribir "Ceros:";
Escribir Ceros;
I Fin;
Entorno:
entero Contador, Numero;
entero Positivos, Negativos, Ceros;
Inicio:
Positivos=0;
Negativos=0;
Ceros=0;
Para Contador=0 a 10 incremento 1 hacer
Escribir "Introduce un número";
Leer Numero;
Si Numero < O entonces
Negativos=Negativos+l;
Sino
Si Numero > O entonces
Positivos=Positivos+I;
Ceros=Ceros+l;
FinSi;
FinSi;
FinPara;
Escribir "Negativos:";
Escribir Negativos;
Escribir "Positivos:";
Escribir Positivos;
Escribir "Ceros:";
Escribir Ceros;
ACTIVIDAD 2.9
Realiza un algoritmo de fomia que se pida al usuario tres números y se ordenen estos en
forma creciente visualizándose por pantalla. Resuelve el problema tal y como se ha hecho con
cada algoritmo resuelto, desarrollando las fases de análisis, creación del diagrama de flujo y
pseudocódigo.
ACTIVIDAD 2.11
Realiza un algoritmo que pida números positivos al usuario. La petición de valores finalizará
cuando el usuario teclee el valor 0. El programa debe mostrar al finalizar el mayor de todos los
números y la meda aritmética. Resuelve el problema desarrollando las fases de análisis, diagrama
de flujo y pseudocódigo.
■ Alternativa.
■ Repetitiva.
Existen lenguajes, sobre todo en el pasado, que usaban estructuras GOTO. Un COTO
equivalía a un salto de línea, es decir, cada vez que veíamos GOTO x el programa saltaba a la
línea con número x. El teorema de la programación estructurada establece que este tipo de
sentencias no son necesarias y pueden ser sustituidas por un bucle, una sentencia alternativa
simple, doble o múltiple, o bien mediante una secuencia de instrucciones.
Aunque normalmente los científicos acreditan el teorema a Corrado Bohm y Giuseppe
Jacopini debido a un artículo de 1966 donde lo demuestran, existen indicios de que surge en
1946 con la descripción de la arquitectura de Von Neumann y el teorema de la forma normal de
Kleene.
COMPRUEBA TU APRENDIZAJE
1. En un programa, ¿qué es una variable? ¿Y una constante?
2. ¿En qué consiste una petición de un dato al usuario? ¿Qué operaciones necesitaremos
usar?
ACTIVIDADES DE AMPLIACION
DesaiTolla un algoritmo que pida al usuario dos números e indique mediante un
mensaje en pantalla si son iguales. En caso de que no lo sean debe mostrar por
pantalla cuál es mayor. Enfoca el problema como se ha hecho en el capítulo con la
resolución de los algoritmos resueltos, desarrollando la fase de análisis, diagrama de
flujo y pseudocódigo.
Realiza una tabla de seguimiento del algoritmo generado en la Actividad 1. ¿Es
correcto? ¿Funciona tal y como indica el enunciado?
Realiza un algoritmo que pida al usuario la nota de un alumno. Este debe procesar
esta nota de forma que muestre los mensajes que se indican en función de:
■ nota < 3 / Mensaje:"Muy deficiente".
■ 3 <= nota < 5 / Mensaje: "Suspenso".
■ 5 <= nota < 6 / Mensaje: "Suficiente".
■ 6 <= nota 7 / Mensaje: "Bien".
■ 7 <= nota < 9 / Mensaje: "Notable".
■ 9 <= nota <= 10 / Mensaje: "Sobresaliente".
11. Necesitamos realizar un programa que muestre por pantalla la suma de todos los
números impares y de todos los números pares menores que cien.
12. Realiza la Actividad 11 pidiendo al usuario en qué valor finalizar, es decir si en la
Actividad 11 se pide números menores que 100 aquí pedimos al usuario que
introduzca también este dato.
13. Realiza un diagrama de flujo que dé solución al cálculo del factorial de un número.
(n!=nxn-l xn-2 x ... 1).
14. Realiza un algoritmo que pida dos números, X e Y de fonna que se pretende calcular
X^.
INICIACION AL LENGUAJE C#
CONTENIDOS OBJETIVOS
3.2. CARACTERÍSTICAS DE C#
C# pretende ser un lenguaje de programación:
■ Simple. Fácil de usar.
■ De propósito general. Puede usarse para generar cualquier tipo de aplicación para
cualquier ámbito.
■ Orientado a objetos.
■ Fuertemente tipado. Se dice que un lenguaje de programación es tipado cuando a la
hora de crear variables es necesario establecer el tipo de datos que se va a almacenar
en ellas.
■ Usa el denominado Recolector de basura. El uso del recolector de basura hace que
no sea necesario ejecutar instrucciones de destrucción de objetos.
■ Usa instrucciones seguras de fonua que a la hora de utilizarlas no se produzcan fallos.
Por ejemplo, C o C++ penuitían en la evaluación de condiciones en las estructuras
alternativas el uso tanto de una expresión condicional como aritmética. En C# solo se
penriite expresiones condicionales de fonua que no puedan confundirse los
operadores de igualdad y asignación y se den fallos difíciles de detectar.
■ Unificación de tipos. En C# todos los tipos derivan de una superclase llamada
System.Object heredando todos sus elementos.
■ No pennite el uso de punteros para conseguir mayor seguridad en las aplicaciones.
Aplicación de consola
Todo código C# se encuentra encapsulado en
Busing Systeraj una clase. En nuestro ejemplo \emos como
using System.Collections.Generic;
using System.Linq; aparece la línea class Program abriéndose una
using System.Text; llave y cerrándose esta casi al finalizar el
using System.Threading.Tasksj programa. Entre estas llaves incluiremos
Bnamespace Ejemplo
atributos y métodos. En primera instancia sólo se
pretende que el lector se familiarice con esta
El class Prcg.-ain estructura, no que la entienda, el entendimiento
I { llegará cuando estudiemos la programación
B static void [-lainístringí] args)
{ orientada a objetos.
}
}
Así, solo debemos tener en cuenta que el
> nuevo código que escribamos debe incluirse
Figura 3.1. Código fuente del fichero
entre las llaves de inicio y cierre de la clase
Program.cs. Program, más concretamente entre las llaves de
la función Main.
Toda clase que vaya a ser ejecutada debe eontener la función Main. Una función es un trozo
de código al que se le denomina con un nombre, de fonua que cada vez que queramos ejecutar
ese código solo tendremos que indicar el nombre de la función. Por ejemplo, supongamos en
pseudoeódigo que tenemos el siguiente trozo de código:
Entorno:
entero Suma, Numl, Num2;
Inicio;
Escribir "Introduce número 1";
Leer Numl;
Escribir "Introduce número 2";
Leer Num2;
Suma=Numl+Num2;
Escribir "La suma de ambos número es:";
Escribir Suma;
Si queremos realizar íá suiña de más ¿euVpar de número tendríamos que repetir este código
una y otra vez en el programa prineipal. Para evitar esto creamos una función o subprograma de
forma que:
Subprograma Sumar Entero's
Entorno:
entero Suma, Numl, Num2;
Inicio:
Inicio:
Escribir "Introduce número 1";
Leer Numl;
Escribir "Introduce número 2";
Leer Num2;
Suma=Numl+Num2;
Escribir "La suma de ambos número es:";
Escribir Suma;
Fin Sumar_Enteros;
/*Inicio del programa principal*/
Entorno:
entero A; // Variable del programa principal"
Inicio:
Sumar_Enteros;
Escibir "Dame una valor para a";
Leer A;
Sumar Enteros;
Cada vez que en el programa principal aparece la línea Sumar_Enteros; se ejecuta el código
que se encuentra entre Subprograma Sumar•JEnteros y Fin Sumar_Enteros;
using System;
La Figura 3.2 muestra de forma
using Systefs.Collcctions.Gencric; diferenciada cada zona de un programa C#.
using Systeffi. Linq;
using Systeffi.Text;
.using Systetr.Thrcading.Tasks;
En la parte superior, se incluyen
referencias a paquetes extemos. A groso
'^airespace Ejen-plo
{
modo podemos decir que un paquete es un
elemento de C# que incluye un conjunto de
clases. Estas clases a su vez están formadas
'tatic void N^in(sfing[ j args;
{ I por funciones que pueden sernos útiles en
int nuffil, nur2;
int suira;
nuestras aplicaciones. Si queremos usar un
C;'ccíf.WriteLine("Introduce un núxepo"); paquete externo colocaremos la palabra
nu»l • Syste».:* t "r.ParseCCcr.súlc.ReadlineO);
Cs-isol'..WriteLÍne("Introduce otro nútrero**); reservada using seguida del nombre del
nuffi2 » Systeffi.Id*r:.Par5e(CcniíIe.RcadLine());
sutca • nunl •f nuis2;
paquete en la parte superior del código.
Ccnsclc.WriteLineCLd suea esr^-í-suma); Cuando creamos un proyecto, tal y como
Censóle.ReadLine();
^ hemos hecho con el proyecto Ejemplo, se
public getfiorrbre()| genera un paquete, que permitirá agmpar
return this.noffibrej^S nuestros propios métodos.
Un paquete debe contener al menos una
clase. Las clases se definen con el encabezado
que se muestra en Si queremos que
publíciñtgcUÍQ nuestro código sea ejecutable, es decir
{
return this.n; estamos generando un .exe en lugar de una
)
public vcid setM(int nue%"0)
librería u otro elemento, la clase debe
{
this.n ■ nuevoij
incorporar una función denominada Main
-X
}
¿ y (podemos verla en la primera zona O)
Figura 3.2. Partes de un programa O#.
Cada línea en un programa escrito en C# está compuesta por una serie de caracteres que se
agrupan formando los denominados tokens. Un token no es más que un componente lé.xieo que
conforma el vocabulario del lenguaje. En lenguaje natural un token podría ser una palabra,
tenemos en cuenta que cuando escribimos usamos letras que según como se agrupen formarán
unos componentes léxicos u otros dando significados diferentes a la sentencia final.
Básicamente, cada sentencia C# estará fonnada por determinados tokens, tales como
palabras reservadas, identifícadores, cadenas de caracteres u operadores.
El término Palabra reservada refiere un conjunto de palabras que realizan una función
concreta en el lenguaje. A la hora de crear nuevos elementos en nuestro programa no podremos
usar ninguna de estas palabras para ello. La siguiente tabla muestra el conjunto de palabras
reservadas que utiliza C#(http://msdn.microsoft.com/en-us/library/x53a06bb.aspx).
3.3.3. IDENTIFICADORES EN O#
Un identificador es un componente del lenguaje de programación que como su nombre indica
se encarga de identificar un elemento concreto, da nombre a un elemento del programa. Usamos
identificadores cuando creamos una variable, una constante, declaramos una nueva clase,
creamos una función, etc. A la hora de definir un identificador cada lenguaje de programación
establece una serie de reglas que indican qué caracteres y símbolos podemos combinar para
formar este. En C#:
Capítulo 3. iniciación al lenguaje O# 97
ACTIVIDAD 3.1
3.3.4. COMENTARIOS EN C#
r nancspftcc Ejei^lo
{
r-, class P-cQfaT
I <
/•Funcíén p-lncip»l ^
Recibe un aToy de cadenas de ca-'acte'-es
fio devuelve ningún vale- de salida*/
static void K«in(strlng[] args)
A continuación se muestra una tabla donde se incluyen los tipos de datos integrados en el
propio lenguaje de programación.
Tipo Descripción Rango de valores Alias
3.3.5.2. LITERALES
Básicamente un literal es cualquier valor que puede adoptar un tipo de datos. Al igual que
existen diferentes tipos de datos, encontramos diferentes tipos de literales;
■ Enteros.
■ Reales.
■ Lógicos.
■ Carácter.
■ Cadena.
■ Valor nulo.
LITERALES ENTEROS
Valores reales, parecidos a los anteriores, pero siempre deben expresarse en formato decimal,
aunque no presenten decimales. Para ello se hace uso del punto (.), separador de parte entera y
parte decimal. Por ejemplo, si queremos asignar un cero a una variable real debemos escribir 0.0,
el O sin la parte decimal no está permitido entre estos literales, este sería un literal entero.
Ejemplos de estos literales podrían ser 12.345, -0.1 o 1.764. En el caso de que queramos
representar valores grandes podemos utilizar el símbolo E o e, tal que se está expresando el
literal a través de una base y un exponente. Ejemplo de literales reales expresados con el uso de
base y exponente podrían ser 2.3E12 o 0.2e-10.
LITERALES LÓGICOS
Se entienden por literales lógicos los valores true y false. Los literales lógicos se usan con el
tipo de datos bool, siendo estos los únicos valores que puede adoptar. Nomialmente se usan en
sentencias condicionales para determinar las instrucciones que se deben ejecutar, siendo true
equivalente a condición cierta y falsa condición falsa.
LITERALES CARÁCTER
Representan el conjunto de caracteres alfanuméricos, es decir, letras, números y signos
encapsulados entre el símbolo de comilla simple ('). Ejemplos de este tipo de literales serían 'a'.
Capítulo 3. Iniciación al lenguaje O# 101
'M','8' o todo el conjunto de caracteres unicode. Debemos prestar atención a la hora de usar
estos valores, ya que no es lo mismo 'M' que 'm'. Además, si a la hora de usar variables de tipo
carácter le asignamos el valor '9' debemos siempre tener en cuenta que este dato es un carácter y
no pueden realizarse ningún tipo de operación aritmética sobre él.
Existen una serie de caracteres especiales, véase la siguiente tabla.
Código
Carácter Carácter Carácter
de escape
Tabulación
Comilla simple \' Retroceso
horizontal
Tabulación
Comilla doble \" Salto de página
vertical
Barra
Carácter nulo \0 Nueva línea
invertida
Ccn5cle.WriteLine("Hola \n f-'undo|");
Figura 3.4. Parte del código fuente donde se usa Figura 3.5. Zona de la consola que muestra el
una función de visualización de información en
mensaje "Hola Mundo". Lo vemos separado en dos
pantalla. En ella el carácater de escape '\n'.
partes debido a que \n conlleva un salto de linea.
Los literales de cadena de caracteres no son más que un conjunto de caracteres encapsulados
entre comillas dobles. Una cadena puede estar compuesta por ninguno, uno o varios caracteres.
No es lo mismo 'c' que "c", el primero es un literal de tipo carácter mientras que el segundo
aunque esté compuesto por un único elemento será considerado como un literal cadena.
Cuando usamos literales de caracteres podemos incluir en ellos los caracteres especiales
vistos tales como \', W, etc. Así, si entre un par de dobles comillas incluimos el código de escape
\t este será traducido como una tabulación, de forma que el texto que se encuentre antes o
después de \t se mostrará visiblemente separado. Sin embargo, si delante de esta cadena de
caracteres colocamos el símbolo @,el código de escape no será interpretado y se mostrará como
un carácter más.
Icnsole.WriteLine(@"Hola \n f'undo");
Consolé.WriteLine("Hola \n "■■undo"*);
w^"nrey7/cvvsers/i53aevuocumentsAVfsuarya'~
iHola Nn Hundo ^
Figura 3.6.Uso de @ para obtener un literal plano. Figura 3.7. Uso de caracteres especiales en las
Vemos como aparece el carácter especial como cadenas de caracteres. En la Figura se usa un
otro más, no es interpretado. salto de linea que es interpretado correctamente.
LITERAL NULO
El literal nulo, o nuil, se usa en objetos de clase. Un objeto adquiere este valor de forma
transparente al usuario cuando se crea un objeto pero no se incializa, es decir, creamos una
variable de objeto pero no damos valor inicial a esta.
3.3.6. DECLARACION DE VARIABLES EN C#
Hemos estudiado diferentes tipos de datos, valor, referencia o puntero y entre los de tipo valor
encontrábamos una serie de tipos básicos incluidos en la propia sintaxis de C#. La sintaxis
formal de creación de variables de tipos de datos simples es la que sigue:
Creamos una variable cuyo identificador es
Nombre_de_Variable y almacenará literales
tipo_de_datos Nombre_de_Variable;
correspondientes al tipo de datos establecido como
tipo de datos.
Declaración de una variable llamada Var, que
almacena literales del tipo de datos establecido
tipojdejdatos Var=valor; . como tipo_de_datos. Además, en esta instrucción
estamos asignando un valor inicial de valor a dicha
variable. Estamos Inicializando la variable.
Similar a la primera sintaxis. En esta ocasión al
contener Vari, Var2 y Var3 el mismo tipo de datos
tipojdejdatos Vari, Vari, Var2;
pueden declararse en la misma linea separándose
estas por el carácter coma (,).
Declaración de la variable Var del tipo de datos
tipojdejdatos Var;
Var=valom;
tipo de_datos y posterior inicialización al valor
valorn.
^ El término declarar una variable se considera al momento en que se hace referencia por primera vez
a ella estableciéndose el tipo de datos que va a almacenar y su identificador como elementos mínimos.
Capítulo 3. iniciación al lenguaje C# 103
Si lo desea el lector puede ver los valores a los que se inicializan los diferentes tipos de
variables en función de su tipo de datos en la siguiente referencia web:
http://msdn.microsoñ.com/es-es/library/83fhsxwc(v=vs.80).aspx.
En C# las palabras reservadas se colorean en azul. Aparecerá una línea de color verde
subrayando una variable cuando esta ha sido creada pero no se usa en ninguna instrucción.
Si observamos una línea de color roja bajo una instrucción esta indica que se ha producido un
error. Este debe ser corregido si deseamos ejecutar el programa.
El código de la Figura 3.8 muestra todas las variables que se han usado a lo largo de la
explicación de declaraciones de tipos.
//Declaración de variables
int nutnl, num2j
char l^et^ = 'a';
float mjme^j
bool cp_ndici.onl23j
condicionl23 = false;
int nuevo = new int();
char ^aract^;
carácter = new char();
ACTIVIDAD 3.2
Crea una variable de tipo real con 7 dígitos de precisión denominada décima. Asígnale el
valor 23.4. A continuación crea otra variable de tipo char a partir del constructor de forma que su
valor inicial sea '\0'.
3.3.7. CONSTANTES EN C#
Figura 3.9. Programa que calcula la circunferencia de un circulo. Se ha declarado la constante PI.
Además de las constantes como las hemos estudiado, en ocasiones precisaremos en nuestros
programas utilizar literales que no hayan sido incluidos como valor de ninguna variable, es decir,
literales constantes. Por ejemplo, si queremos realizar una comparación podemos escribir
directamente numero < 3, siendo 3 una constante literal. Para cada tipo de datos C# dispone de
este tipo de constantes, ahora bien, si usamos literales constantes numéricas, cada vez que
escribamos un número este será tomado como entero, ¿qué puedo hacer para que sea detectado
por el compilador como un tipo long?; además, con el uso de números decimales, por defecto un
Capítulo 3. Iniciación al lenguaje O#
número con punto se trata como doublé, ¿cómo podemos indicar que sea registrado como float
para que ocupe menos espacio?
En C# podemos usar los caracteres u, 1 o f para indicar si estamos tratando con números
unsigned, long o float respectivamente. Según esta infonnación:
- 13/int ■ 13L/long ■ 13u/unsigned
- 2.1234/double - 2.1234f/float ■ 13ul /ulong
Podemos usar las letras u, 1 y f en mayúsculas o minúsculas, a continuación del literal
numérico. Podemos realizar combinaciones de las mismas, por ejemplo: ul.
ACTIVIDAD 3.3
Averigua si el siguiente código fuente tiene errores. En caso afinnativo tras localizarlos
corrígelos.
int p=3.0;
double resultado;
resultado = p*2;
p=(doiible)(8.1/5);
resultado=p;
3.3.9. OPERADORES EN C#
A la hora de formar las instrucciones, en muchas ocasiones estas son expresiones en las que
se concatenan diferentes tipos de tokens mediante un elemento denominado operador. Existen
diferentes tipos de operadores, ya en el Capítulo 2 avanzábamos la existencia de algunos, C#
posee una gran variedad de ellos.
Clasificaremos los operadores en:
■ Aritméticos.
■ Relaciónales.
■ Lógicos.
■ Asignación.
■ Operador sizeof.
■ Nivel bits.
Nombre Descripción
Positivo Indica que el número es positivo. Operador uñarlo.
Negativo Se usa para establecer el número como negativo. Operador
unario.
Suma Suma aritmética de dos valores.
Resta Resta aritmética de dos valores.
Multiplicación Multiplicación aritmética de dos valores.
División División aritmética de dos valores.
Módulo Obtiene el resto de la división entera.
Incremento Incrementa en uno el valor que contenga en operando. Es un
operador unario.
Decremento Disminuye en uno el valor del operando. Igualmente unario.
NOTA: A la hora de trabajar con operadores debemos tener en cuenta que existen
operadores uniarios y binarios. Un operador unario es aquel que solo necesita un
operando mientras que un operador binario precisará de dos. Por ejemplo, el operador -
usado para el cambio de signo o establecer un número negativo es unario, sin embargo, la
suma es binaria ya que precisa de dos valores u operandos para proceder.
Los operandos que usaremos con estos operadores serán de los tipos básicos int, float, double,
char, etc. Si los operandos son del mismo tipo la expresión resultante de aplicar el operador será
del tipo de los operandos. En caso de que usemos operandos de diferentes tipos de datos, uno
será de mayor tamaño que otro de fonna que el de menor tamaño se convertirá al de mayor rango
y el resultado final será de este último tipo, por ejemplo 13.2+4 dará como resultado 17.2, es
decir un dato double.
Podemos realizar operaciones entre números enteros y caracteres de forma que se toma el
código interno del carácter para realizar la operación siendo el resultado final int. De igual modo,
si realizamos una operación sobre dos variables tipo char el resultado final será entero.
Debemos tener en cuenta ciertas peculiaridades a la hora de usar algunos de estos operadores:
DIVISIÓN
A la hora de usar el operador división (/), la división puede ser tomada como división entera
o división real, es decir, si los operandos que se usan son enteros el resultado de la división será
entera, en caso contrario será double. Por ejemplo:
Ya que 10 y 2 son tomados por el compilador como números enteros el
10/4=2
resultado de la división también lo será. Obtendremos el valor 2.
El operador suma suele usarse para sumar dos operandos numéricos o de tipo carácter, sin
embargo tiene otra utilidad, la de concatenar cadenas de caracteres.
Así, podemos usar el operador con dos datos de tipo string o bien un dato de tipo string y otro
de cualquier otro tipo de forma que en esta última casuística el resultado final será también
string.
Tenemos dos cadenas de caracteres, "Hola" y
"Mundo", al realizar la expresión estamos asignando a
string saludo="Hola" +"Mundo" la variable saludo el valor HolaMundo. El resultado
no contiene espacios en blanco ya que no lo hemos
especificado en las cadenas operando.
En esta otra sentencia estamos creando una
variable de tipo cadena (string) con el nombre
mensaje. Le asignamos la frase "El valor es:" junto al
string mensaje="El valor
valor de la variable cuyo nombre es variable. Al
es:"+variable:
realizar la concatenación de operandos de diferentes
tipos con un operando de tipo string el resultado final
será de tipo cadena de caracteres.
1
Devuelve verdadero si una variable es mayor estrictamente
Mayor que (mayor que otra dada.
estricto) a > 3. Para que la expresión sea cierta, a debe ser como
mínimo 4.
i variable=(condición)?va¡or_si_yerdad:valor_si_falso; :
Un ejemplo de uso sería;
//declaración de las variables nota y mensaje "•
¡ int nota; :
; string mensaje=""; ;
I /*La variable mensaje almacenará el texto "El alumno esta aprobado" o "El ;
: alumno esta suspenso" en función de la condición (nota>=5). El símbolo ? ;
■ separa la condición del resto de la instrucción. Los valores a asignar en ;
i función de si la condición es cierta o falsa se separan mediante .*/
I mensaje=(nota>=5)?"E1 alumno esta aprobado":"El alumno esta suspenso"; :
I Consolé.WriteLine(mensaje); ;
ACTIVIDAD 3.4
Realiza un pequeño programa que tenga una variable entera a la que se le asignará el valor 10
por defecto. La aplicación debe comprobar si este número es par o impar y en función de esta
condición debe mostrar el mensaje "El número es par" o "El número es impar". Aunque aún no
la hemos estudiado, usa el método Consolé.WriteLine(mensaje); para mostrar el texto
correspondiente en pantalla como en el ejemplo anterior. Usa el operador ?:.
mt numero=2,numero2,numero3; I
I
numero3=numero2—numero;
II \
numero3=numero2+(numero=6); |
Las asignaciones se realizan de derecha a izquierda. Así, en numero3=numero2=numero
tomamos el valor de numero y se lo asignamos a numero2. A continuación, el valor de
numero2 es asignado a numero3. En el ejemplo de código mostrado, esta línea daría como
resultado numero=2, numero2=2 y numero3=2.
En la instrucción numero3=numero2+(numero=6) las asignaciones igualmente se realizan
de derecha a izquierda tal que primero se asigna un 6 a la variable numero (numero=6). A
continuación se suman numero2 y numerol y el resultado es almacenado en numero3. Para
esta línea de código y teniendo en cuenta que anteriormente la asignación hizo que numero,
numero2 y numero3 tomaran el valor 2, numero=6, numero2=2 y numero3=8.
Como ya se ha indicado en alguna ocasión se diferencia el operador de asignación del de
igualdad para evitar confusiones, tal que usamos un solo signo igual para la asignación (=) y dos
símbolos(=)para la comparación.
Además del = encontramos una serie de operadores en este grupo que permiten simplificar
instrucciones en las que se modifica el valor de una variable usando su valor anterior, por
ejemplo variable=variable+10;
Formato Formato
Operador Descripción
largo corto
El operador sizeof devuelve el tamaño en bytes de un tipo de datos concreto. Su sintaxis es:
sizeof(tipo_de_datos);
sizeof(Objeto);
Encontraremos un mayor sentido al uso de este operador cuando trabajemos con objetos.
Existen otros operadores, como el operador punto (.) que igualmente utilizaremos con estos
tipos de datos,justo cuando queramos acceder a los elementos del mismo.
Ccnscie.KriteLine("Un tipo de datos int ocupa:" + si:ecf(int) + " bytes de rero-ia");
Los operadores a nivel de bits también se denominan bitwise. Comparan bit a bit los \alorcs
de las variables que se incluyen como operandos. Los operadores & y 1 tienen un
comportamiento algo especial. En caso de que se usen operandos booleanos o condiciones que
devuelven el valor true o false estos operadores se convertirán en operadores lógicos perezoso, a
continuación estudiaremos este concepto.
Operador Descripción Ejemplo
Desplazamiento a la
izquierda, cada bit es
recorrido x posiciones a la
izquierda.
Desplazamiento a la derecha
Cada bit es recorrido x bits a
la derecha.
001
~c^I 001
Si un bit es 1 equivale a Verdad y si es O es Falso. Teniendo en cuenta las tablas de verdad
estudiadas en el Capítulo 2 el resultado de c es 001 = 1.
Capitulo 3. Iniciación ai lenguaje C# 113
Si los operandos a analizar son booleanos, es decir, son expresiones que devuelven un valor
verdadero o falso, los operadores & y|realizan el AND u OR de las condiciones que concatenen,
eso sí, la evaluación que realizan es perezosa.
Sabemos que si una de las condiciones es falsa el resultado final de im AND es falso y si una
de las condiciones de un OR es true, el resultado final también lo será. Según esto, podemos
evitar que se evalúen todas las condiciones de una expresión con los operadores & y |, a esto se le
denomina evaluación perezosa.
,„ , Si a<6 da como resultado false la sentencia completa devolverá false, no se
a<6 & b>c , '1 ^
evaluara b>c.
« »
= *= /= %= += «= »= &= 1=
Nonnalmente todos los operadores tienen una asociatividad. Esto es, el orden en el que se
deben ejecutar si no existen paréntesis que delimiten las operaciones. Cuando tenemos una
expresión con operadores de la misma prioridad, la asociatividad es la que indica cuál debe
tenerse en cuenta primero. Por ejemplo, la expresión x+y-z se evalúa como si estuviera escrita
(x+y)-z debido a que la asociatividad de estos operadores es de izquierda a derecha, es decir, se
irán ejecutando los operadores que vayamos encontrando en dirección derecha.
Todos los operadores binarios a excepción de la asignación (=) y el operador especial
condicional (?:) son asociativos por la izquierda, es decir, se ejecutan los operadores de izquierda
a derecha. La asociatividad de = y ?: es por la derecha, es decir, la ejecución de órdenes se realiza
de derecha a izquierda, por ejemplo cuando realizábamos la operación
numero3=numero2=numero esta se traducía a numero3=(numero2=numero) de forma que la
primera asignación que se realizará será numero2=numero.
ACTIVIDAD 3.5
Dada las variables enteras x=3, y=4 y z=2 indica que se asignará a la variable resultado en
cada expresión:
resultado=x+y*z;
resultado=(x+y)*z;
resultado=++x%y;
resultado=x+z/y;
NOTA: El punto (.) es un operador que atin no hemos estudiado ya que se usa sobre ¡
? todo en variables de tipos de datos compuestos, tipo estructura u objetos. Se utiliza para ;
í acceder a los elementos individuales de estos tipos, es decir, a los campos de una i
estructura o bien a los atributos y métodos de un objeto. ¡
Capítulo 3. iniciación ai lenguaje O# 115
Los métodos WriteLine y Write pemiiten mostrar infonnación al usuario a través de la salida
estándar, normalmente la pantalla. WriteLine además de mostrar infoniiación realiza un salto de
línea tal y como indica su propio nombre.
Ya que estos métodos penniten la visualización de infonnación, esta debe incluirse de algún
modo en la función. La sintaxis básica de WriteLine y Write es la siguiente:
Consolé. WriteLine(expresión); !
Console.Write(expresión); j
Expresión abarca a cualquier información que pueda ser visualizada, ya sea un literal, una
cadena de caracteres o una instrucción.
^Yaríable^ r Variable y
indicado. La posición en la que está un parámetro vendrá dada por número de orden cmpc/aiido
a contar en cero.
Parámetro 2
int X = 3, y = 10; ^
Ccn5cle.WriteLine("El valor de x es {0} y el valor de y es {l}",x,y);
Tv, '
I Parámetro 1 j
Figura 3.13. Uso de cadena de formato para mostrar información por la salida estándar.
Estos métodos se encargan de leer infonnación introducida por el usuario a través del
dispositivo de entrada estándar, el teclado.
El método ReadLine recoge todo lo que el usuario ha escrito hasta pulsar la tecla ENTER.
esto puede ser un simple carácter, número o cadena de caracteres. Si bien es cierto, todo lo que se
recupere mediante estos métodos será tratado como un entero (Read) o una cadena de caracteres
(ReadLine). Si el usuario escribe el valor 13 este debe ser convertido si se quieren realizar
operaciones con él ya que por defecto es tratado como una cadena de caracteres.
La función Read devuelve un valor de tipo entero (código ascii del carácter escrito), con lo
que debemos realizar un casting a la operación de lectura. Solo leerá el primer carácter escrito de
forma que si el usuario teclea "ab" o "12" la lectura con Read solo tendrá en cuenta la letra 'a' y
el dígito '1'.
_ — " — - -- -- — - _ — - — - —
char letra;
string cadena;
letra=(char)Consolé.Read();
cadena=Console.ReadLine();
Consolé.Writeline("Ha escrito la letra {0} y la frase (1}", letra,cadena);
Cuando queramos convertir ervalórintroducidó a partir del método ReadLine() no podremos
usar un simple casting, será necesario utilizar operaciones de conversión propias de los objetos a
los que queremos convertir. Por ejemplo, si hemos pedido al usuario que introduzca un valor
float debemos incluir la función Console.ReadLine en el método float.Parse(); La función Parse
espera que entre sus paréntesis se introduzca una cadena de caracteres que es lo que precisamente
devuelve el método Console.ReadLine().
Podemos usar la función Parse() por cada uno de los tipos de datos integrados vistos:
int.ParseO, double.Parse(), float.Parse(), long.Parse(), etc.
int numerol, numero2,resultado;
Consolé.WriteLine("Introduce un número");
numerol=int.Parse(Console.ReadLine());
Consolé.WriteLine("Introduce otro número");
numero2=int.Parse(Consolé.ReadLine());
resultado=numerol+numero2;
Consolé.WriteLine("La suma de {0} y {1} es:{2}",numerol,numero2,resultado);
Consolé.ReadLine();®
® Usamos ReadLine en la última línea para poder visualizar el resultado ya que el programa finalizará
cuando el usuario pulse ENTER.
Capítulos. Iniciación al lenguaje C# 117
ACTIVIDAD 3.6
Realiza un pequeño programa de consola que pida al usuario el valor del lado de un cuadrado
y muestre como resultado el área del mismo.
ACTIVIDAD 3.7
Realiza un pequeño programa que pida al usuario una letra y muestre por pantalla el carácter
siguiente al especificado.
Condición representa cualquier expresión que de como resultado un valor booleano, por
ejemplo true, a<5 o(a>b S¿& b<c).
Por sentencias entendemos cualquier tipo de instrucción que podamos escribir en C# o grupo
(bloque) de instrucciones. El uso de llaves no es necesario si solo vamos a incluir una línea de
código.
int nota;
Consolé.WriteLine("Introduce nota");
nota=int.Parse(Consolé.ReadLine());
if (nota>=5)
Consolé.WriteLine("El alumno esta aprobado");
Consolé.ReadLine();
if(condición){ \
Sentencias; ;
} \
else{ \
Sentencias; i
} \
Al igual que en las sentencias alternativas simples no es necesario el uso de llaves si
sentencias se reduce a una única instrucción, tanto en la parte relativa al ¡f como al else.
int numerol,numero2
char operación;
Consolé.WriteLine("Introduce el primer número");
numerol=int.Parse(Consolé.ReadLine());
Consolé.WriteLine("Introduce el segundo número");
numero2=int.Parse(Consolé.ReadLine ());
Consolé.WriteLine("Indica operación a realizar (0-Suma/1-Resta)
operacion=(char)Consolé.Read();
if (operación == ~0'){
Consolé-WriteLine("La suma de {0} y {1} es {2}", numerol,
numero2, numerol+numero2);
else{
Consolé.WriteLine("La resta de {0} y {1} es {2}", numerol
numero2, numerol-numero2);
break;
Sentencias;
La estructura alternativa múltiple 1 tiene bastante similitud con las sentencias alternativas
simple y doble. La primera de las condiciones es precedida por if mientras que se pueden
contemplar algunas más anteponiendo else if. Para finalizar, si ninguna de las condiciones es
cierta se ejecutarán las instrucciones contempladas en el else siempre que exista.
Así, la primera estructura múltiple sería interpretada por el compilador del siguiente modo:
Si condición_l es cierta se ejecutan las instrucción que se encuentran entre las siguientes
llaves y finaliza la expresión condicional, si no es cierta condición_l se comprueba condición_2.
Si condición_2 es true se ejecutarán las sentencias que se incluyen justo detrás de ella, si no,
seguirán evaluándose condiciones hasta que una de las condiciones sea válida, lleguemos a una
sentencia else o bien no existan más condiciones a evaluar.
La estructura alternativa múltiple 2 se estudió tal cual en el Capítulo 2, es decir, veíamos
como en función del valor de una variable se ejecutaban unas líneas de código u otras. Así,
tendremos una variable definida en un detemiinado tipo de datos y la sentencia swltch
proporcionará todos los posibles valores válidos por los que se deben ejecutar determinadas
instrucciones. La palabra reservada case precede a cada valor válido. Las instrucciones incluidas
para un valor válido deben finalizar con la instrucción break de forma que se garantice que
cuando uno de los case sea evaluado finalice la estructura múltiple.
Además, es nonual encontrar una palabra reservada default que indica las instrucciones que
se deben ejecutar en caso de que ninguno de los valores de los case se hayan validado.
— — -1
char opcion; |
Consolé.WriteLine("O.- Sumar"); i
Consolé.WriteLine("1.- Restar"); I
Consolé.WriteLine("2.- Salir"); I
Consolé.WriteLine("Opción:"); i
opcion = char.Parse(Consolé.ReadLineO); I
switch (opcion) ;
{ i
case 'O': Consolé.WriteLine("Has escogido sumar"); 1
break; i
case '1': Consolé.WriteLine("Has escogido restar"); '
break;
case '2': Consolé.WriteLine("Has escogido salir");
break;
default: Consolé.WriteLine("La opción seleccionada es
incorrecta");
break;
Consolé.ReadLine();
Al declarar opción de tipo char cada case debe contemplar un valor incluido entre comillas
simples, 'O', '1' y '2', aunque representen números. En caso de que el usuario escriba un valor
distinto de O, 1 y 2 se ejecutará la línea bajo default escribiéndose por pantalla el texto La
opción seleccionada es incorrecta.
El código del ejemplo anterior se puede expresar mediante sentencias if - else if del siguiente
modo:
char opcion;
Consolé.WriteLine("O.- Sumar");
Consola.WriteLine("1.- Restar");
Consolé.WriteLine("2.- Salir");
Consolé.WriteLine("Opción:");
opcion = char.Parse(Consolé.ReadLineO);
if (opcion == 'O'){
Consolé.WriteLine("Has escogido sumar");
}
else if (opcion == '1'){
Consolé.WriteLine("Has escogido restar");
}
else if (opcion == '2'){
Consolé.WriteLine("Has escogido salir");
else {
Consolé.WriteLine("La opción seleccionada es incorrecta");
: Consolé.ReadLine();
NOTA: En una sentencia switch podemos obligar a que más de un valor ejecuten las
mismas instrucciones si omitimos el uso del break. Por ejemplo, el siguiente código fuente
está permitido en C#.
int mes;
Consolé.WriteLine("Introduce el mes");
mes=xnt.Parse(Consolé.ReadLine());
switch(mes){
case 2: Consolé.WriteLine("El mes tiene 28 dias");
break;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: Consolé.WriteLine("El mes tiene 31 dias");
break;
case 4:
case 6:
case 9:
case 11: Consolé.WriteLine("El mes tiene 30 dias");
break;
}
Consolé.ReadLine();
Si el valor del mes es 3, al acceder al switch y no contener el case correspondiente un
break se ejecutarán las sentencias de los siguientes case. De este modo se alcanzará el case
12 que mostrará por pantalla el mensaje y finalizará la ejecución.
Capítulo 3. iniciación al lenguaje C# 121
ACTIVIDAD 3.8
Codifica un programa que pida al usuario un número que represente una cantidad expresada
en pesetas. Si tenemos en cuenta que 1 euro = 166,386 pesetas, muestra por pantalla la
conversión a euros de ese número de pesetas.
ACTIVIDAD 3.9
Realiza el ejercicio anterior teniendo en cuenta que el número de pesetas introducido por el
usuario debe ser mayor que cero. Si se introduce un número positivo de pesetas se realizará la
conversión, en caso contrario no se hará ninguna acción.
ACTIVIDAD 3.10
Realiza la Actividad 3.8 de fonna que la cantidad de pesetas sea positiva (Actividad 3.9) pero
en esta ocasión, si el número introducido es negativo o igual a cero se debe mostrar al usuario la
frase "El valor de pesetas establecido no es correcto".
ACTIVIDAD 3.11
Imaginemos que queremos desarrollar un programa tal que al escribir un día de la semana
aparezca por pantalla la actividad extraescolar a la que debe acudir nuestro hijo. Por ejemplo, si
ejecutamos el programa y escribimos martes que aparezca "Natación". Las actividades que se
realizan cada día son: lunes - psicomotricidad, martes - natación, miércoles - música, jueves -
natación, viernes - descanso. Los días sábado y domingo no se realizan actividades con lo que si
el usuario escribe por error alguno de estos días de la semana se debe mostrar el mensaje "Día sin
actividades". Si por equivocación, además, se escribe un día inexistente se debe mostrar en
pantalla "Día erróneo".
Descripción
nombre' contexto:
Figura 3.14. Panel "Lista de errores" de Visual Studio. Es la zona donde se podrán visualizar los diferentes
errores de compilación que se vayan produciendo.
En esta clase encontraremos atributos y métodos de clase accesible por todos los elementos de
esta incluidos entre las llaves.
Para finalizar, el bloque que incluye a todos los demás es el namespacen o nombre de
espacio que encapsula a una o un conjunto de clases. Aunque las llaves indican los límites de
acceso, al trabajar con clases podemos usar operadores de visibilidad que indicarán si algunos
elementos son accesibles o no.
Los conceptos función, clase y namespace serán vistos con más detenimiento en los
siguientes capítulos.
Capítulos. Iniciación al lenguaje O# 123
if (n>5){
int j=n;
int j;
Consolé.WriteLine("La variable j tiene el valor {0}",j);
jlonsole.ReadLine()j
}
Figura 3.16. Identificador repetido en el bloque. Error de compilación indicando que la variable ya se ha
declarado.
class P^cg'-am
{
int j;
/ static void Kain(string[] args)
{ .
int n;
Censóle.WriteLine("Introduce un valor numérico");
n"int.Parse(Censóle.ReadLineO);
^ if (n>5){
p > int j-n;
n++;
Consolé.WriteLine("La variable j tiene el valor {0}",j);
Con so le.ReadLineO;
}
Figura 3.17. Variable] declarada en dos ámbitos distintos. Declaración permitida, no se producen errores
de compilación.
Sin embargo, se aconseja al lector que utilice las llaves para evitar confusiones.
La condición del bucle será una expresión que dará como resultado un valor booleano que
determinará la continuidad o no en el bucle. En este tipo de sentencias de control repetiti\as
puede darse el caso de que nunca lleguen a ejecutarse las instrucciones que incluyen, ya que
pudiera ocurrir que la expresión condicional no sea cierta.
Veamos un ejemplo de código en el que necesitamos utilizar una senencia repetitiva,
supongamos que tenemos que desarrollar un programa que dado un número indique cuántos
divisores tiene. Si el lector lo desea, puede desarrollar el diagrama de flujo, pseudocódigo y
código fuente sin mirar la solución y así comprobar sus conocimientos.
— - - — ____ — __ — — ________ — _____ - - -1
ACTIVIDAD 3.12
ACTIVIDAD 3.14
Realiza un programa que muestre por consola algo similar a lo que ves en la Figura 3.18.
do{ i
Sentencias; ¡
}while (condición); •
Al igual con sentencias de control anteriores podemos omitir el uso de llaves si Sentencias se
refiere a una sola instrucción. Veamos un pequeño ejemplo para que el lector comprenda
claramente esta nueva sentencia. Imaginemos que tenemos que desarrollar un programa que pida
al usuario por cada mes del año, el número de días en los que ha llovido mostrando por pantalla
el total de días con precipitaciones. Se aconseja al lector que antes de observar el código fuente
intente realizarlo, siguiendo el proceso: análisis, desarrollo del diagrama de flujo y
pseudocódigo.
int totalDias=0; ;
int precipitacionesMes; I
int nies=l; I
do{ ;
Consolé.WriteLine("Introduce las precipitaciones del mes {0}",mes); I
precipitacionesMes=int.Parse(Consolé.ReadLine()); I
totalDias=totalDias+precipitacionesMes; i
mes++; 1
}while(mes <=12); ;
Consolé.WriteLine("Ha llovido este año durante {0} dias",totalDias); ;
Consolé.ReadLine(); !
ACTIVIDAD 3.15
ACTIVIDAD 3.17
Consolé.ReadLine();
Al igual que con el resto de sentencias de control podemos no usar las llaves si es una única
instrucción la que ejecuta el bucle, aunque como siempre se aconseja utilizarlas.
Las variables que se declaran en el bucle, en la cabecera del mismo, solo serán visibles en él.
ACTIVIDAD 3.18
En realidad podemos dejar en blanco cada una de las tres regiones de la cabecera de un bucle
for, nunca debemos olvidar el signo delimitador punto y coma. Con estas anomalías
conseguiremos bucles infinitos, es decir, que un programa esté ejecutándose de forma
continuada, estado no muy recomendable para muchos programas o software de aplicación
específicos.
Un bucle for puede convertirse en while y viceversa como estudiábamos en pseudocódigo.
int 1=0; xnt 1=0;
for(xnt 1=0;i<10;1++){ while(i<10){ do{
Consolé.Write(i); Consolé.Write(i); Consolé-Write(i);
i++; i++;
} while(i<10);
■ return. Usaremos retum en un elemento del lenguaje que hemos nombrado pero que
aún no se ha estudiado en profundidad, las funciones. La instrucción retum obligará
la finalización de la función. Se usa comúnmente para comtmicar funciones
secundarias con funciones principales pennitiendo el intercambio de valores a través
de variables de retomo.
^
media = iredia + numero;
} y
media = media / 50;
Ccriscie.WriteLine("La media es:{0}", icedia);
Figura 3.19. Ejemplo de uso de la sentencia break. Si numero es igual a cero se romperá el bucle de
forma que la siguiente sentencia a ejecutar es media=media/50:
Figura 3.20. Ejemplo de uso de la sentencia continué en un bucle for. Si numero es igual a cero se
incrementará el valor de i. Si la condición aún es cierta se volverá a acceder al bucle y ejecutar sus
instrucciones. Las instrucciones que se encontraran después de continué, si este se alcanza, no se
ejecutarán.
^ numero^
Y.int.Par
Parse(Console.ReadLine());
if (nuroiro"0)
{ \
continué;
}
media s inedia -t- numero;
i++;
}
media » media / 50;
Consolé.WriteLine("La media es:{0)", media);
Figura 3.21. Ejemplo de uso de la sentencia continué en un bucle while. Si numero es igual a cero se
ejecuta continué de forma que las demás sentencias (media=media+numero; y i++;) no se llevarán a
cabo. Tras comprobar la condición, si sigue siendo cierta se volverá con la ejecución de la sentencia de
control while.
{
Censóle.WriteLine("Escribe un valor de 1 a 5")j
op = int.Parse(Ccnscle.ReadLineO);
switch (op)
{
case 1: Consolé.WriteLine("Estoy en uno");
break;
case 2: goto case 1;
case 3: Consolé.WriteLine("Estoy en el tres");
break;
case 4: goto default;
case 5: Consolé.WriteLine("Estoy en el cinco");
break;
default: Consolé.WriteLine("0 has escogido la opción 4 o un número no válido");
break;
}
} while (op != 0);
}
Figura 3.23. Uso de las sentencias goto case valor y goto default.
Los case 1, 3 y 5 funcionan tal y como hemos estudiado con anterioridad. Si el usuario escoge
alguno de estos valores se mostrará el correspondiente mensaje en pantalla. Tras la visualización
la instrucción break tomará el control tal que acabará la sentencia switch y se pasará a
comprobar si la condición del bucle sigue siendo cierta.
En caso de que el usuario escoja el case 2 el compilador leerá goto case 1, es decir, "salta al
case 1" y esto es lo que hará, de forma que se visualizará el mensaje "Estoy en uno" y finalizará
el switch.
En caso de que el usuario escoja la opción 4 el compilador leerá goto default, o lo que es lo
mismo,"salta a default". Pasaremos a ejecutar las líneas de código que se encuentren en default
en nuestro switch.
< ,i
Ü* CpnsQ^WriteLineCEscribe un valor de 1 a 5**);
(0p>
(
<*>« X: «n w*)x
trc«k;
<««« 2t |c.tA c«t« 1;
c«»c li ri «n «]
c*w «1 gote
iUpe««roC(*C»corx,iM.. « ca'KitfnUwadc.
b'cM;
í 0 u*á.'.'ri£nc{3:
Descripción
T. oi
í V 1 ti
El nom
nombre 'Consol' no existe en el contexto actual
Cwipcicn •—""'1 1 ' '■ ~
Figura 3.24. Errores de compilación en Visual Studio. El error se indica en la misma línea de código (parte
superior de ia imagen) y en el panel Lista de errores (parte inferior de la imagen). El mensaje es muy
representativo dando suficiente información para la corrección del fallo.
n; \
I 1 advertencid
Descripoon
Figura 3.25. Advertencias. En el ejemplo se advierte al programador de que se ha creado una variable
nunca va a ser utilizada. Podemos ejecutar la aplicación pero si es cierto que deberíamos eliminar la linea
ya que una variable ocupa espacio en memoria.
Capítulos. Iniciación al lenguaje C# 131
Imaginemos que se nos pide la creación de un algoritmo que debe contener una constante
llamada gravedad a la que asignaremos el valor 9.8 y las variables velocidad y tiempo, esta
última tendrá asignado el valor de 2.
PSEUDOCÓDIGO
Entorno: ■
constante real GRAVEDAD=9.8; I
real velocidad; |
entero tiempo; ;
CÓDIGO FUENTE
const float GRAVEDAD=9.8f; ;
float velocidad; 1
int tiempo; ;
Imaginemos que se nos pide la creación de un algoritmo que debe contener ima constante
llamada gravedad a la que asignaremos el valor 9.8 y las variables velocidad y tiempo.
Debemos solicitar al usuario que especifique qué valor de tiempo tenemos que usar.
PSEUDOCÓDIGO
Entorno: j
/* Zona (1) del diagrama de flujos */ i
constante GRAVEDAD=9.8; i
real Velocidad; i
entero Tiempo; ;
Inicio: i
/*zona (2) del diagrama*/ j
Escribir "Introduce el tiempo"; !
Leer Tiempo; ■
Fin; i
CODIGO FUENTE
ENUNCIADO
■ Imaginemos que se nos pide la creación de un algoritmo que debe contener una constante
llamada gravedad a la que asignaremos el valor 9.8 y las variables velocidad y tiempo.
Debemos solicitar al usuario que especifique qué valor de tiempo tenemos que usar. En caso de
que este valor sea menor o igual a O se mostrará el mensaje "Tiempo incorrecto" y finalizará el
programa. Si el usuario escribe un valor de tiempo correcto, es decir positivo, se calculará el
valor de velocidad (gravedad x tiempo).
PSEUDOCÓDIGO
Entorno:
/*Zona (1)*/
constante real GRAVEDAD;
real Velocidad;
entero Tiempo;
Inicio:
/*Las siguientes dos lineas forman la zona (2)*/
Escribir "Introduce el tiempo";
Leer Tiempo;
Si Tiempo > O entonces
/*Zona (4)*/
Velocidad=GRAVEDAD*Tiempo;
Escribir Velocidad;
/*Zona (5)*/
Escribir "Tiempo incorrecto";
FinSi;
CÓDIGO FUENTE
const float GRAVEDAD=9.8f;
float velocidad;
int tiempo;
Consolé.WriteLine("Introduce el tiempo");
tiempo=int.Parse(Consolé.ReadLine());
if(tiempo>0){
velocidad=GRAVEDAD*tiempo;
Consolé.WriteLine(velocidad);
else{
Consolé.WriteLine("Tiempo incorrecto");
Supongamos que se nos pide hacer un pequeño menú de tres opciones. Este debe visualizarse
como sigue:
1. Calcular diámetro.
: , 2. Calcular circunferencia, .j
Capítulos. Iniciación al lenguaje O# 133
3. Calcular área.
PSEUDOCODIGO
Entorno:
CODIGO FUENTE
ENUNCIADO
Se precisa realizar un algortimo que calcule si los números introducidos por el usuario son
pares o impares. Para ello se debe pedir al usuario un número, se comprueba si este es par o
impar mostrando por pantalla los mensajes "El número es par" o "El número es impar" según el
caso. A continuación se preguntará al usuario si desea finalizar la ejecución del software. Si su
respuesta es No (n), repetiremos el proceso descrito pidiendo un nuevo número, en caso
contrario, si especifica Sí(s) finalizará el programa.
PSEUDOCÓDIGO
Entorno:
entero Numero;
carácter Salir;
Inicio:
/*La petición del número se encuentra dentro del bucle*/
Hacer
Escribir "Introduce un número";
Leer Numero;
Si (Resto(Numero/2))=0 entonces
Escribir "El número es par";
Sino
Escribir "El número es impar";
FinSi;
Escribir "¿Desea finalizar (S/n)?";
Leer Salir;
Mientras Saliro's';
CODIGO FUENTE
int numero;
char salir;
do{
Consolé.WriteLine("Introduce un número");
numero = int.Parse(Consolé.ReadLine ());
if ((numero % 2) == 0){
^ L:onsole.WriteLine("El número es par");
else {
Consolé.WriteLine("El número es impar");
ENUNCIADO
En el siguiente enunciado se pide al programador que realice un algoritmo por él, se solicite al
usuario la introducción de diez números y muestre por pantalla cuántos de ellos eran positivos,
cuántos negativos y cuántos cero.
PSEUDOCODIGO
Entorno:
entero Contador, Numero;
entero Positivos, Negativos, Ceros;
Inicio;
Positivos=0;
Negativos=0;
Ceros=0;
Para Contador=0 a 10 incremento 1 hacer
Escribir "Introduce un número";
Leer Numero;
Si Numero < O entonces
Negativos=Negativos+l;
Sino
Si Numero > O entonces
Positivos=Positivos+l;
Sino
Ceros=Ceros+l;
FinSi;
FinSi;
FinPara;
Escribir "Negativos:";
Escribir Negativos;
Escribir "Positivos:";
Escribir Positivos;
Escribir "Ceros:";
Escribir Ceros;
CODIGO FUENTE
int numero;
int positivos=0;
int negativos=0;
int ceros=0;
for (int contador=0; contador<10; contador++){
Consolé.WriteLine{"Introduce un número");
numero=int.Parse(Consolé.ReadLineO);
if(numero<0){
negativos++;
else{
if(numero>0){
positivos++;
}
else{
ceros++;
Consolé.WriteLine("Negativos:{O}",negativos);
Consolé.WriteLine("Positivos:{O}",positivos);
Consolé.WriteLine("Ceros:{O}",ceros);
Consolé.ReadLine();
COMPRUEBA TU APRENDIZAJE
1. ¿Cuáles son las características principales de C#?
2. ¿Para qué se usa using en C#? ¿Y la función Main? ¿Cuál es la estmctura básica de
un programa C#?
3. ¿Qué se entiende por identifícador? ¿Qué reglas debe cumplir en C# un identificador
para que sea válido en el lenguaje?
4. ¿Qué tipos de datos podemos usar en C#? ¿Qué podemos decir del siguiente dato
2.3f?
5. ¿Qué estamos haciendo en la línea de código int a=9;? ¿Qué debemos hacer si
queremos realizar la siguiente asignación int a=3.2;? ¿Es válida la siguiente
instrucción: int num=Console.ReadLineO;?
6. ¿Qué tipos de operadores encontramos en C#? ¿Qué función desempeña el operador
sizeofQ;?
7. ¿Es correcta la siguiente sentencia: if(a=3){..,}? Justifica tu respuesta.
8. ¿Si declaramos una variable entre las llaves de un bucle for podremos visualizar esta
cuando el bucle finalice? Justifica tu respuesta.
9. ¿Qué diferencias encuentras entre break, continué y return?
10. ¿Qué tipos de errores pueden aparecer durante la creación de código fuente?
ACTIVIDADES DE AMPLIACION
1. Realiza un programa que muestre las tablas de verdad de los operadores &&, 1| y !.
Utiliza variables booleanas. Recuerda que en el Capítulo 2 tienes estas tablas.
2. En esta actividad se espera analizar los operadores a nivel de bits vistos en el
capítulo. Para ello, realiza un programa que pida al usuario dos números enteros.
Realiza todas las operaciones a nivel di bits vistas y muestra los resultados obtenidos
por pantallas,justifica razonadamente estos.
3. Realiza un programa que muestre el tamaño de los tipos de datos vistos en el capítulo.
4. Realiza un programa que pida al usuario su nombre y dos apellidos. Una vez los haya
introducido deberá mostrar estos del siguiente modo:
Capítulos. Iniciación al lenguaje C# 137
6. Realiza un programa para una tienda tal que en función de las compras que realicen
sus clientes se les aplique un decuento u otro:
■ Si el importe de la compra es menor de 200 euros no se aplica descuento.
■ Si el importe de la compra es cómo mínimo 200 euros pero no supera los 500
se aplica un descuento del 5%.
■ Si el importe de la compra oscila entre los 500 y 1000 euros el descuento a
aplicar es del 10%.
■ Si el importe supera los 1000 euros se aplicará un descuento del 15%.
7. Realiza un programa que pida al usuario un año y muestre por pantalla si este es
bisiesto.
12. Realiza un programa tal que dado un nútnero de 5 cifras compruebe si es palíncromo.
13. Realiza varios programas tal que se muestren las siguientes figuras en pantalla:
00000 0 00000
@000 00 0000
@00 @00 000
00 0000 00
0 00000 0
16. Realiza un programa que pida al usuario el lado de un cuadrado. Este valor debe ser
menor de 20. Dibuja en pantalla el cuadrado que corresponde con el valor
introducido.
17. Realiza un programa que muestre la siguiente figura por pantalla.
###
#####
###
#
18. Realice un programa que muestra la tabla de código ASCll por pantalla de la
siguiente fonna:
1 - carácter 2 - carácter 3 - carácter
19. Mejora el ejercicio anterior de forma que en esta ocasión las columnas se muestren
como siguen:
1-carácter 31-carácter 61-carácter ...
2 - carácter 32 - carácter 62 - carácter ...
20. Realiza un programa tal que pida al usuario una fecha del año (días y mes) y muestie
por pantalla los días transcurridos desde el 1 de enero.
21. Realiza un programa que pida al usuario un número y muestre por pantalla si este es
primo o no.
22. ¿El siguiente código es correcto? Localiza los errores.
—
; int i=0,nuin;
¡ while (i>0){
I num+=i;
CAPITULO 4
FUNCIONES
CONTENIDOS OBJETIVOS
Entender la recursividad y la
sobrecarga de funciones.
4.1. INTRODUCCION
Hasta ahora hemos estado realizando pequeños programas, aplicaciones de consola con no
demasiadas líneas de código. En la vida real, los programas son extensos y a veces inabordables
por una única persona. Además, en muchas ocasiones, existen grupos de líneas de código que
deben repetirse a lo largo de toda la aplicación.
Normalmente, cuando se desarrolla un software se establecen grupos de trabajo donde una
serie de programadores se encargan de codificar cada parte de la aplicación. La codificación se
hace de tal forma que ningún programador tiene por qué conocer exhaustivamente cómo
funciona o qué líneas posee el código del compañero para poder usarlo. Esta es básicamente la
esencia del diseño descendente o Top-Down.
El diseño descendente pone en práctica la frase "divide y vencerás" de forma que se aborda
un problema dividiendo este en partes más pequeñas. Se dividirá nuevamente cada parte en otras
tantas cuantas veces sea necesario hasta limitar acciones más fáciles y capaces de ser
desarrolladas por una única persona.
mmmm
■ Simplifica la programación.
■ Permite que un programa pueda ser desarrollado por más de ima persona.
■ Contribuye a la creación de bloques de código reutilizable.
■ Favorece la abstracción.
4.2. ABSTRACCIÓN
Según la Real Academia de la Lengua Española, abstracción es "/a acción y efecto de
abstraer o abstraerse", siendo abstraer "'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". Si esta defmición la aplicamos al desarrollo de software se ajustaría
bastante bien a uno de los paradigmas de la programación orientada a objetos por la que al
usuario solo le interesa saber qué operaciones puede realizar con un objeto, pero no la forma en
la que esas operaciones han sido diseñadas o codificadas.
En programación estructurada existen mecanismos de abstracción de forma que un
programador puede desarrollar un bloque de código y que este sea funcional y pueda ser usado
por otros programadores pero sin conocer los detalles de la programación del mismo.
Así, podemos definir la abstracción como el mecanismo por el que se consigue que un bloque
de código pueda ser usado sin conocer los detalles de su programación. La persona que lo utiliza
sólo necesitará conocer qué función desempeña, que elementos necesita para comenzar a
funcionar y cuáles serán las salidas obtenidas.
En programación estructurada se procede a la abstracción de acciones mientras que en
programación orientada a objetos la abstracción se da en los datos.
En la Figura 4.2 se observa un código fuente sin abstracción, donde las operaciones a realizar
son visibles por todos aquellos que tengan que acceder a programar o incluir funcionalidad en el
Main. En la parte inferior, el mismo código se encapsula de algún modo de forma que no
conocemos las instrucciones usadas, solo sabemos que tenemos un identifícador llamado
sumarNumerosO.
4.3. SUBPROGRAMAS
Cuando desarrollamos un software teniendo en cuenta el diseño descendente, existen dos
elementos fundamentales, el programa principal y los subprogramas que ayudarán en la
resolución del problema.
En el programa principal es donde se soluciona el problema planteado, origen del software, y
es donde incluiremos las denominadas llamadas a subprogramas. El programa principal suele ser
sencillo y no muy extenso, además al observarlo se denota claramente la funcionalidad del
problema que se está desarrollando.
Un subprograma en cambio se encargará de resolver una parte del problema. Para ello puede
usar otros subprogramas. Un subprograma se codifica pero no se ejecuta hasta que en alguna
línea del código principal u otro subprograma se le "llame". La llamada a un subprograma
consiste en escribir el nombre de este cuando nos sea necesario.
//Llamada a la función
suma=Sumar_Dos_Numeros(a,b);
El pseudocódigo anterior muestra un ejemplo de uso de ima función. Esta se crea en esta
ocasión en el mismo fichero de código fuente que la función principal que la va a utilizar. Se
observa cómo en la declaración, los valores de entrada o parámetros se establecen indicando el
tipo de datos que almacenan, sin embargo, algo más abajo, cuando se utiliza la función no es
necesario indicar este, solo debemos escribir las variables del mismo tipo que se van a usar
(Sumar_Dos_Numeros(a,b);).
El usar funciones implica la devolución de un valor de forma que cuando se hace la llamada a
la función esta debe ser asignada a alguna variable o escribirse en alguna instrucción, tipo salida
de datos. La llamada a una función o procedimiento consiste tan solo en escribir el nombre del
mismo sin olvidar los paréntesis y posibles parámetros de entrada.
Subprograma Sumar_Dos_Numeros()
Entorno:
entero numl, num2;
entero suma=0;
Inicio:
Escribir "Introduce un numero";
Leer numl;
Escribir "Introduce otro número";
Leer num2;
suma=numl+num2;
Escribir "La suma de ambos números es:";
Escribir suma;
FinSumar_Dos_Numeros;
En este pseudocódigo estamos desarrollando un procedimiento. Vemos que no existen ni en la
cabecera ni en el código referencia a retomo de ningún valor. Se realizan todas las operaciones
en el subprograma y una vez este fianliza cede el control al programa principal o subprograma
que lo llamó. Es equivalente a los algoritmos que hemos estado realizando a lo largo de estos
primeros capítulos.
144 Programación
Al igual que ocurría con eí ejemplo en el que creábamos y utilizábamos una función, en este
se declara y crea el subprograma en el mismo fichero donde se ubica el programa principal. Sin
embargo, en el código del programa principal solo se realiza la llamada al procedimiento, ya que
es este quien codifica todas las operaciones de entrada y salida. La llamada no implica ninguna
asignación como podemos observar en la línea Suniar_Dos_NunierosOv
Conforme se realicen actividades, se desarrollen programas, iremos adquiriendo experiencia y
sabremos en cada momento qué tipo de subprograma usar (subprograma o función) y si debemos
utilizar parámetros o no.
4.4. FUNCIONES EN O#
C# dispone de dos mecanismos para implementar la modularídad. funciones y clases. El
término modularídad se ha definido ya de forma subliminal en este capítulo pues constituye la
esencia del diseño descendente, sin embargo establezcamos a continuación una definición
formal.
2. Ping.
3. Salir.
/*Función menú*/
int opcion;
Consolé.WriteLine("MENU");
Console.WriteLineC'l. Información");
Consolé.WriteLine("2. Ping");
Consolé.WriteLine("3. Traza");
Consolé.WriteLine("4. Salir");
Consolé.WriteLine("¿Qué deseas hacer?");
opcion = int.Parse(Consolé.ReadLineO);
return opcion;
Función necesaria para mostrar información de red. Esta función proporciona datos
relacionados con la red:
2. ¿Necesita algún parámetro? No. La infonnación será extraída del sistema con lo que
la función principal no necesitará comunicarse con esta.
3. ¿Devolverá algún valor? Antes de responder a esta pregunta pensemos qué queremos
hacer realmente en esta función. Debido a que el objetivo de este ejemplo es que el
lector entienda por qué usar funciones, cómo configurarlas y utilizarlas, no vamos a
incluir demasiado código C# nuevo que pueda llevar a confusión. Así, la función
infoRed mostrará todas las interfaces de red del equipo, de cada una de ellas
proporcionará información sobre: descripción de la interfaz, si usa el protocolo IPv4 o
IPv6, la dirección MAC y el tipo de adaptador. La función se limitará a mostrar
información al usuario a través de la pantalla, una vez se visualice esta, pasaremos el
control al programa principal para que vuelva a activar el menú, con lo que no existe
ningún intercambio de variables entre el programa principal y la función, así NO se
devolverá ningún dato. En este lugar en la cabecera de la fiinción escribiremos void.
4. ¿Debemos usar modificadores? Utilizaremos la palabra static.
~ — — — — — — — — —1
/* ;
Función estática infoRed I
^Parámetros de entrada: ninguno ;
Valor devuelto: ninguno
//Tipo de interfaz
Consolé.WriteLine("Tipo de adaptador:(O}
,adaptador.NetworkinterfaceType);
if (adaptador.Supports(NetworkInterfaceComponent.IPv4))
Consolé.WriteLine("Versión del protocolo IP: IPv4");
Consolé.WriteLine("-
}
Consolé.ReadLine();
/* i
Función estática ping •
Parámetros de entrada: cadena de caracteres (dirección IP) !
Valor devuelto: ninguno ;
Llegados a este punto hemos finalizado la primera parte del ejemplo, hemos desarrollado
todas las funciones. En Visual studio, debemos crear un nuevo proyecto e incluir todas estas
funciones entre las llaves de la clase (línea que comienza con la palabra resei-vada class).
Finalmente, debemos ver algo similar a esto;
namespace Funciones
{
class Program
break; ;
case 3: Consolé.WriteLine("Gracias por usar este :
software"); ^
break;
default: Consolé.WriteLine("Opción inexistente"); :
break;
152 Programación
Consolé.ReadLine();
Las llamadas se realizan en los casos 1 y 2. Observamos que una llamada a una función
equivale a colocar su nombre seguida de paréntesis en el lugar donde se desea sea ejecutada.
Cuando el usuario escoja la opción 1 accederemos al case 1 y se leerá infoRedO, se detecta que
esta es una función y que debe ser localizada en el resto del código. Una vez la encontramos
pasan a ejecutarse sus líneas. Al finalizar, la ejecución continúa justo después de la llamada a la
función en el código principal.
Si la función tiene parámetros, a la hora de realizar la llamada estos no pueden omitirse. Por
ejemplo, la cabecera de la función ping es static p¡ng(string ip) de forma que cuando la usemos
debemos especificar entre los paréntesis un valor que sea compatible con el parámetro
establecido. En el caso 2, en la función principal, la llamada se muestra como pingfip), la
diferencia con la declaración es la omisión del tipo de datos. Esto es así debido a que en la
llamada se incluye entre los paréntesis variables o expresiones del tipo de dato que indica la
declaración, es decir, cuando realizamos la llamada pasamos a ejecutar el código, de forma que
es preciso establecer valores concretos a los parámetros de entrada.
Como regla general:
//Declaración de lafunción
modificador tipo_devuelío nombre_función(tipoparí, tipopar2,..., tipoparn){
Sentencias;
return expresión; //Si tipo_devuelto es distinto de void
Sentencias;
Resumiendo:
■ Definición o declaración de la función. Desarrollo de la función, especificación del
código fuente de esta.
■ Invocar o llamar a una función. Momento en que se hace referencia a ella en otra
zona del código de forma que se da la orden de ejecución de esta.
■ Paso de parámetros. Si la función tiene parámetros, cuando realizamos la llamada
estos deben ser sustituidos por variables o expresiones del tipo de datos
correspondiente.
■ Valor devuelto. En caso de que la función devuelva un valor este debe ser usado en
una expresión, aunque no producirá error si no se considera.
La Figura 4.4 es bastante representativa.
NOTA: Una función que no devuelve valor finaliza cuando acaban sus instrucciones,
accedemos a la llave de cierre. En caso de que usemos la sentencia return, será ahí donde
finalice. Aunque suele estar al final, podemos encontrar retum en cualquier parte del |
código, en ocasiones hasta varias veces.
EJECUCIÓN
ACTIVIDAD 4.1
Crea una función que pida el lado de un cuacirado y calcule su área. Usa posteriormente esta.
ACTIVIDAD 4.2
Codifica una función que pida los valores necesarios para calcular el área de un triángulo. Usa
posteriormente esta.
ACTIVIDAD 4.3
Crea una función que calcule la potencia a partir de la multiplicación de la base x las y
veces del exponente. Usa posterionuente esta función.
ACTIVIDAD 4.4
Desarrolla una función que devuelva verdadero o falso según si el carácter que recibe como
parámetro es o no una vocal (vocal = verdadero, consonante = falso). Codifica una función
154 Programación
a=b;
b=c;
Resultado final
a=4 y b=6
Llamada a intercambio
Paso por valor
.j ^ a=5yb=4
<r- ~r u n
- Función principal
Static void Main(string[] args)
i{
í b=6
j int a, b;
I a ■ 4;
b ■ 6;
^ intercairbio(ref a, ref b);
^ CcPScle.Kr^eLineCasiB} y b*!!}", a, b); '
Llamada a intercambio
Paso por referencia
nombre_función(refvari,..., refvarn); i t
ACTIVIDAD 4.5
Escribir una función llamada redondear tal que acepte como parámetros un número real y un
número entero, siendo el primero de ellos el que se debe redondear, según se intuye en el nombre
de la función. La función devolverá el número redondeado la cantidad de posiciones decimales
que establezca el parámetro entero a través del propio parámetro real, es decir, cuando
realicemos la llamada: redondear (numero, posiciones); será en número donde se almacena el
resultado, la función no devuelve ningún tipo de datos.
Ejemplo: redondear (2.3658,2) -> 2.37.
ACTIVIDAD 4.6
b. Cuadrado.
c. Rectángulo.
d. Triángulo.
e. Salir.
Se deben usar funciones. Se aconsej'a que el lector practique el paso de parámetros por valor y
referencia tal y como se ha estudiado, aunque lo ideal en este tipo de ejercicios es que se
devuelva el valor pedido de forma normal.
Recuerda que;
Área del círculo = PI * radio^
Área del cuadrado = lado^
Área del rectángulo = ancho * alto
Área del triángulo = base * altura / 2
■ de manipulación de cadenas.
■ fecha y hora.
■ de carácter.
■ aleatorias.
Funciones trigonométricas:
■ Acos(x), Asin(x) y Atan(x). Arco coseno, seno y tangente de x.
■ Cos(x), Sin(x) y Tan(x). Coseno, seno y targente de x.
Funciones logarítmicas:
■ Exp(x). Calcula e^
■ Log(x). Logaritmo neperiano de x.
■ LoglO(x). Logaritmo decimal de x.
Este pequeño progi'ama ejemplo tiene un faíío que podremos suplir en el siguiente capítulo
cuando estudiemos el tipo de datos array. Los números aleatorios pueden aparecer repetidos.
4.8. RECURSIVIDAD
Cuando se estudian las funciones es común hablar de funciones recursivas. Una función es
recursiva cuando entre sus líneas realiza una llamada o invocación a sí misma.
nombreJunción(varl,... ,var2);
factorial(l)=l;
¿Cuál podría ser el caso recursivo? Si observamos el cálculo del factorial líneas más arriba,
veremos que multiplicamos continuamente un número por su inmediatamente anterior, de fonna
que podemos decir que el factorial de un número podría expresarse igualmente como:
n!=n*(n-l)!, o lo que es lo mismo
factorial(n)= n*factorial(n-l);
Dicho todo esto:
Factorial(n) K—
n'Factoria!(n,) 3=4-1
factor¡al(4)=4"5=24
4"Factorla!(3)
Oj'Factorial (Oj)
1=2-1
2*Factorial(1) factorial(2)=2"l=2
[ FactorÍ3l(l)=l[—
Figura 4.10. Ejemplo de ejecución, cálculo del
Figura 4.9. Ejecución recursiva de la función
factorial de 4.
factorial(n).
Aunque las Figuras son muy representativas y muestran el proceso de ejecución de vma
función recursiva, vamos a desarrollar una tabla de seguimiento suponiendo que el valor de
entrada sea 4(n=4).
fact=fact*i 4*3=12 3
i—, 2>1 Verdad 12 2
fact=fact*i 12*2=24 2
i--, 1>1 Falso 24 1
ACTIVIDAD 4.7
Realiza una función recursiva que calcule el Fibonacci de un número especificado, teniendo
en cuenta que:
Tenemos dos representaciones de la íúnción suma, aunque el objetivo es sumar dos números,
cada una hace la operación de diferente forma. El nombre de ambas funciones es el mismo, la
Capítulo 4. Funciones 165
diferencia estriba en los parámetros que reciben. La primera no usa parámetros, mientras que a la
segunda le pasamos un número entero. A la hora de realizar la llamada se diferenciarán
claramente aunque se llamen igual, con lo que no existirá ambigüedad alguna.
Para sobrecargar una función es necesario que cada declaración de esta se diferencie en sus
parámetros:
■ Tengan diferente número de parámetros.
■ Tengan parámetros de diferentes tipos.
■ Tengan la misma cantidad de parámetros pero de diferentes tipos.
■ Tengan diferente número de parámetros de diferentes tipos de datos.
int suma (int a,int. b) { string suma(string a,string b){
return a+b; return a+b;
void suma(){
Vector suma(Vector a) {
int ni, n2, resultj-
Vector resultado;
Console.WriteLine("Introduce los numerous");
resultado.x=x+a.x;
nl=int.Parse(Consolé.ReadLine ());
resultado.y=y+a.y;
n2=int.Parse(Consolé.ReadLine ());
resultado.z=z+a.z;
result=nl+n2;
return resultado;
Consolé.WriteLine("La suma es {0}", result);
Si existe una coincidencia exacta entre los tipos de parámetros de la función que se
esta invocando y una de las funciones sobrecargadas. En este caso, ejecuta la función
con la que ha encontrado coincidencia.
Si no existe una coincidencia exacta pero puede producirse conversión de tipos, se
ejecuta la función sobrecargada con el mismo número de parámetros.
string suma(string a,string b){
return a+b;
9. ¿Qué entiendes por recursividad? ¿Qué entiendes por caso base y caso recursivo?
10. ¿Qué entiendes por sobrecarga de funciones? ¿Cómo se consigue?
ACTIVIDADES DE AMPLIACION
1. Realiza un programa que muestre por pantalla la fecha del dia siguiente al que se
especifica. Para ello debes usar las siguientes funciones:
A. diasMes(mes). Calcula el número de dias que tiene el mes especificado entre
los paréntesis.
B. diaSiguienteQ. Da solución al problema planteado utilizando diasMes(mes).
2. Utilizando las funciones creadas en la Actividad 1 realiza un programa que calcule la
fecha correspondiente pasados n días.
3. Realiza un programa que dado un número real separe su parte entera de su parte
decimal devolviendo dos números enteros. Usa funciones.
4. Dado un número binario realiza un programa utilizando funciones, que devuelva el
número decimal correspondiente a dicho binario.
5. Realiza la operación inversa a la Actividad 4, de forma que dado un número
expresado en el sistema de numeración decimal se obtenga su binario
correspondiente.
6. Realiza un programa usando funciones de forma que muestre un menú como sigue:
A. Convertir binario-decimal.
B. Convertir decimal-binario.
C. Convertir decimal-octal.
D. Convertir decimal-hexadecimal.
E. Convertir binario-octal.
F. Convertir binario-hexadecimal.
G. Salir.
10. Desarrolla una función recursiva a la que se le pasará como parámetro un número
entero debiendo mostrar este número al revés. Por ejemplo, si el número es 3265 la
función debe mostrar el número 5623.
11. Realiza la función anterior de forma que devuelva una cadena de caracteres. Una vez
obtenido el número al revés se debe comprobar si el número original es o no
palíndromo.
12. Escribe una función recursiva que calcule la potencia de un número. El formato de la
función debe ser similar a: potenc¡a(base,exponente).
13. Realiza una función recursiva que calcule el producto de dos números mediante
sumas repetidas. producto(a,b).
14. Realiza un programa que calcule el primer número primo a partir de uno dado.
15. Realiza un programa que muestre por pantalla una pirámide de números tal que el
usuario indique el nivel de esta. Por ejemplo, si el usuario especifica nivel 4, debe
mostrarse la pirámide como sigue;
12321
1234321
16. Crea una función que dadas dos fechas indique el número de días transcurrido entre
ambos.
17. Desarrolla una función que dado un número muestre sus divisores.
18. Realiza un programa que pida al usuario un intervalo, es decir, solicite dos números
que establezcan un intervalo, por ejemplo 5 y 8. A continuación debe mostrar una
tabla similar a la que sigue para los números incluidos en el intervalo junto a los
extremos.
CONTENIDOS OBJETIVOS
Algo así sería inverosímil en programación. Con las herramientas que hasta ahora conocemos
no podríamos abordar problemas de este tipo.
Existen otros tipos de datos denominados tipos de datos compuestos que están fomiados por
los tipos de datos simples que ya conocemos.
En este capítulo estudiaremos arrays, cadenas de caracteres, estructuras y enumeraciones.
5.2. ARRAYS
Un array es un tipo de datos compuesto que permite almacenar un número x de elementos del
mismo tipo. El uso de array consigue que mediante una sola declaración hagamos referencia a un
conjunto de valores, estos valores pueden ser de los tipos de datos simples estudiados o bien de
algún tipo de datos diseñado por el usuario.
13 17 15 21 27 47
Cada elemento del array se referencia mediante su posición en la tabla, empezando a contar
en O, es decir, si quisiéramos acceder al número 2 de la tabla de la Figura 5.1., diríamos que
queremos el valor que se encuentra en la posición 2 del array.
13 17 15 21 27 47
Posición
Así, al trabajar con arrays debemos diferenciar entre su contenido y sus posiciones. El
contenido del array puede ser de cualquiera de los tipos de datos estudiados mientras que cada
posición será un número entero de O a n, siendo n el número de elementos del array menos 1.
Una de las características a tener en cuenta a la hora de crear un array es su dimensión. La
dimensión indica a groso modo el número de filas que tendrá. A mayor dimensión mayor número
de valores. Entraremos en el estudio de este ténriino más adelante, por lo pronto trabajaremos
con arrays de una única dimensión, una única fila.
Hasta ahora, cada vez que hemos realizado un acceso a una posición de un array, se ha usado
un literal entero. La posición siempre debe ser un valor entero, ahora bien, podemos usar
variables, como en el interior de los bucles vistos o expresiones.
Imaginemos el array int [] valores = new int [10]. Todas las opciones de acceso que se
muestran a continuación son válidas:
Un array puede ser pasado como parámetro en cualquier función teniendo en cuenta que este
siempre es pasado por referencia ya que como se ha explicado con anterioridad es un tipo de
datos referencia. Según esto, todas las modificaciones que realizamos sobre el objeto en el
interior de la función se verán reflejadas en él, una vez acabe esta.
Debemos tener claro que no es lo mismo pasar un array como parámetro que un elemento del
array ya que en el primero de los casos se está realizando un paso por referencia y en la segunda
ocasión por valor. Veamos un pequeño ejemplo:
static void modifica(int []n){
n[l]=9;
)
static void modifica(int a) {
a=9;
)
static void Main(string [] args){
int [] numeros=new int[]{1,2,3};
modifica(}mmeros[l]);
Pasa como parámetro el valor almacenado en la posición 1 del array números, de forma que
aunque se indique en el código interior de la función la modificación a 9 de este valor no se verá
alterado. En cambio en la línea:
modifica(nwneros);
Estamos pasando como parámetro el array completo, una referencia, de forma que la
modificación indicada se reflejará una vez acabe la función.
La salida para este pequeño trozo de código será algo así como:
Si la función void modifica(int a) hubiera sido declarada de la siguiente forma void
modifica(ref int a) estaríamos pasando el dato por referencia y sí se verían reflejadas las
modificación en el array una vez acaba la ejecución de la función.
Una vez hemos estudiado los conceptos básicos relacionados con este tipo compuesto de
datos veamos un pequeño ejemplo. En esta actividad crearemos una pequeña aplicación que
mantendrá los precios de los productos de una tienda del barrio. El programa debe mostrar un
menú en el que se visualicen las opciones:
1. Nuevo producto.
2. Precio medio.
3. Listar productos.
4. Salir.
Además, tendremos dos arrays, uno de tipo string que almacenará los nombres de los
productos y otro de tipo real que guardará los precios. Para relacionar cada producto con un
precio, tendremos en cuenta que el nombre que ocupa la posición cero del primer array tiene
como precio el que aparece en la posición cero del segundo array; el nombre de la posición uno
del primer array corresponde con el precio de la posición uno del segundo array y así
sucesivamente.
/*Función insertarProd
Inserta un nuevo producto si no esta la tienda llena. Pedirá al usuario nuevo
nombre y precio y insertará esta información al final de las tablas nombres y
precios
Parámetros de entrada: tabla nombres y precios, número total de productos
almacenados.
Salida: ninguna.*/
/*Función promedio
Realiza el promedio o media aritmética de todos los precios de los productos
de la tienda.
Parámetros de entrada: tabla precios y el número de productos almacenados.
Salida: promedio calculado.*/
/*Funci6n listarProductos
Muestra los productos de la tienda de forma que se listan nombres junto a
precios de la forma:
Nombre producto Precio
a 12
b 1
Parámetros de entrada: tabla nombres y precios, número de productos
almacenados.
Salida: ninguna.*/
Básicamente el programa se limita a usar un bucle que finalizará cuando el usuario indique
qué opción es igual a 4. Cada vuelta de la sentencia repetitiva se borrará la pantalla
(ConsoIe.CIearO), visualizaremos el menú, se dará opción al usuario a escoger la instrucción a
ejecutar y se evaluará el switch desde el que el software nos redirigirá a la función que
corresponda según el caso determinado.
— — — — -1
Consolé.Olear();
opcion = menú O;
switch (opcion)
Consolé.ReadLine();
) while (opcion != 4);
int op;
Consolé.WriteLine("1. Nuevo producto.");
Consolé.WriteLine("2. Precio medio.");
Consolé.WriteLine("3. Listar productos.");
Consolé.WriteLine("4. Salir.");
Consolé.WriteLine("Escoge opción:");
op = int.Parse(Consolé.ReadLineO);
return op;
Función promedio. Devolverá la media aritmética de todos los productos. Sumará todos los
precios y dividirá el resultado entre el total de productos almacenados. Para poder realizar la
operación será necesario que se pase como parámetro el array con los precios de los productos
además del total de elementos que contiene. El número total de elementos no hace falta que sea
pasado por referencia ya que no va a ser modificado en el interior de la función.
static double promedio (dotible[] p, int totalProductos) i
{ i
double media =0.0; ;
if (totalProductos > 0) i
( i
for (int i = 0; i < totalProductos; i++) ;
{ I
media = media + p[i];
} i
media = media / totalProductos; ¡
) :
return media; ¡
} ;
Función listarProductos. Muestra un listado de todos los productos de la tienda, visualizando
en primer lugar el nombre y a continuación su precio. Para poder realizar la operación debemos
pasar como parámetro a la función el amay de nombre, la tabla de precios y el total de productos
almacenados hasta el momento. Si no se han insetado productos se mostrará el mensaje "No se
ha almacenado aún ningún producto".
static void listarProductos(string[] nom, double[] p, int totalProductos) I
{ i
if (totalProductos > 0) ;
{ i
Consolé.WriteLine("\tPR0DUCT0S\t\t\tPRECI0"); i
Consolé.WriteLine(" "); ;
for (int i = 0; i < totalProductos; i++) ;
{ i
Consolé.WriteLine("\t{O}\t\t\t{1}",nom[i],p[i]); <
ACTIVIDAD 5.1
Crea un programa que almacene las notas de una asignatura de todos los alumnos de la clase.
ACTIVIDAD 5.2
Continúa la actividad anterior de forma que se muestre por pantalla cuál es la mayor y menor
nota.
ACTIVIDAD 5.3
Finaliza la Actividad 5.2 de forma que crees una función que obtenga la nota media de los
alumnos para la asignatura dada.
int []numeros=new...
■ Un bucle foreach se usa para recorrer todos los elementos del array.
■ Se ejecutarán las instrucciones para todos los elementos del array.
■ En la cabecera foreach (tipo variable in array), variable es un elemento de solo
lectura. Se encargará de guardar el valor de la posición del array que está siendo
analizada. Este valor puede ser interpretado y podremos realizar operaciones con él,
pero sin embargo no podremos modificar la posición del array a la que referencia.
■ El array que queremos recorrer con el foreach debe estar deelarado y creado antes de
ser recorrido.
ACTIVIDAD 5.4
Crea un array de tipo de dato string. Inicializa este a las cadenas de caraeteres que desees. A
continuación, y haciendo uso del bucle foreach, muestra por pantalla cada cadena con el número
de caracteres que contiene. La función que devuelve el número de caracteres de un tipo string es
Lengtb.
ACTIVIDAD 5.5
Crea un array de números enteros. Inicializa cada posición al valor que desees. Muestra por
pantalla para cada elemento del array si este es par o impar. Utiliza el bucle foreach.
3. Listar productos.
4. Salir.
/*Función modificarNombre
Se encarga de cambiar el nombre de un producto por otro solicitado en la misma
función.
Parámetros de entrada: Elemento del array de productos que se desea modificar.
Salida: ninguna.*/
/*Función eliminarProducto
Eliminará el producto y precio almacenados en las tablas nom y p en la
posición posEliminar. El numElementos, o lo quo___fs___lo__^m_ismq,^ el total_ _de_
Capítulo 5. Tipos de datos compuestos
/*Funci6n buscarNombre
Buscará el producto en la table de productos, cuyo nombre coincide con el
nombre pasado como parámetro. Si el producto se encuentra en la tabla devuelve
su posición, en caso contrario -1.
Parámetros de entrada: Tabla de productos, total de elementos de la tabla y
nombre del producto buscado.
Salida: Posición del producto buscado o -1.*/
E emento a e ¡minar
A la hora de buscar debemos recorrer el array hasta que el elemento buscado se encuentre o
lleguemos al fmal de este. En nuestro ejemplo buscaremos un producto concreto, si se localiza la
función buscarNombre devolverá la posición de este, en caso contrario se devolverá el número
entero -1. Este valor es muy usado en la funciones de búsqueda de objetos como identificativo de
dato no encontrado.
Existen diferentes mecanismos de búsqueda: búsqueda secuencial o lineal y búsqueda
binaria. Veremos estos a continuación tras finalizar de analizar el código fuente de nuestro
programa ejemplo. Básicamente la primera de las búsquedas es la que hemos aplicado en la
función buscarNombre, ya que el proceso de búsqueda consiste en recorrer el array de fonna
secuencial hasta encontrar una coincidencia exacta con el dato buscado.
Capítulos. Tipos de datos compuestos 185
buscado = i;
return buscado;
switch (subopcion)
{
case 1: modificarNombre(ref productos[pos]);
break;
case 2: modificarPrecio(ref precios[pos]);
break;
case 3: modificarNombre(ref productos[pos]);
modificarPrecio(ref precios[pos]);
break;
break;
case 5:
if (numElementos > 0)
{
Consolé.WriteLine("Indica el nombre del producto
a eliminar");
nomAux = Consolé.ReadLine();
pos = buscarNombre(productos,numElementos
,nomAux);
if (pos >= 0)
í
eliminarProducto(productos, precios,
ref numElementos, pos);
}
else
break;
default: Consolé.WriteLine("La opción escogida no
es válida, vuelva a intentarlo");
break;
Consolé.ReadLine();
} while (opcion != 7);
Capítulos. Tipos de datos compuestos 187
Elemento encontrado
32=32
VALOR ENCONTRADO
Subprograma Principal Q
Entorno:
j entero []tabla={.,.} //Tabla con todos los valores
^ . entero totalElementos—size; //Total de elementos almacenados en el array.
^ entero clave—valor; /*Suponemos un array de enteros aunque puede ser de
cualquier tipo, sólo debemos tener precaución a la hora de
realizar la comparación ya que todos los tipos no tienen
y''- sobrecargado el operador ==*/
entero posEncontrado;
return pos;
Capítulos. Tipos de datos compuestos 189
Subprograma Principal Q
Entorno:
entero []tabla={...} //Tabla con todos los valores
entero totalElementos—size;//Total de elementos almacenados en el array.
entero clave=valor; /*Suponemos un array de enteros aunque puede ser de
cualquier tipo, solo debemos tener precaución a la hora
realizar la comparación ya que todos los tipos no tienen
sobrecargado el operador ==*/
entero posEncontrado;
Inicio:
posEncontrado —BusquedaBinaria(tabla,totalElementos,clave);
FinPrincipal;
Fundón búsqueda binaria en C#
static int BusquedaBinaria(int []tabla,int totalElementos,int clave) {
int posCentro,posinicio, posFin;
int valorCentral;
poslnicio=0;
posFin=totalElementos-l;
while(posInicio<=posFin){
posCentro=(posInicio+posFin)/2;
valorCentral=tabla[posCentro];
if(clave==valorCentral){
return posCentro;
}
else if (clave<valorCentral){
posFin=posCentro-l;
else{
posInicio=posCentro+l;
return
Clave=54.
ACTIVIDAD 5.6
Realiza un programa que utilice como tipo de datos principal un array de caracteres ordenado.
Usa la función de búsqueda binaria tal que se busque el carácter solicitado por el usuario en el
Capítulo 5. Tipos de datos compuestos
array. Si existe dicho carácter debe mostrar en pantalla la posición en la que se encuentra, en
caso contrario el mensaje "El carácter buscado no es un elemento de la tabla".
ACTIVIDAD 5.7
Cuando pulsemos la opción 1 se realizará una búsqueda binaria y secuencia! del mismo valor,
solicitado este al usuario. Se deben registrar las iteraciones que se producen en cada bucle de
cada algoritmo, de forma que además del array principal tendremos un array entero para
almacenar las vueltas de bucle de la búsqueda secuencial y otro para el registro de vueltas de la
búsqueda binaria.
Al pulsar la opción 2 se mostrarán por pantalla los arrays relacionados con las vueltas de
bucles dadas del modo que se indica:
Valores búsqueda secuencia:
BS-0: 10 I BS-1:6 |BS-2: 8 |...
Valores búsqueda binaria:
BB-0; 3 I BB-1: 1 |BB-2:6 |...
ACTIVIDAD 5.8
Realiza una pequeña aplicación que mantenga los datos relacionados con mediciones de
experimentos en un laboratorio. Cada experimento tiene asociada una cantidad real
representativa y el nombre de la persona que lo realizó. Como máximo en un mes se realizan 60
experimentos, pasado este tiempo todos se guardan en una tabla historial (que ya se ha
programado) y se resetea nuestra infonnación, es decir, los tipos de datos donde se almacenan
nombres de experimentos, de personas que lo realizan y cantidades se vacían (todos los
experimentos pasan a llamarse exOO, las cantidades 0.0 y los nombre "vacio").
El programa debe pennitir escoger entre las siguientes opciones al usuario:
1. Almacenar nuevo experimento.
2. Eliiuinar experimento fallido.
3. Modificar experimento.
4. Contabilidad de experimentos exitosos y fallidos.
5. Listado de experimentos agrupados por persona que lo realiza.
6. Salir.
Tabla original:
12 5 3 13 2 9 7
Valor más pequeño: 2,intercambiar con la posición 0.
5 3 13 1 2 1 9 7
5 3 13 9 7
5 3 13 flT l 9 7
■ 13 12 9 7
13 12 9 7
3 5 7 12 9 13
Valor más pequeño: 9, intercambiar con la posición 4.
2 3 5 7 13
2 3 5 7 13
9 I 12 13
Capítulos. Tipos de datos compuestos 193
El siguiente valor es tabla[l], 5. ¿Es mayor o menor que 12 que ya esta insertado? Menor, así
debe ser colocado antes.
La nueva tabla se genera ordenada. El siguiente valor a insertar es 3, tabla[2]. ¿Dónde debe
colocarse? Justo antes de 5, tabla[0]. Realizamos justo en esa posición la inserción.
3 I 5 I 12
Repetidamente realizamos la misma operación;
3 I 5 I 12 I iTI
2 3 5 12 13
2 3 5 9 12 13
2 3 5 7 9 12 13
A modo formal, el algoritmo sigue el siguiente procedimiento:
1. La lista inicial estará formada por un único elemento ordenado, tabla[0].
2. Insertamos el elemento tabla[l] en la nueva lista, antes o después del valor insertado
en la posición anterior según sea este menor o mayor.
3. Para cada elemento de la tabla a ordenar se buscará en la nueva lista su posición
correcta y se desplazarán a la derecha todos los valores para dejar la casilla libre al
nuevo dato.
12
Siguiente dato a insertar: 5
5< 12
3 I 5 I 12 I 13
Realizaremos este proceso hasta que no tengamos más elementos en la tabla original.
El algoritmo para este tipo de búsqueda se muestra a continuación:
Subprograma Inserción (entero [] tabla, entero NumeroElementos)
Entorno:
entero i, j;
entero aux;
Inicio:
Para i=l a NumeroElementos-1 incremento 1 hacer
j = i;
aux = tabla[i];
Mientras j > O Y aux < tabla[j-1] hacer
tabla[j] = tabla[j-1];
FinMientras;
tabla[j] = aux;
FinPara;
FinInserción;
ACTIVIDAD 5.9
Realiza un pequeño programa que permita al usuario realizar las siguientes operaciones.
1. Inicializar array de números reales.
2. Ordenar usando el método de selección.
12 5 3 13 2 9 7
Comparamos las posiciones O y 1, tabla[0] y tabla[l], 12 y 5, están desordenados, se
intercambian:
5 12 3 13 2 9 7
A continuación, comparamos las posiciones 1 y 2, tabla[l] y tabla[2], 12 y 3, están
desordenados con lo que se procede al intercambio.
5 3 12 13 2 9 7
Comparamos las posiciones 2 y 3, tabla[2] y tabla[3], 12 y 13. Están ordenados con lo que no
se realiza ninguna acción.
5 3 12 13 2 9 7
Comparamos las posiciones 3 y 4, tabla[3] y tabla[4], 13 y 2. Nuevamente están
desordenadas. Procedemos a intercambiar.
5 3 12 2 13 9 7
Comparamos las posiciones 4 y 5, tabla[4] y tabla[5], 13 y 9. Intercambiamos ambas.
5 3 12 2 9 13 7
Comparamos las posiciones 5 y 6, tabla[5] y tabla[6], 13 y 7. Intercambiamos ambas ya que
están mal posicionadas.
5 I 3 I 12 I 2 I 9 I 7 I 13 I
Tras esta primera pasada, hemos conseguido que el mayor de los valores esté ya bien
posicionado. En la siguiente recorreremos el array hasta la posición anterior, es decir la número
5. El proceso se repite sucesivamente hasta alcanzar la posición 0.
A modo formal, los pasos seguidos en el proceso son:
1. Primera pasada. Comparamos elementos adyacentes. Si está mal posicionados ya que
el primero debe ser menor que él según se intercambian los valores. Realizamos las
comparaciones adyascentes hasta alcanzar la posición n-1 siendo n el total de
elementos de la tabla.
2. Segunda pasada. Comparamos elementos adyascentes y realizaremos los
intercambios oportunos hasta la posición n-2.
3. Siguientes pasadas. Comparamos elementos adyascentes hasta alcanzar la posición O,
estando ya esta ordenada.
El algoritmo para la búsqueda por burbuja es el que sigue:
Subprograma Burbuja (entero []tabla, entero NumeroElementos)
Entorno:
booleano ordenado = falso;
entero pasada=0, j, aux;
Inicio:
Mientras pasada<NumeroElementos-l Y No(ordenado) hacer
ordenado=verdad;
Para j = O a NumeroElementos-pasada-2 incremento 1 hacer
Si tabla[j] > tabla[j+l] entonces
ordenado = falso;
aux = tabla[j];
tabla[j] = tabla[j+1];
Capítulo 5. Tipos de datos compuestos
tabla[j+l] =
FinSi;
FinPara;
FinMientras
FinBurbuja;
ACTIVIDAD 5.10
Prueba el algoritmo de burbuja. Desarrolla un programa en el que nada más iniciar pidas al
usuario los valores de un array de números enteros. A continuación, debes mostrar paso a paso
cómo se produce la ordenación burbuja del mismo.
Vamos a usar la tabla ejemplo que hemos utilizado en otros algoritmos de ordenación:
12 I 5 I 3 I 13 I 2 I 9 I 7
Este array tiene un total de 7 elementos, tomaremos n=7.
Realizamos n/2 grupos, separados n/2 números entre ellos. n/2=7/2=3. Coloreamos en azul
los valores de la primera sublista.
12 I 5 I 3 I 13 I 2 I 9 I 7
Debemos realizar intercambios ya que no están ordenados.
7 I 5 I 3 I 12 I 2 I 9 I 13 I
Seguimos fonuando grupos de 3 a partir del segundo valor del array. Volvemos a colorear los
valores que formarán el nuevo grupo.
7 I 5 I 3 I 12 I 2 I 9 I 13
En esta ocasión solo fonuan el grupo dos números, no están ordenados con lo que tenemos
que proceder a intercambiarlos.
7 I 2 I 3 I 12 I 5 I 9 I 13
Repetimos el proceso a partir del siguiente número (3).
7 2 3 12 5 9 13
Los valores están ya ordenados, seguimos formando grupos.
7 I 2 I 3 I 12 I 5 I 9 I 13
Igualmente están ordenados. No podemos seguir formando grupos de números separados tres
posiciones de forma que volvemos a dividir entre dos nuestro intervalo, 3/2 = 1. Al llegar a 1 la
ordenación es similar a una ordenación por inserción directa.
2 7 3 12 5 9 13
2 3 7 12 5 9 13
2 3 5 12 7 9 13
2 3 5 7 12 9 13
2 3 5 7 9 12 13
2 3 5 7 9 12 13
Los pasos a seguir en este tipo de ordenación son los siguientes:
1. Teniendo en cuenta que la lista original tiene n elementos realizamos la operación
n/2, consideramos un incremento o salto entre los elementos de n/2, es decir,
obtenemos n/2 subarrays y cada elemento en las sablistas estarán separados n/2
espacios.
2. Se comparan las parejas o grupos de números en cada sablista y si no están ordenados
se intercambian.
else{
temp = tablaíj];
tabla[j] = tabla[k];
tabla[k] = temp;
j -= intervalo;
intervalo = intervalo / 2;
5 I 3 I 2 I 9 I 7
Escogemos como pivote el primer elemento, 5.
FinMientras;
Si i<=j entonces
tmp = tabla[i];
tabla[i] = tabla[j];
tabla[j] = tmp;
i++;
j~;
FinSi;
Mientras i <= j;
Si primero < j entonces
Quicksort(tabla, primero, j);
FinSi;
Si i < ultimo entonces
quicksort(tabla, i, ultimo);
FinSi;
FinQuicksort;
if (i<=j){
tmp = tabla[i];
tabla[i] = tabla[j];
Capítulo 5. Tipos de datos compuestos
tabla[j] = tmp;
i++;
j--;
}
)while (i <= j);
if (primero < j){
Quicksort(tabla, primero, j);
)
if (i < ultimo){
quic)csort(tabla, i, ultimo);
)
ACTIVIDAD 5.11
Realiza un programa que muestre un menú desde el que se puedan realizar todas las
ordenaciones vistas en este apartado. Usa arrays de otros tipos de datos como double, char o
string. Recuerda que para este último tipo de datos debes usar funciones como CompareTo para
descifrar cuál de las cadenas comparadas es menor o mayor.
NOTA: Todos los arrays que hemos usado en los algoritmos de ordenación han sido j
de tipo entero. Se optó por este tipo ya que es sencillo y no complica la explicación de |
estos algoritmos que definitivamente es lo importante del apartado. !
Hasta ahora hemos estado usando arrays de una dimensión, conocidos también como
vectores, tablas o listas. Estos airays se recorren con ayuda de un solo índice. En este apartado
vamos a estudiar arrays de más de una dimensión para los que necesitaremos más de un índice a
la hora de ser recorridos.
Los arrays multidimensionales más comunes son los de dos dimensiones o bidimensionales,
también llamados matrices. Es común representar este tipo de datos como una tabla compuesta
por una serie de filas y columnas:
dato(n,0) dato(n,n)
Entre los paréntesis (0,0),(1,0), etc., hemos colocado los índices que identifican a cada celda
de la matriz. El primero de ellos representa la fila y el segundo la columna, tal que dato(2,l) está
referenciando el valor ubicado en la fila 2 y la columna 1.
Podemos generar arrays de tantas dimensiones como queramos aunque es cierto, que la
mayoría de los problemas más complejos como máximo necesitarán 3 dimensiones. En este
apartado centraremos nuestra atención en los arrays bidimensionales.
5.2.10.1. DECLARACION Y CREACION DE ARRAYS MULTIDIMENSIONALES
EN C#
Al igual que veíamos en los arrays de una única dimensión, los arrays multidimensionales
deben declararse y crearse adecuadamente antes de poder ser usados.
La declaración incorpora en los corchetes una coma por cada dimensión adicional, es decir, si
queremos declarar un array de dos dimensiones pondremos una coma entre los corchetes, si es de
tres dimensiones, ubicaremos dos, y así sucesivamente.
'
I I
\ tipo_de_datos[,
] identificador; \
Ejemplos:
int [,] números;
double [„]reales;
En cuanto a la creación, debemos establecer el tamaño real de cada dimensión. Usaremos el
operador new para realizar la reserva de memoria.
matriz[0,0]=12;
matriz[0,l]=13;
12 13 matriz[0,2]=5;
I íy ^ — matriz[6,4]=6;
\ 4 Realizar la inicialización de esta forma es
^ bastante tedioso y generaría demasiado
-L: Z Z Z Z— código. En el ejemplo tenemos una matriz de
I 1 I 39 I 5 154 16 gj tuviéramos que realizar la
Figura 5.9. Representación gráfica de una inicialización de una matriz de 100x100 el
matriz bidimensional. proceso sería inviable.
INICIALIZACIÓN EN EL MOMENTO DE CREACIÓN DE LA MATRIZ
Podemos inicializar una matriz justo en el momento en que se crea esta, al igual que veíamos
con los arrays de una única dimensión. Usamos las llaves para delimitar grupos de elementos de
cada fila y columnas.
tipo[,]matr¡z—new iipo[filas,columnas]{{elementos_Jila}{elementos_columnas}} \
tipo[,]matriz={{elementos_fila}{elementos_columnas}} i
tipo[,]matriz=new tipo[,]{{elementos_Jilas}{elementos_columnas}} :
4. Suma matrices.
7. Traspuesta.
8. Salir.
1+5=6 2+6=8
3+7=10 4+8=12
X 5=
1*5+2*7=19 1*6+2*8=22
3*5+4*7=43 3*6+4*8=50
A donde Aij=A ji
/♦Función menú
Muestra el menú, pide al usuario que escoja una opción y devuelve la opción
elegida.
Parámetros de entrada: ninguno.
Salida: Número entero.
*/
static int menú()
{
int opcion;
Consolé.WriteLine("1. Rellena la primera matriz");
Consolé.WriteLine("2. Rellena la segunda matriz");
Consolé.WriteLine("3. Visualiza las matrices");
Consolé.WriteLine("4. Suma matrices");
Consolé.WriteLine("5 . Producto por un escalar");
Consolé.WriteLine("6. Producto de matrices.") ;
Consolé.WriteLine("7. Traspuesta");
Consolé.WriteLine("8. Salir") ;
Consolé.WriteLine("Escoge opción:");
opcion = int.Parse(Consolé.ReadLine O);
return opcion;
}
/♦Función inicializa
Inicializa la matriz pasada como parámetro.
Parámetros de entrada: Matriz de números enteros.
Salida: ninguna.
♦/
static void inicializa(int[,] matriz)
/♦Función sumar
Suma las matrices pasadas como parámetro. El resultado no se almacena,
simplemente se muestra por pantalla.
Parámetros de entrada: matrices a sumar.
Salida: ninguna.
♦/
static void sumar(int[,] mi, int[,] m2)
Console.Write("{0}\t",matriz[i,j])
}
Consolé.Write("\n");
/*Función prodEscalar
Realiza el producto escalar de una matriz por un número dado. El resultado se
muestra por pantalla, no es almacenado.
Parámetros de entrada: numero entero y matriz de números enteros.
Salida: ninguna.
*/
static void prodEscalar(int num, int[,] matriz)
/*Función product
f'-ssliza el producto de dos matrices y muestra el resultado por pantalla,
atendiendo a las especificaciones de cálculo de producto de matrices antes
visto.
Parámetros de entrada: las matrices de números enteros a multiplicar.
Salida: ninguna.
*/
static void producto(int[,] mi, int[,] m2)
int matriz_producto=0;
for (int le = 0; k < FILAS; k++)
{
for (int j = 0; j < FILAS; j++)
{
matriz_producto=0;
for (int i = 0; i < COLUMNAS; i++){
matriz_producto += ml[k,i] * m2[i,j];
}
Consolé.Write("{O}\t", matriz producto);
}
Consolé.Write("\n");
/*Función traspuesta
Realiza la traspuesta de una matriz dada. Muestra el resultado por pantalla.
Parámetros de entrada: matriz de números enteros.
Salida: ninguna.
*/
static void traspuesta(int[,] matriz)
{
for (int i = 0; i < FILAS; i++)
{
for (int j = 0; j < COLUMNAS; j++)
{
Consolé.Write("{O}\t", matriz[j, i]);
}
Consolé.Write("\n");
ACTIVIDAD 5.12
Imagina que debes mantener las notas de los alumnos de tus tres asignaturas. En cada
asignatura tienes 15 alumnos, tal que se debe mantener la información mediante una variable que
gráficamente presenta esta estructura:
Asignatura1 5 6 2.3 4.3 5.7
Asignatura2 3 3 5 6 6
Asignatura3 2 1 2.3 5.6 5
Crea una aplicación con la que puedas:
1. Insertar las notas de la asignatura seleccionada.
2. Insertar todas las notas.
6. Salir.
La opción Estadística muestra la cantidad de notas entre O y 3, entre 3.1 y 5, entre 5.1 y 7,
entre 7.1 y 9 y 9.1 y 10.
Una matriz irregular o escalonada no es más que un array cuyos elementos son a su vez
tablas. Gracias a este tipo de array, podemos usar matrices con un número x de filas tal que cada
fila puede tener un número diferente de columnas.
Capitulo 5. Tipos de datos compuestos 209
Podemos anidar tantas tablas como queramos, de forma que tendremos multitud de tablas
enlazadas. Todas los arrays deben ser del mismo tipo de datos.
o ^ 1 2 3 4 5
. I ^1 O I 15 10 13
. ^1 76 12
Las declaraciones anteriores dan lugar a un tipo de datos similar al que se representa en la
Figura 5.12.
No es necesario indicar el tamaño ya que los valores que se incluyen entre las llaves imponen la
dimensión.
A la hora de acceder a cada elemento de un array escalonado, debemos indicar la fila en la
que se encuentra y su columna, como hacíamos con arrays de una y varias dimensiones, eso sí,
aquí usaremos un par de corchetes para especificar cada índice.
1 nombre[fila][columna]=valor;
En el ejemplo usamos un bucle for para recorrer cada fila ya que cada una apunta a diferente
número de elementos.
ACTIVIDAD 5.13
Realizar la Actividad 5.12 tal que en cada asignatura tengamos un número diferente de
alumnos.
ACTIVIDAD 5.14
Imagina que tienes que realizar una aplicación para una tienda de forma que esta necesita
almacenar sus productos en categorías:
T. T 1 TI 1 Queso fresco Yogures
Lácteos Leche Puleva _,
Día danone
Coca cola
Bebidas
La primera cadena de caracteres representa el nombre de la categoría y los demás casillas los
nombres exactos de productos. Como se observa no tendremos la misma cantidad de productos
en cada categoría. La aplicación debe permitir realizar las siguientes operaciones:
Capítulo 5. Tipos de datos compuestos 211
Inicializar la matriz.
Cada vez que escribamos en nuestro código fuente combinaciones alfanumérícas entre
comillas dobles ("") el compilador tomará esta como un valor de tipo string. Además, podemos
inicializar variables string a partir de arrays de tipo carácter creados con anterioridad.
char []letras=char[]{ 'M','u','n','d',
'o'};
string frase=new string(letras);
Usamos la palabra reservada new para crear un objeto string al que pasaremos como
parámetro el array de tipo carácter letras.
El tipo de datos string dispone de una serie de métodos y propiedades de bastante utilidad.
■ Length. Devuelve el tamaño o número de caracteres.
■ ToCharArrayO. Método que devuelve un array de caracteres, de forma que en cada
posición de este array encontraremos un carácter de la cadena almacenada en el
string. Convierte un string a un array de caracteres.
■ SubStringO. Extrae una parte de la cadena. Este método está sobrecargado de fonua
que encontraremos SubString(int inicio) y SubStríng(int inicio, int tamaño). El
primero de ellos extrae una subcadena desde la posición inicio hasta el final. El
segundo permite establecer más concienzudamente los limites de la subcadena, ya
que debemos especificar dónde empieza y qué tamaño tiene.
■ CopyToO. Copia un número detenninado de caracteres situados en una posición
concreta del string en una posición de un array de tipo carácter.
■ CompareToQ. Compara la cadena de caracteres que contiene el string que llama al
método con otra dada. Devuelve O si ambas cadenas son iguales, un valor negativo o
positivo en función de si la cadena está antes o después alfabéticamente de la pasada
como parámetro.
■ ContainsQ. Devuelve un valor booleano que indica si la cadena pasada como
parámetro forma parte del string que invoca al método.
■ IndexOfQ. Este método devuelve el índice de la primera aparición de un carácter o
cadena pasado como parámetro en el string que hace la llamada. En caso de que no se
encuentre el carácter o la cadena el método devolverá -1.
■ Inserto. Inserta una cadena de caracteres pasada como parámetro en el string que
invoca al método.
■ TrimO. Quita todas las apariciones de un carácter concreto en el inicio y fin de la
cadena de caracteres.
■ RepIaceQ. Sustituye un carácter o string por otro dado.
■ RemoveO. Elimina un número de caracteres de una instancia concreta.
■ SpIitQ. Permite separar una cadena de caracteres en partes, cada una de ellas está
delimitada por un elemento que será especificado en la función. Devuelve un array de
string.
■ ToLowerQ. Devuelve una copia del string que realiza la llamada en minúsculas.
■ ToUpperQ. Devuelve una copia del string que realiza la llamada en mayúsculas.
/*Función Burbuja
Realiza la ordenación mediante el método de ordenación burbuja ya visto.
Parámetros de entrada: Array de tipo string y número de elementos de esta.
Salida: Ninguna.
*/
Burbuja(string[] tabla, int NumeroElementos)
bool ordenado = false;
int pasada = O, j;
string aux;
while (pasada < NumeroElementos - 1 && '(ordenado))
{
ordenado = true;
for (j =0; j < NumeroElementos - pasada - 1, j++)
{
if (tabla[j].CompareTo(tabla[j + 1])>0)
{
ordenado = false;
aux = tabla[j];
tabla[j] = tabla[j + 1];
tabla[j + 1] = aux;
Capítulo 5. Tipos de datos compuestos
/*Función mostrar
Muestra los array introducidos por parámetros
Parámetros de entrada: Array de tipo string.
Salida: ninguna.
*/
static void mostrar(string[] p)
{
for (int i = 0; i < p.Length; i++)
{
Consolé.Write("{O)\t",p[i]);
}
Consolé.Write("\n");
En el siguiente ejemplo hacemos uso de la función Spiit. Supongamos que debemos realizar
una aplicación que dada una dirección IP muestre: dirección de red, máscara, puerta de enlace y
dirección de broadcast.
static void Main(string[] args)
{
string direccionlP;
char[] separador = { );
string[] numeroslp;
Consolé.WriteLine ("Introduce la dirección IP");
direccionIP=Console.ReadLine();
numeroslp = direccionlP.Split(separador);
if (IpValida(numeroslp))
{
Consolé.WriteLine("Para la dirección IP dada:{0)", direccionlP);
Consolé.WriteLine("Dirección de red:{0)", direccionRed(numeroslp));
Consolé.WriteLine("Máscara de red:{0)", mascara(numeroslp));
Consolé.WriteLine("Puerta de enlace:(0)", gateway(numeroslp));
Consolé.WriteLine("Dirección de Broacast:{O)", broadcast(numeroslp));
)
else
{
Consolé.WriteLine("La dirección introducida no es una IPv4 válida");
)
Consolé.ReadLine();
Utilizamos la función Split para separar cada número de la dirección IP. Esta función propia
del tipo string necesita que se pase como parámetro un array de tipo carácter en el que se
incluyan aquellos caracteres delimitadores que permitan separar el string. En nuestro código este
array se declara y crea como sigue:
r~— — —I
/*FUNCIÓN IpValida*/
static bool IpValida(string[] parteslp)
bool valida = true;
int i = 0;
if (parteslp.Length != 4)
valida = false;
else
{
while (i < parteslp.Length && valida)
int parte = int.Parse(parteslp[i])'
if (parte < 1 || parte > 254)
{
valida = false;
return valida;
Capítulos. Tipos de datos compuestos 215
/*FUNCIÓN mascara*/
staliic string masca ra (string []parteslp)
/*FUNCIÓN direccionRed*/
static string direccionRed(string []parteslp)
{
string mascaraRed = mascara (parteslp);
if (mascaraRed.CompareTo("255.0.0.O") == 0)
{
mascaraRed= parteslp[0] + ".0.0.0";
}
else if(mascaraRed .CompareTo("255.255.0.0")==0){
mascaraRed = parteslp[0] + "." + parteslp[l] + ".0.0";
}
else if (mascaraRed.CompareTo("255.255.255.O") == 0)
{
mascaraRed = parteslp[0] + "." + parteslp[l] +
"." + parteslp[2] + ".O";
}
return mascaraRed;
/*FUNCION gateway*/
static string gateway(string[] parteslp)
{
string dirGateWay = "E.E.E.E";
int primerNumero = int.Parse(parteslp[ O ]);
if (primerNumero >= 1 && primerNumero <= 127)
{
dirGateWay = parteslp[0] + ".0.0.1";
}
else if (primerNumero >= 128 && primerNumero <= 191)
{
dirGateWay = parteslp[0] + "." + parteslp[l] + ".0.1";
}
else if (primerNumero >= 192 && primerNumero <= 223)
í
dirGateWay = parteslp[0] + "." + parteslp[1] +
+ parteslp[2] + ".1";
}
return dirGateWay;
/^FUNCIÓN broadcast*/
static string broadcast(string[] parteslp)
{
string dirBroadcast="E.E.E.E";
int primerNumero=int.Parse(parteslp[0]);
if (primerNumero >= 1 && primerNumero <= 127)
{
dirBroadcast = parteslp[0] + ".255.255.255";
}
else if (primerNumero >= 128 && primerNumero <= 191)
{
dirBroadcast = parteslp[0] + "."+parteslp[1]+".255.255";
}
else if (primerNumero >= 192 && primerNumero <= 223)
{
dirBroadcast = parteslp[0] + + parteslp[l] +
+ parteslp[2]+ ".255";
}
return dirBroadcast;
I string cadena="Hola"+nombre+apell+apel2;
i string dirRed=numl+"."+num2+"."+num3+".O";
Capítulos. Tipos de datos compuestos 217
Debemos declarar y crear (resei^var espacio en memoria) el objeto. Así, es necesario usar la
palabra reservada new.
ACTIVIDAD 5.15
Realiza un pequeño programa que pida al usuario 5 nombres. Estos deben ser introducidos
siguiendo el orden: nombre apellido 1 y apellido2, y modifique el formato para que se visualicen
de la forma: apellido 1 apellido2, nombre. Usa el objeto StringBuilder.
5.4. ESTRUCTURAS
Una estructura es un tipo de datos compuesto tal que agmpa variables de diferentes tipos. Por
ejemplo, imaginemos que queremos desarrollar un programa que debe almacenar los datos de
nuestros alumnos junto a sus notas. Hasta ahora podemos realizar la aplicación haciendo uso de
arrays de diferentes tipos de datos, tal que cada vez que queramos insertar, eliminar o modificar
un alumno debemos averiguar el índice de este y proceder a la operación en todas las tablas. Esta
es ima forma se subsanar el problema pero no es la más acertada, ya que cada array es
independiente del resto, en algún momento podemos cometer algún error de programación y
podemos enlazar datos que no tiene nada que ver unos con otros.
Podemos decir que una estructura es un tipo de datos creado por el usuario que no llega a
tener la potencia de una clase pero que permite mantener agrupada información relacionada con
un elemento concreto de nuestro programa.
Juan Mana
9,8 10,0
i tipojdato nombre; i
I estructura nombre; i
I alumno clase; //Siendo alumno una estructura ;
1 coche arosa; //Siendo coche una estructura j
r — 1
public int X;
piiblic int Y;
);
static void Main(string[ args)
punto coordenada;
coordenada.X=1O;
coordenada.Y=5;
X e Y son campos de la estnictura. Se usa el modificador public para que podamos acceder a
ellos desde cualquier otra función (recordamos las características de visibilidad de los objetos en
C#).
A la hora de usar la estructura declaramos una variable de tipo punto: punto coordenada; El
símbolo punto (.) permite acceder a los elementos públicos creados en nuestro tipo de datos. Otro
modo de desarrollar esta estructura es:
publxc struct punt
this.X = x;
this.Y =
Normalmente las variables que se incluyen en una estructura o una clase no se declaran
públicas, es decir, no se pennite el acceso directo a ellas a través del operador punto, se usan
métodos o funciones que penniten su visualización o modificación.
Así, en nuestra nueva estructura punto declaramos una variable llamadaX y otra Y de tipo
entero a la que podremos acceder mediante los métodos set y get. Un método que empieza por
set se refiere a la modificación de un campo de la estructura, mientras que get conseguirá
exteriorizar o visualizar el valor de un campo. Ya que un método set modifica un campo debe
recibir como parámetro el nuevo valor. El método get obtiene un valor con lo que no recibe
parámetros pero sí devuelve el valor de un campo concreto. Todos los métodos son public para
que puedan ser usados.
public int getX() /*La variable se llama X, nuestro método se denomina getX, \
al ser un método get devuelve el valor de la variable X, 1
de ahi public int.*/ ;
Las estructuras son tipos de datos valor. Podemos crear arrays d^e tipo estructura.
Para entender definitivamente este tipo de datos, vamos a desarrollar un pequeño programa
que gestiona una agenda de direcciones. La estructura del tipo de dato a usar es la siguiente:
■ Apellido 1.
■ Apellido 2.
■ Dirección.
■ Teléfono fijo.
■ Teléfono móvil.
Eliminar un contacto.
Capítulo 5. Tipos de datos compuestos 221
/*Función insertar
Inserta un contacto ya creado con anterioridad en la agenda.
Parámetros de entrada: Array de contactos (agenda), total de contactos
almacenados y el contacto a insertar.
Salida: Ninguna.*/
static void insertar(contacto[]ag,ref int totalContactos, contacto nuevo)
ag[totalContactos] nuevo;
totalContactos++;
/*Función modificar
Se encarga de modificar un contacto insertado en una posición concreta del
array. Se visualiza cada campo del contacto, el usuario debe escribir '*s' o
'n' según quiera modificar o no el dato. Si escoge ^s' debe escribir el nuevo
valor.
Parámetros de entrada: la agenda y la posición del contacto que se quiere
modificar.
Salida: Ninguna.*/
static void modificar(contacto[] ag, int posContacto)
{
char mod=' ';
Consolé.WriteLine("¿Qué desea modificar? Iremos mostrando cada dato,
si quiere modificar esciba s, para no modificar n");
Consolé.WriteLine(ag[posContacto].nombre);
mod = char.Parse(Consolé.ReadLineO);
if(mod=='s')
{
ag[posContacto].nombre=Console.ReadLine();
Consolé.WriteLine(ag[posContacto].apellidol);
mod = char.Parse(Consolé.ReadLineO);
if(mod=='s')
{
ag[posContacto].apellidol=Console.ReadLine();
}
Consolé.WriteLine(ag[posContacto].apellido2);
mod = char.Parse(Consolé.ReadLineO);
if(mod=='s')
{
ag[posContacto].apellido2=Console.ReadLine();
}
Consolé.WriteLine(ag[posContacto].dirección);
mod = char.Parse(Consolé.ReadLine O);
if(mod=='s')
{
ag[posContacto].direccion=Console.ReadLine();
}
Consolé.WriteLine(ag[posContacto].telFijo);
mod = char.Parse(Consolé.ReadLineO);
if(mod=='s')
{
ag[posContacto].telFijo=Console.ReadLine();
Consolé.WriteLine(ag[posContacto].telMovil);
mod = char.Parse(Consolé.ReadLine O);
if(mod=='s')
{
ag[posContacto].telMovil=Console.ReadLine();
}
Consolé.WriteLine(ag[posContacto].mail);
mod = char.Parse(Consolé.ReadLine O);
if(mod=='s')
(
^ ag[posContacto].mail=Console.ReadLine();
/*Función eliminar
Elimina un contacto de la agenda.
Parámetros de entrada: agenda, número total de contactos de la agenda y
posición del elemento a eliminar.
Salida: Ninguna.*/
static void eliminar(contacto[] ag, ref int totalContactos, int posEliminar)
for (int i - posEliminar; i < totalContactos 1; i++)
/*Funci6n buscarApellidos
Esta function se utilize en las opciones de eliminar y modificar ya que antes
de realizar estas operaciones se debe localizer el element. Busca un contacto
cuyos apellidos coincidan con los dados.
Parámetros de entrada: agenda, número total de contactos de la agenda y los
apellidos a buscar.
Salida: Posición del elemento buscado o -1 si no encuentra coincidencias.*/
^static int buscarApellidos(contacto[] ag, int totalContactos,string
Capítulo 5. Tipos de datos compuestos 223
string ap2)
{
int buscado = -1;
int i = O;
while (i < totalContactos && buscado == -1)
{
if (ag [ i].apellidol.CompareTo(api) == O
&& ag[i].apellido2.CompareTo(ap2) == 0)
{
buscado = i;
return buscado;
/*Función ordenarApellido
Ordena la agenda. El criterio de ordenación es el primer apellido.
Parámetros de entrada: Array de contactos, primera posición o posición desde
la que empezar a buscar y última posición o posición donde finalizar la
búsqueda.Se usa el algoritmo Quicksort visto para la ordenación.
Salida: Ninguna.*/
static void ordenarApellido(contacto[] ag, int primero, int ultimo)
{
int i, j, central;
contacto tmp;
string pivote;
central = (primero + ultimo) / 2;
pivote = ag[central].apellidol;
i = primero;
j = ultimo;
do
while (ag[i].apellidol.CompareTo(pivote)<0)
while (ag[j].apellidol.CompareTo(pivote)>0)
{
if (i <= j)
{
tmp = ag[i];
ag[i] = ag[j];
ag[j] = tmp;
i++;
ordenarApellido(ag, i, ultimo);
/*Función menú
Muestra las opciones del programa y devuelve la elección del usuario.
Parámetros de entrada: Ninguno.
Salida: Opción seleccionada por el usuario.*/
static int menú()
{
int opcion;
Consola.WriteLine("1. Insertar contacto.");
Consolé.WriteLine("2. Modificar contacto.");
Consolé.WriteLine("3. Eliminar contacto.");
Consolé.WriteLine("4. Buscar contactos por apellidos.");
Consolé.WriteLine("5. Ordenar contactos por apellido.");
Consolé.WriteLine("6. Mostrar todos los contactos.");
Consolé.WriteLine("7. Salir");
Consolé.WriteLine("Elige opción");
opcion = int.Parse(Consolé.ReadLineO);
return opcion;
}
/*Función mostrarAgenda
Muestra la agenda.
Parámetros de entrada: La agenda y el total de contactos almacenados.
Salida: Ninguna.
*/
static void mostrarAgenda(contacto[] ag, int totalConstactos)
{
for (int i = 0; i < totalConstactos; i++)
{
Consolé.WriteLine("{0} {1},{2}", ag[i].apellidol, ag[i].apellido2,
ag[i].nombre);
Consolé.WriteLine("{O}", ag[i].dirección);
Console.WriteLine("{O)-{l}", ag[i].telFijo, ag[i].telMovil);
Consolé.WriteLine("{O}", ag[i].mail);
Consolé.WriteLine(" ");
}
}
La función principal, Main, incorpora como en otras ocasiones una sentencia repetitiva
(do...while) y una sentencia alternativa múltiple (switch) para que el usuario escoja la operación
a realizar.
ACTIVIDAD 5.16
Crea una función Main que use todas estas funciones de la agenda y muestre las opciones que
se describen en menu().
5.5. ENUMERACIONES
Una enumeración, tipo enumerado o enum es un tipo especial de estructura compuesta por un
conjunto de constantes. Cada elemento de una enumeración estará asociado a un valor de un tipo
de datos concreto excepto char, siendo el tipo de datos por defecto int. En enumeraciones enteras,
el primer elemento de la numeración tiene asignado por defecto el valor 0.
i escogerTalla(Tallas.M) i
I cambiarTalla(Tallas.L) \
En las funciones de ejemplo, cuando en escogerTalla introducimos como parámetro Talla.M
este equivale a 2, es decir, invocar al método de la forma escogerTalla(2) surtiría el mismo
efecto que escogerTalla(Tana.M), sin embargo el segundo de los casos resulta más sencillo y
recordaremos mejor la Talla.M que el valor 2 para esta talla.
Una enumeración:
Hemos creado una enumeración taí que 1 Hemos creado una enumeración tal que
XS=0, S=l, M=5,L=6 y XL=7. XS=1, S=2, M=3,L=4 y XL=0.
A la hora de asignar valores a los identiflcadores de la enumeración podemos usar datos
concretos o expresiones cuyos resultados se encuentren en el rango de valores pennitido por el
tipo de dato asociado a la enumeración.
envun Tallas{ ; Creamos la enumeración llamada Tallas donde S equivale a 1 y los
s=l,M,L, ; valores asociados a XS y XL se obtienen tras realizar las operaciones S-
I 1 y L+J
VT.=T J-1 . J ^ *
5.5.2. USO DE ENUMERACIONES EN C#
A la hora de utilizar los valores de una enumeración debemos especificar su nombre seguido
del operador punto.
I ,
i nombre_enumeracion.nombreJiteras ¡
En nuestra enumeración de ejemplo, a la hora de usar alguna de las tallas escribimos:
Tallas.XS
Tallas.XL
Ya que los elementos de una enumeración están conectados con valores de tipo numérico, ya
sea entero, byte, etc., podemos asignar a variables de estos tipos los literales de una enumeración.
Así podemos encontrar código fuente como sigue:
1 Creamos una enumeración donde
enum Tallas{ I referenciamos las tallas y una estructura que
xs,s,M,L,XL ; almacena información sobre una persona.
j
}
Slic '
i continuación, la variable talla de la
I estructura persona es asignada a una de las
public static void Main(string args[]){ ! tallas válidas de la enumeración:
persona yo; I yo.taIla=Tallas.M; Eso sí, debemos realizar
^ yo.talla=(int)Tallas.M; ! conversión a entero (en este caso) en la
; asignación.
Dado que internamente íos elementos de una enumeración referencian tipos de datos
numéricos, podremos usar los operadores relaciónales, aritméticos, etc., con ellos.
enum CoidigoDeError
{
Opcionincorrecta,
DivisionPorCero,
NumeroGrande
Consolé.WriteLine("MENU");
Consolé.WriteLineC'l. Suma.");
Consolé.WriteLine("2. Resta.");
Consolé.WriteLine("3. Multiplicación.");
Consolé.WriteLine("4. División.");
Console.WriteLine("5. Salir.");
Consolé.WriteLine("Escoge una opción.");
op = int.Parse(Consolé.ReadLine O);
switch (op)
{
case 1: Consolé.WriteLine("La suma es:{O}",numl+num2);
break;
case 2: Consolé.WriteLine("La resta es:{0}", numl - num2);
break;
case 3: Consolé.WriteLine("La multiplicación es:{0}"
, numl * num2);
break;
case 4:
if (num2 == 0)
Consolé.WriteLine(textoError((int)
CodigoDeError.DivisionPorCero));
}
else
{
Consolé.WriteLine("La división es:{0}"
, numl / num2);
}
break;
case 5: Consolé.WriteLine("Gracias por confiar
en nuestra empresa");
break;
default: Consolé.WriteLine(textoError((int)
CodigoDeError.Opcionincorrecta));
break;
}
Consolé.ReadLine();
} while (op != 5);
COMPRUEBA TU APRENDIZAJE
1. ¿Qué es un array? ¿A qué nos referimos cuando hablamos de un array de ima
dimensión?
2. ¿Cuál es la sintaxis básica de creación e inicialización de un array? ¿Qué hace la
palabra reservada new?
3. ¿Cómo accedemos a un array bidimensional?
4. ¿Qué estamos haciendo en la siguiente línea de código fuente: int [][]m=new [][]{new
int[2],new int[12]};?
5. ¿A la hora de pasar como parámetro un array, este es pasado por valor o por
referencia? ¿Y una estructura? ¿Y un elemento concreto del array?
6. ¿Cuál es la sintaxis de un bucle foreach? ¿Cuál es su funcionamiento?
7. ¿En qué consiste una búsqueda binaria? ¿Cómo realiza la ordenación de un array el
algoritmo quicksort?
8. ¿Para qué usamos la propiedad Rank? ¿Y el método getlength()?
9. ¿Podemos modificar un carácter de un tipo string? ¿Para qué usamos el método
CompareToQ?
10. ¿Qué es una estructura? ¿Para qué podemos usarlas? ¿Y una enumeración? Escribe la
sintaxis de creación de una estructura y un tipo enumerado.
ACTIVIDADES DE AMPLIACION
1. Desarrolla una pequeña aplicación que use un array bidimensional como pantalla,
cada casilla es un pixel que por defecto se caracteriza por el carácter *.
* * * * * * * * *
* * * * * * * * * *
3- Rectángulo.
4- Triángulo.
5- Círculo.
6- Mostrar pantalla.
Veamos cómo debe funcionar. Si escogemos 1 pediremos al usuario que inserte un
carácter que será aquel que usaremos para dibujar (el carácter de dibujo por defecto es
@). Si escogemos cualquiera de las opciones restantes pediremos al usuario la posición
dónde empezar a dibujar (en el caso del rectángulo y el cuadrado es la posición de la
esquina superior izquierda, el triángulo el vértice superior y el círculo el centro).
Capítulo 5. Tipos de datos compuestos
además de las medidas de los lados o radio. Si seleccionamos 2 y posición (1,1) lado 3
y el carácter de dibujo es + debe modificarse nuestra matriz pantalla del siguiente
modo;
( I I 1 \ I I i l I i
5. Amplía el programa de la Actividad 4 de fonna que tras ordenar muestre los números
en pantalla separados por guiones.
6. Mediante el uso de arrays pide al usuario un número y muestra por pantalla si este es
palíndromo o no. Debes pedir el número completo, no digito a digito.
7. Realiza un programa que pida al usuario la introducción de un carácter hasta que este
pulse el carácter @. El programa debe mostrar las veces que se ha escrito cada
carácter. Recordad que los caracteres tienen asociado un número o código ASCII que
comienza en cero. Utilizad arrays para hacer el ejercicio.
8. Realiza un programa que pida caracteres al usuario. Finalizará la introducción de
caracteres cuando el usuario pulse @ o haya escrito 20 caracteres. A continuación se
deben mostrar los elementos almacenados en mayúsculas.
9. Realiza un programa que encripte una cadena de caracteres (solo podemos usar
caracteres en minúsculas o números). La encriptación consiste en:
■ Dada una cadena de caracteres, en la cadena encriptada cada carácter será
igual a él mismo más el carácter que se encuentra a continuación. Si nos
encontramos en el último valor le sumaremos 4.
■ Una vez realizada la operación anterior sumaremos 3 a cada carácter
obteniendo finalmente la cadena encriptada definitiva.
10. Realiza un nuevo programa de encriptación tal que se pida al usuario la cadena de
caí acteres a encriptar y la clave de encriptación que también será una cadena (ambas
cadenas compuestas por caracteres en minúsculas o números).
■ Localiza el carácter mayor de la clave de encriptación.
■ Suma el carácter obtenido en el punto anterior a cada carácter de la cadena.
■ Agrega la clave de encríptación a la cadena de fonna que cada carácter de la
clave se posicione cada dos caracteres de la cadena principal. El exceso de
caracteres se colocará al final.
Ejemplo:
Cadena a encriptar: coco.
Clave de encríptación: game.
Carácter mayor de game -> m
coco + m = oUUU.
15. Crea una matriz de dos dimensiones (4x9) tal que se inicialice con números enteros
aleatorios entre O y 100. Muestra por pantalla el mayor, el menor, la media de todos y
la media aritmética por fila.
16. Crea un programa que genere una matriz unitaria. Una matriz unitaria tiene N filas y
N columnas tal que todos los elementos están a O a excepción de la diagonal que está
inicializada a 1.
17. Realiza un programa que pida una matriz al usuario (array bidimensional) y diga al
usuario si es simétrica.
18. Crea un programa que permita gestionar los alumnos de una asignatura. Cada alumno
está definido mediante una estructura con información relativa a su nombre y
apellidos y su nota media. Estos alumnos están almacenados en un array. Calcula la
Capitulo 5. Tipos de datos compuestos
media aritmética de la clase, e indica cuántos alumnos están por encima y por debajo
de la nota media calculada.
19. Desarrolla un programa que gestione los empleados de una empresa, de cada
trabajador se debe almacenar: nombre, edad, cargo (puesto de trabajo) y sexo. Realiza
las siguientes operaciones:
■ Insertar, eliminar y modificar un empleado.
■ Mostrar el número de hombre y mujeres que hay en la empresa.
■ Mostrar la edad media de los empleados. Además, calcular la edad media de
hombre y mujeres por separado.
■ Mostrar el nombre del empleado más joven y del más viejo.
20. Desarrolla un programa tal que dado un DNI averigua la letra que le corresponde para
formar el NIF y muestre este por pantalla. Tendremos en cuenta la siguiente
infonnaeión:
Debemos obtener un número entre O y 23, ambos inclusive, para obtener un valor en
la tabla equivalente de caracteres que vemos a continuación. El numero de 1 a 20 se
calcula dividiendo el DNI entre 23 y trabajar solo con la parte entera. Multiplicamos a
la parte entera por 23 y restamos el DNI original con el DNI calculado.
0='T' 7='F' I4='Z' 21='K'
1='R' 8='P' 15='S' 23='E'
2='W' 9='D' 16='
3='A' IO='X' I7='V'
4='G' I1='B' 18='H'
5='M' 12='N' 19='L'
6='Y' 13='J' 20='C'
CAPITULO 6
CONTENIDOS OBJETIVOS
Codigo fuente
Función 2
N Función
2
Función 1
1
Programa principal
Función 1.
Función 2.
Programa principal:
Función 2
Figura 6.2. Tipos abstractos de datos. A la izquierda el desarrollo de un TAD con valores y operaciones a
usar sobre las variables. A la derecha uso del TAD en un programa. Se declara el tipo y posteriormente
usamos este.
236 Programación
Objeto
Atributos
Métodos
Mensaje
Hereda
Objeto Objeto
Atributos Atributos
■ Para finalizar, las operaciones' que podemos realizar con números complejos son:
—> Crear un número complejo a partir de dos números reales dados.
—> Sumar, restar y multiplicar números complejos.
—> Extraer la parte real de un número complejo.
Extraer la parte imaginaria de un número complejo.
Así, la especificación fonnal sería:
especificación complejos :
usa: reales '• i
tipo: complejo :
operaciones: i
. complejo: real X real-> complejo i
suma: complejo x complejo -> complejo . ,j
resta: complejo X complejo-> complejo : i
multiplicación: complejo X complejo-> complejo j
parteEntera: complejo -> real '\
partelmaginaria: complejo -> real I
variables: :
x,y,z,p: reales i
ecuaciones: •
suma(complejo(x,y); complejo(z,p)) = complejo(x + z, y + p) i
resta(complejo(x,y); complejo(z,p)) = complejo(x - z, y - p) ;
multiplicación(complejo(x,y); complejo(z,p)) = complejo ((x*z)-(y*p), i
(y*z)+(x*p)) ;
parteReal(complejo(a, b)) = a i
parteImaginaria(complejo(a,b)) = b i
fin-especificación . .. i
La especificación denota que usaremos números reales para definir cada parte de un número
complejo (real e imaginaria), se observa en el apartado usa. Indica para cada operación su
nombre, parámetros de entrada y salida, por ejemplo: suma: complejo x complejo -> complejo
denota que suma es el nombre de la operación, se usarán dos números complejos (complejo x
complejo) y la salida de la función será otro número complejo (-> complejo). Además, en el
apartado ecuaciones se detalla en qué consistirá cada operación antes definida.
Este es el TAD de números complejos, ahora podrá ser implementado en cualquier lenguaje
de programación y cada método podrá realizarse de varias formas, sin embargo, lo
verdaderamente importante es la especificación, no la posterior implementación.
Podrían incluirse algunas más pero no vamos a profundizar en exceso en este tema.
Un TAD simplemente reconoce los valores y operaciones que se pueden realizar, cuando
hablamos de objetos, en esencia es básicamente un tipo abstracto de datos al que se agrega
términos como herencia, polimorfismo, paso de mensaje, etc.
ACTIVIDAD 6.1
ACTIVIDAD 6.2
6.2.1. ABSTRACCIÓN
La abstracción permitirá recolectar y representar las características esenciales de un objeto,
dejando atrás aquellas que no tienen tanta importancia. Además, se centra en el objeto tal y como
lo conocemos en la vida real, de fomia que nos centramos en lo que es capaz de hacer pero no en
cómo lo hace. Básicamente, definiríamos la abstracción como la fonna de describir una entidad
del mundo real sin importar la complejidad que está presente y el poder utilizar esta en cualquier
aplicación.
estructura coche{
colora- Función repararChapa (){
ruedas;
}
Función Principal {
coche A, B.
cambiarAce¡te(A)
cambiarAce¡te(B)
cambiarCo!or(B)
Figura 6.4. Ejemplo de codificación para un taller de vehículos. A la izquierda un modelo estructurado a
la derecha un modelo orientado a objetos.
6.2.2. ENCAPSULAMIENTO
I Pfogram.cs
Examinar: Mi solución
Miembro de Svstom.Consolé
Resumen:
Escribe el valor de cadena especificado, seguido del terminador de linea actual, en el
Tlujo de salida estándar.
Parámetros:
valué: Valor que se va a escribir.
Excepciones:
6.2.3. MODULARIDAD
Esta propiedad se refiere a la forma en la que los elementos en programación orientada a
objetos se encuentran organizados en módulos, facilitando asi la encapsulación y abstracción de
la información.
La medularidad permite dividir una aplicación en partes. Estas partes deben ser tan
independientes como sea posible del resto así como de la aplicación principal. A cada parte se la
denomina módulo. Al crear módulos independientes de la propia aplicación, estamos
contribuyendo a la creación de código reutilizable, tal que si hemos desarrollado un módulo para
un programa concreto, esta pueda usarse en cualquier otro. En nuestro ejemplo de aplicación de
taller de vehículos, si desarrollamos un módulo o clase llamado coche, si es independiente puede
utilizarse en este programa como en un concesionario.
Capitulo 6. Programación orientada a objetos 241
Programa 1 Programa 2
6.2.4. JERARQUÍA
Mediante la jerarquía se ordenan las abstracciones u objetos de forma que se establecen
relaciones de algún tipo entre ellas. Podemos hablar de herencia entre clases tal que los
elementos de una clase son heredados por otra o incluso sus métodos pueden ser sobrecargados.
Supongamos en nuestra aplicación para el taller de vehículos que debemos además de
mantener información sobre los eoches, motocicletas, etc., que se reparan, controlar datos
relacionados con los empleados, personal en general de la empresa. En el taller cada empleado o
grupo de empleados está asociado a un departamento, y todos tienen un sueldo y un rango. Así,
podríamos desaiTollar una abstracción denominada Empleados donde almacenemos datos
relacionados con todos los empleados independientemente de su función y un objeto por cada
tipo de empleado, teniendo en cuenta para definir el tipo el departamento en el que se ubica.
Finalmente, podríamos desarrollar una jerarquía de clases como la que se observa en la Figura
6.7.
EMPLEADOS
■ Nombre y apellidos.
■ Dirección.
■ Teléfono.
■ Sueldo base
MECANICO DIRECTOR
6.2.5. POLIMORFISMO
El término polimorfismo es una palabra griega que significa muchas formas. La palabra es
ideal para definir esta característica, ya que en programación orientada a objetos podemos tener
métodos con igual nombre pero con implementaciones diversas tal que dependiendo del objeto
que se use, este método o función realizará una u otra operación.
El polimorfismo se usa bastante junto a la herencia, tal que cuando una clase deriva de otra
hereda sus características y operaciones. En la clase que hereda se puede redefinir cualquier
método heredado, de forma que en función de la referencia a objetos que usemos en cada
momento se estará ejecutando un método u otro.
"Un mismo mensaje enviado a objetos diferentes dará como respuesta salidas diferentes", es
decir, si tenemos varios objetos con métodos similares, según se referencie uno u otro objeto el
resultado final será diferente. Cuando tenemos varios objetos que derivan o heredan de un objeto
base se aplica extensamente esta definición al usar arrays del objeto base. Véase la Figura 6.8.
EMPLEADOS
■Nombre y apellidos.
■ Dirección.
■ Teléfono.
■ Sueldo base
MECANICO DIRECTOR
El método Calcular sueldo que se ejecutará en cada caso depende de la referencia a objeto
■ De cada elemento debemos conocer cuáles son sus características o cuáles son las
características que lo representan.
■ De cada elemento debemos conocer las operaciones a realizar ya que cada conjunto
de datos permitirá la realización de un conjunto de operaciones.
■ Finalmente, desarrollaremos un enlomo donde usaremos los elementos configurados.
Por ejemplo, a la hora de desarrollar la aplicación para nuestro taller de reparación de
vehículos, podemos resolver las siguientes cuestiones para determinar los elementos que vamos a
incluir:
Ahora bien, si en nuestro taller hace entrada un Seat Arosa de tres puertas, las características
antes mencionadas adoptan ciertos valores:
■ Ruedas tipo X.4 más la de repuesto.
■ Matrícula H1467W.
■ 3 puertas.
■ Seat. Modelo Arosa.
■ Etc.
Atributos
Objeto Ceed
color, marca,
modelo, matrícula,
blanco, kia, ceed,
etc.
1667cvf, etc. ceed.cambiar color
II' Métodos.
cambiar color,
cambiar aceite, poner
a punto, etc.
. Objeto fiesta
negro,ford,fiesta,
fiesta.cambiar aceite
2374cmg, etc.
■ class. Palabra reservada del lenguaje que indica el inicio de la definición de una clase.
■ nombre. Nombre con el que será conocida la clase.
■ atributos. Características que definen la clase.
■ métodos. Funciones u operaciones sobre los atributos permitidas por la clase.
Los miembros de una clase: atributos y métodos, puede declararse como públicos (public) o
privados (prívate). Estos modificadores de visibilidad detenninarán el acceso a un miembro de
la clase.
■ Miembros interna!. Definimos un miembro intemal cuando queremos que este sea
accesible solo dentro del fichero donde se ha creado. Por ejemplo, si creamos un
atributo intemal, solo podrá ser usado en el mismo fichero o ensamblado. Si
tuviéramos una instancia de la clase en otro fichero, no podríamos modificar o usar
este atributo. En cierto modo son miembros públicos para su fichero pero privados
para el resto.
■ Miembros protected intemal. Son miembros accesibles desde la clase que los
contiene a sus derivadas dentro del ensamblado al que pertenecen.
6.4.1. ATRIBUTOS EN C#
Un atributo recoge una característica concreta de un objeto y no es más que una variable que
se ajusta a ella, definida mediante un tipo de datos y un nombre.
I - -I
I tipo_dato_atributo nombre_atributo; ;
■ tipo_dato3tributó.""Éf tipó de'd^^^ ser cualquiera de los que ya hemos
estudiado. Podemos usar tipos de datos básicos como int, double o cbar, tipos de
datos complejos: estructuras o arrays y otros objetos. A la hora de usar como tipo
de dato un objeto, podemos utilizar los objetos predefinidos e incluidos en C# o bien
objetos creados por el propio usuario.
■ nombre_atributo. Es un identificador válido. Este nombre debe ser representativo y
orientativo del valor o tipo de información que almacenará.
I class empleado { |
I string nombre; //Atributo que almacenará el nombre del empleado 1
I string apellidol; I
; string apellido2; i
I string NIF; //Atributo que almacenará el NIF del empleado I
6.4.2. MÉTODOS EN C#
Un método se puede definir como función o procedimiento de una clase. Bloque de código al
que se le asocia un nombre igualmente representativo y que puede procesar parámetros y
Capítulo 6. Programación orientada a objetos 247
devolver valores del procesamiento dado. Desde los métodos podremos acceder libremente a los
atributos de la clase, cambiando estos o usando su contenido. La sintaxis básica de im método es:
tipojievuelto nombre_niétodo(parámetros){ i
sentencias; I
} \
■ tipo_devueIto. Tipo de dato de la variable que será devuelta por el método, en caso
de que se use la instrucción return en algún momento en el código. Si el método no
devuelve ningún valor usaremos la palabra reservada void como cuando codificamos
funciones en programación estructurada.
■ nombre_método. Nombre que daremos al método. Cuando tengamos que ejecutar tm
conjunto de instrucciones concretas, mandaremos im mensaje al objeto usando este
nombre.
■ parámetros. Pares (tipo, nombre) que reflejan variables que serán pasadas al método
para que puedan ser usadas en sus sentencias. Recordamos que si existen variables
extemas, necesitaremos acceder a ellas de algún modo.
■ sentencias. Conjunto de instmcciones, operaciones, que debe realizar el método.
NOTA: Recomendamos usar un fichero .es por cada nueva clase que vayamos a
incluir en nuestro software. Todas ellas bajo el mismo espacio de nombres.
class empleado {
string nombre; //Atributo que almacenará el nombre del empleado
string apellidol;
string apellido2;
string NIF; //Atributo que almacenará el NIF del empleado
double sueldoBase;
6.4.3. INSTANCIAS EN C#
Una vez que se ha declarado una clase con sus atributos y métodos, el siguiente paso es la
instanciación de esta, es decir, uso de la clase, creación de un objeto de clase.
La instanciación consiste en la creación de una variable de una clase, un objeto. A la hora de
crear un objeto, la sentencia que usaremos estará compuesta de definición y creación.
INTERFAZ PRINCIPAL
EMPLEADOl
Juan, Orellana,
Moro, 29876543L,
1200
EMPLEADO empleado EMPLEADOl
CalculaSueldo Jempleado EMPLEAD02
Nombre, Apellidol,
Apell¡do2, NIF, Console.WriteLIneC'Sueldo;",
sueldoBase
CalculaSueldo
a EMPLEAD02
EMPLEADQl.CalculaSueldo(10,12);
Console.WriteLine("Sueldo:",
Isabel, Jiménez, EMPLEAD01.CalculaSueldo(0,0);
Pérez, 29871243L,
1400
CalculaSueldo
Figura 6.11. Clase empleado. Instancias, programa principal y uso de los métodos.
En la definición indicamos la clase que vamos a instanciar, mientras que en la creación se
produce la reserva real de memoria para la variable.
I
6.4.4. CONSTRUCTORES EN C#
Un constructor es una función miembro de una clase que se ejecuta de forma automática
cuando se crea una instancia de esta. El constmctor de una clase se diferencia del resto porque
debe llamarse igual que la clase (respetando mayúsculas y minúsculas) y nunca se especifica en
su definición un tipo de datos devuelto, ni siquiera void.
El constructor admite parámetros, siendo un método que puede sobrecargarse, es decir,
podemos tener varios contructores con diferente número o tipo de parámetros.
Los constructores tienen como objetivo principal la inicialización de las variables o atributos
de la clase.
Cuando no definimos un constructor en una clase los atributos tomarán por defecto valores
asociados a sus tipos de datos. Por ejemplo, si tenemos un atributo de tipo entero, se le asignará
por defecto el valor O, en caso de un atr ibuto de una clase, el valor por defecto será nuil.
NOTA: La palabra nuil es un literal que representa una referencia vacía, es decir, una
variable referencia que no apunta a ningún objeto, ningún espacio en memoria. Cuando
trabajamos con tipos de datos int el valor por defecto es O, es un tipo de dato valor; en
cambio, los arrays u objetos son tipos de dato referencia tal que al inicializarse deben
apuntar a una referencia de memoria donde se almacena un objeto, si no asignamos ninguna
referencia la inicialización por defecto será a nuil.
Podremos acceder a los miembros de una clase en función de su visibilidad y el lugar donde
se quiera llevar a cabo el acceso. Al comienzo del Apartado 6.4 estudiábamos los diferentes
modificadores de visibilidad y el efecto que producían sobre sus métodos miembros.
Recordamos que podemos usar las palabras public, prívate, protected, internal o protected
internal. Normalmente estableceremos como públicos los métodos miembros y privados los
atributos.
Para acceder a un elemento de la clase usaremos el operador punto (.) de la siguiente forma:
■ — —-—-— — * —1
objeto.ati'ibuto; :
objeto.método; •
Si los miembros de la clase son privados, al realizar el acceso desde otra clase se producirá un
error sintáctico. Estos deben ser públicos o protegidos en el caso de que la case derive de la que
contiene los miembros a los que se quiere acceder.
6.5. EJEMPLO DE DESARROLLO DE UN PROYECTO
CON CLASES EN C#
Una vez se han definido los elementos principales de un programa orientado a objetos vamos
a desarrollar en C# un ejemplo para que queden claros los conceptos y además el lector sepa
cómo estructura un proyecto en diferentes ficheros o clases.
En el Capítulo 5, mediante el uso de estructuras, se creaba una aplicación que mantenía los
contactos de una agenda. Vamos a retomar este ejemplo, y realizar un objeto que refiera cada
contacto a almacenar.
5. Clic en Agregar.
6. Llegados a este punto tendremos un proyecto con el fichero Programs.cs que
usaremos para definir la funcionalidad de la agenda y un fichero Contacto.cs que
editaremos con los miembros de la clase contacto.
7. Doble clie sobre el fichero Contacto.cs para que aparezca la pantalla de edición,
veremos algo similar a lo que se observa en la Figura 6.12.
8. Cada contacto en la agenda debe mantener información relativa a: nombre, apellidol,
apellido2, dirección, telFijo, telMovil y mail.
9. Los atributos serán privados por lo que si queremos modificar o visualizar estos
debemos desarrollar un método de acceso y modificación para cada atributo.
10. Crearemos varios constructores. Uno que inicializai-á solo nombre, apellidos y
teléfono móvil; otro referido a nombre, primer apellido, teléfono móvil y para
finalizar un tercero que inicializa nombre, primer apellido, teléfono móvil y mail.
^
Agenda.Contacte
F'using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
; using System.Threading.Tasks;
.Tnamespace Agenda
{
iz' j class Contacto
! {
//CONSTRUCTORES
public Contacto(string n, string api, string ap2, string telfM)
{
nombre = n;
apellidol = api;
apellido2 = ap2;
telMovil = telfM;
piiblic Contacto(string n, string api, string telfM) ;
{ i
nombre = n; I
apellidol = api; ;
telMovil = telfM; i
} i
public Contacto(string n, string api, string dir, string telfM, string ;
telF, string correo) I
{ i
nombre = n; ;
apellidol = api; ■
dirección = dir; I
telMovil = telfM; ;
telFijo = telf.; ;
mail = correo; I
} i
A partir de aquí únicamente falta definir métodos propios de la clase, tales como los de
modificación y acceso a los datos:
— I
NOTA: No es obligatorio el uso de get o set para iniciar los nombres de estos
métodos, e incluso no tienen por qué contener el nombre del atributo al que hacen
referencia, particularmente considero que es una buena forma de distinguir los
' componentes de la clase y su función. Se usará esta nomenclatura a lo largo del libro.
¡ _
Si accedemos al fichero Program.cs podemos crear una instancia de Contacto escribiendo
algo similar a alguna de las líneas que se muestran :
Isabel.setApellido2("Cumbreras"); ;
Isabel.setTelfMóvil("676342134"); I
Isabel.setEmail("is_ji_cu0grct.com"); ;
O getApellidol
string Ccntacto.getApeliidolO
O getDireccion
O GetHashCode
© getNombre
O getTelMovi!
O GetType
© setApellidol
© setApellidol
int opcion;
Consolé.WriteLine("1. Insertar contacto");
Consolé.WriteLine("2. Visualizar agenda");
Consolé.WriteLine("3. Salir");
Consolé.WriteLine("Escoge una opción");
Capítulo 6. Programación orientada a objetos 255
static void insertar (Contacto[] ag, ref int nTotal, Contacto nuevo)
{
ag[nTotal] = nuevo; //nuevo es un contacto ya creado
nTotal++;
op = menú ();
switch (op)
{
case 1: Contacto n = nuevoContacto(); /*Creación de un nuevo
contacto*/
insertar(agenda, ref numeroElementos, n);
break;
case 2: mostrar(agenda,numeroElementos);
break;
256 Programación
Consolé.ReadLine();
} while (op != 3);
nuil nuil nul nuil nuil nuil Objeto I nuil nuil nuil I nuil
arrayíl]
arravll]
Cada casilla esta preparada para recibir un Cada casilla está preparada para recibir un
objeto creado anteriormente objeto creado anteriormente. Arrayjl] ya contiene
una referencia a objeto
,V"rr:rív¡ .. ■
Nombre de nuestro proyecto C#
funcionPrinctpal
Al escribir funcionPrincipai se
ejecuta automáticamente la
función Main.
uncionPrxnca.pAl*exe Parámetro
argslOj)
Biblioteca Documentos
Pcbug
I ^ funcionPrincipal.vshostexe.manifest
i funcionPrincipal.exe.config Ejecutable
¡ funcionPrmcipal.vshcst.exe^gpírfíí'''^
■ funcionPrincipal.exe
I D funcionPnncipal.pdb
■ . luncionPrmcipal.vshostete
I fundonPrindpal -o X Program.cs
Apiicadón
Configuracióru 1(Debug)activa Plataforma: |(AnyCPU)activa
Compilar
Servicios
Configuración
Directorio de trabajo:
Rutas de acceso de referencia
Firma
n Habilitar depuración de código nativo
Seguridad
Habilitar el proceso de hospedaje de Visual Studio
Publicar
Análisis de código
ACTIVIDAD 6.3
Crea una clase llamada Persona que almacene información del tipo: nombre, apellidos,
DNI, sexo, fecha de nacimiento, peso y altura. El atributo fecha de nacimiento debe ser una
estructura (fecha) que guarde día, mes y año.
Configura la clase tal que tenga al menos un constructor y un método selector y modificador
por cada propiedad. Además, crea un método llamado mostrar que visualice todos los datos de
una persona en el formato que prefieras.
ACTIVIDAD 6.4
Desarrolla un programa principal que use la clase Persona creada en la Actividad 6.3, tal que
pueda almacenar como máximo 20 personas. Muestra un menú que pennita: insertar, eliminar y
modificar una persona. Añade las funciones o métodos que necesites.
ACTIVIDAD 6.5
Modifica el programa ejecutable de la Actividad 6.4 tal que además realice las funciones de
ordenar personas por apellidos, ordenar personas por fecha de nacimiento, calcule el peso medio
de las personas almacenadas, así como la edad media y la altura.
Gracias a this podemos pasar parámetros con el mismo nombre que los atributos de la clase
ya que la referencia a objeto distinguirá claramente qué elemento es el atributo y cuál es el
parámetro.
Si retomamos la clase contacto del Apartado 6.5.1, podríamos modificar sus métodos tal que:
Capítulo 6. Programación orientada a objetos 259
//Primer constructor
Contacto(string nombre, string apellidol, string apellido2,
string telMovil)
{
this.nombre = nombre;
this.apellidol = apellidol;
this.apellido2 = apellido2;
this.telMovil = telMovil;
}
//Segundo constructor. Hace uso del primer constructor
public Contacto(string nombre,string apellidol,string apellido2,
string telMovil, string telFijo):this(nombre, apellidol, apellido2, telMovil)
this.te1Fijo = telFijo;
public constructor(tipolparl,..,tiponparn):thís(parl,...,parx){
thís.atributo=pairy;
260 Programación
int numero;
char carácter;
Primero se ejecuta
el constructor llamado con this
6.8. DESTRUCTORES EN O#
Un destructor es una función especial de la clase que se ejecuta de forma automática cuando
se elimina un objeto. Al igual que un constructor no devuelve ningún tipo de dato, ni siquiera
void y se denomima como la clase aunque anteponiendo el símbolo No recibe parámetros y se
usa normalmente para liberar recursos, ficheros, conexiones de red, etc.
Sentencias;
-Contacto(){
Consolé.WriteLine("Objeto destruido exitosamente");
class Ejemploi
String nombre;
public Ejemplo(string nombre){ //(l)
this.nombre=nombre;
Consolé.WriteLine ("El objeto {0} ha sido creado",this.nombre);
~Ejemplo () { //(2)
Consolé.WriteLine ("El objeto {0} ha sido eliminado"
,this.nombre);
)
class Program {
static void Main(string [] args) {
Ejemplo A=new Ejemplo("A"); //(3)
Ejemplo B=new Ejemplo("B");
A=null; //(4)
GC.CollectO; //(5)
}
(3): En este punto, ya en el programa principal, creamos una variable de la clase a la que
llamamos 'A'. Realizamos la misma operación con la variable 'B'.
(4): Asignamos nuil a la variable A, es decir, estamos eliminando la referencia del objeto. En
el momento en que el recolector de basura compruebe los objetos creados y localice que este no
está referenciado, será eliminado.
(5): En lugar de esperar a que el recolector se ejecute cuando tenga previsto damos la orden
de que se produzca la recolección mediante GC.CollectO- Veremos en pantalla el mensaje "El
objeto A ha sido eliminado".
No usamos modificadores de visibilidad cuando codificamos el destmctor, la cabecera public
~Gbjeto NO está permitido.
ACTIVIDAD 6.6
Localiza en la web o bibliografía aportada por el profesor información más detallada sobre el
recolector de basura y el modelo de reserva de memoria de C#. Desarrolla un esquema breve con
la información que hayas obtenido.
ACTIVIDAD 6.7
A.crearObjetoO. mostrar();
class Variables ;
{ i
int var_normal; I
static int var_estatica; //(1) ;
En el código se han distinguido varias zonas con un comentario del tipo (número):
■ (1). Creamos la variable estática. Para definir estático un atributo de la clase solo
tenemos que anteponer la palabra reservada static a su declaración, static tipo_dato
nombre;.
■ (2). Se define el constructor de la clase. Este inicializa la variable var_normal que
como su nombre indica es un atributo como los que hemos estado usando hasta el
momento.
//(2)
Consolé.WriteLine("La variable normal de A es:{ O }",A.getVarNormal());
Consolé.WriteLine("La variable normal de B es:{0}", B.getVarNormal());
A.setVarEstatica(12); //(3)
//(4)
Consolé.WriteLine("Somos A y la variable estática vale:{0}"
, A.getVarEstaticaO);
Consolé.WriteLine("Somos B y la variable estática vale:{0}"
, B.getVarEstatica O);
Consolé.ReadLine();
■ (1). Creamos dos variables de nuestra clase Variables, las llamamos Á y B. Los
valores de var_nomal para A y B son 10 y 20 respectivamente.
■ (2). Realizamos una pequeña comprobación por la que observamos los valores de
var_nonTial para A y B.
(3). Cambiamos el valor de nuestra variable estática, var_estatica. Observamos que
el cambio se realiza desde la instancia A,sin embargo, al ser var_estatica un miembro
static si usamos desde B el método getVarEstatica() el valor devuelto será 12.
(4). Visualizamos el contenido de la variabe estática mediante el uso de los métodos
getVarEstaticaO de A y B y ambos devuelven el mismo valor, ya que una variable
estática es una variable de clase, de forma que todas las instancias de la clase acceden
a ella y pueden modificarla en cualquier momento permaneciendo el cambio para el
resto de instancias.
var estatice
Figura 6.20. Salida del programa ejemplo usado en la explicación de variables estáticas.
NOTA: Podemos usar la variable estática sin necesidad de crear una instancia de la
clase siempre que esta sea pública.
i class Variables{ j
I I
class Program{
static void Main(string [] args){
Variables.var_estatica=27;
Consolé.WriteLine("var_estatica={O)"
,Variables.var estática);
Resumiendo:
■ Los miembros de clase existen incluso cuando no se han creado instancias de la clase.
■ Podemos acceder a un atributo estático indicando Nombre_Clase.var_estática.
Normalmente definiremos variables estáticas públicas para no obligar a la
instanciación en su uso.
ACTIVIDAD 6.8
Crea una clase llamada NodoRed que almacene infonnación sobre: nombre del equipo,
dirección IP, máscara de red, dirección de broadcast, puerta de enlace, dirección de red y
servidores DNS. La clase debe tener una variable estática que se incremente en uno cada vez que
se instancie la clase. Desarrolla los métodos que creas oportunos para visualizar y modificar las
variables, asi como una función estática que pennita ver el número de NodoRed creados hasta un
momento detenninado. Programa una función Main que use la clase. El objetivo es practicar el
uso de miembros estáticos.
6.10. PROPIEDADES EN C#
En repetidas ocasiones hemos hecho hincapié en el uso de atributos privados, tal que si
queremos visualizar o modificar estos el proceso se realizará a partir de un método. Sin embargo,
es cierto, que seria más cómodo escribir de fonna automática instancla.atributo. Las
propiedades penniten que de cara al usuario, un atributo parezca directamente accesible aunque
de forma interna una propiedad no es más que un método selector o modificador.
Véase el siguiente ejemplo.
■ (1). Aunque aún no hemos explicado la sintaxis básica de una propiedad, en esta línea
se está creando una. La propiedad Campo modificará o visualizará el valor del
atributo campo.
■ (2). La palabra reservada set (poner o cambiar) inicia el bloque de código para la
modificación de la variable. Cuando usemos la propiedad se ejecutarán las líneas de
esta zona si queremos proceder a la asignación de nuevos valores.
■ (3). campo=value. Valué referencia el valor que se asignará a la propiedad, siendo
campo como ya sabemos el atributo de la clase.
■ (4). El bloque get incluye las líneas de código que deberán ejecutarse cuando se haga
una llamada desde el objeto a la propiedad. Normalmente get devuelve el valor de la
variable sin más mientras set cambia este.
tipo_propiedad nombre_propiedad{ i
set{ ;
código_para_set;//atributo=value; '<
} \
get{ i
código_para_¿et;//return atributo; '•
} !
; :I
ACTIVIDAD 6.9
Modifica la Actividad 6.8 de forma que en lugar de usar métodos set y get utilices
propiedades para cada atributo de la clase.
Capítulo 6. Programación orientada a objetos 267
6.11. INDIZADORES EN C#
En ocasiones usamos en nuestras clases tipos compuestos como arrays, tal que si queremos
acceder a ellos debernos generar métodos a los que pasar como parámetro una posición. Los
indizadores permiten el acceso "directo" a cada casilla del array ya sea para escribir o leer de él.
Un indizador usa el operador [ ] para acceder a colecciones definidas dentro de la clase, de
fomia que el propio objeto instanciado puede ser tratado como un array facilitando la
codificación del programa y su comprensión.
Objeto A=new ObjetoO;
A[l]="Hola Mundo";
get //(4)
{
if (índice <0 1 ! índice >= 10)
{
return 0;
)
else
{
return tabla[índice];
class Program
■ (1). La clase Indices cuenta con una variable de tipo array. Codificaremos el objeto
para que podamos acceder a ella directamente desde la instancia de la clase.
■ (2). Cabecera del indizador. Usaremos un índice de tipo entero int índice.
■ (3). set permitirá modificar un elemento del array. Controlamos si el índice del array
es correcto, ya que este debe encontrarse en el rango de O a 9.
" (4). get por el contrario devolverá el valor ubicado en una de las casillas de nuestro
array tabla. Al igual que en set comprobamos que el índice introducido sea correcto.
■ (5). Creamos un objeto llamado T de la clase Indices.
■ (6). Usamos T como si esta íuera una variable de tipo array. En la primera línea TI3]
estamos accediendo sin que el usuario se de cuenta al atributo de tipo array de la clase
Indices, concretamente a la posición 3, modificando esta con el valor 13. En la
segunda aparición del indizador estamos accediendo nuevamente a la posición 3 para
visualizar su contenido. Usamos set y get respectivamente.
Los índices del indizador no tienen por qué ser números enteros como ya se ha explicado, e
incluso pueden usarse más de un índice. Véase el siguiente ejemplo:
class Norabre
{
/*La clase usa dos arrays de tipo string, almacenan nombres y apellidos.
Las posiciones refieren el nombre y apellido de una misma persona*/
string[] nombres = { "sabel", "Pepe", "Juan", "Maria"};
string[] apellidos = { "Perez", "Vázquez", "López", "Camacho"};
return -1;
}
return buscaNombre(nombre);
Consolé.ReadLine();
ACTIVIDAD 6.10
Modifica el proyecto realizado en la Actividad 6.3 de fonna que crees la clase Persona y una
clase llamada ListaPersonas. En esta última incluiremos un array donde almacenaremos objetos
tipo Personas y se incluyen todos los métodos para insertar, modificar, eliminar, etc. Utiliza los
mecanismos vistos hasta ahora, propiedades, indizadores, etc. Crea un progi'ama principal que
declare una variable de tipo ListaPersona y se encargue de gestionar los contactos de la agenda.
las clases que los usan, por ejemplo, si usamos el operador relacional = debemos realizar
comparaciones de igualdad entre atributos, no sería correcto realizar operaciones de asignación
ya que confundiría al usuario o programador que use la clase.
La sobrecarga de un operador conlleva la creación de una función con las siguientes
características:
//ATRIBUTOS
int X;
int y;
int z;
//CONSTRUCTOR
public Vector(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
El operador suma necesita de dos operandos, por eso entre sus paréntesis se incluyen dos
parámetros (Vector A, Vector B). A la hora de realizar la operación se suman los atributos de
cada operando y se van almacenando en una variable Vector llamada resultado. Este será el
objeto devuelto en la función.
class Program
{
static void Main(string[] args)
{
Vector A = new Vector(2, 3, 4);
Vector B = new Vector(1, 1, 1);
Vector R = A + B;
En el programa principal creamos una variable Vector con los valores A(2,3,4) y una variable
también de tipo Vector con los valores B(1,1,1). El resultado de realizar la operación R=A+B
será R(3,4,5).
A la hora de sobrecargar un operador debemos tener en cuenta sus características y que no
podemos alterar la precedencia respecto a otros operadores, asociatividad, ubicación y número
total de operandos.
ACTIVIDAD 6.11
Completa la clase Vector usada de ejemplo en el apartado y agrega las sobrecargas de los
operadores resta, multiplicación, producto por un escalar, mayor que, menor que e igual. El
operador mayor comprobará que todos los atributos del primer vector sean menores que los del
segundo. Devuelve -1 en caso contrario. Las operaciones menor_que e igual devolverán -1 en
caso de que los atributos del primer Vector sean mayores que los del segundo o diferentes.. =
devolverá O si los atributos del primer Vector son iguales a los del segundo Vector.
COMPRUEBA TU APRENDIZAJE
1. ¿Qué entiendes por abstracción? ¿Qué mecanismos existen?
2. ¿Qué entiendes por tipo abstracto de datos(TAD)?
3. ¿Cuáles son las propiedades de la programación orientada a objetos o POO?
Descríbelas brevemente.
ACTIVIDADES DE AMPLIACION
1. Crea una clase llamada Fecha para almacenar y operar con fechas. Debe tener los
métodos;
9. Crea una clase llamada Rectángulo que permita almacenar infonnación relativa a
esta figura geométrica como: ancho, alto, posX, posY, carácter. posX y posY
representan las coordenadas x e y de su posición en pantalla (posición de la esquina
superior izquierda). El atributo carácter almacenará el carácter que usaremos a la
hora de visualizar el rectángulo, por defecto es la X. Los métodos que incluiremos en
la clase son:
■ Constructores.
■ Destructor.
■ Propiedades.
■ esValido(anchoPantalla, altoPantalIa). Este método devuelve verdadero o
falso en función de si las coordenadas del rectángulo y sus dimensiones son
aptas para una pantalla de ancho y alto especificado en los parámetros. La
pantalla es representada mediante una matriz de máximo 15x15 de tipo
carácter. Por defecto cada casilla del array esta inicializado con el carácter #.
A partir de esta matriz podemos definir pantallas de 12x5, 9x9, etc., según
deseemos.
■ dibuja(anchoPantaIla, altoPantalla). Dibuja el rectángulo en una pantalla
de ancho y alto pasado como parámetro. Se deben comprobar estas
coordenadas tal que no superen 15. Además, debemos hacer uso del método
esValidoQ para saber si podemos dibujar.
■ Desarrolla una aplicación que haga uso de la clase creada.
10. Modifica la Actividad 9 de forma que las coordenadas vengan representadas por una
estructura de datos llamada coordenadas.
11. Modifica la Actividad 9 de forma que la Pantalla sea tomada como otro objeto.
Nuestro proyecto estará formado ahora de dos clases: Rectángulo y Pantalla. La
clase Pantalla tendrá una matriz de cómo máximo 15x15, usará un indizador para
acceder a ella. Los métodos esValido y dibuja recibirán ahora un objeto de tipo
Pantalla. Modifica la aplicación principal para adaptarla a las nuevas definiciones de
métodos y objetos.
Capítulo 6. Programación orientada a objetos 275
12. Amplía el programa de la Actividad 11 de forma que añadas las clases Triangulo y
Circulo tal que en la misma pantalla puedas dibujar todas las figuras geométricas
definidas. Configura las clases con constructores, destructor, propiedades y
sobrecarga de operadores si lo crees oportuno.
13. Crea un nuevo proyecto e importa a este la clase Persona creada en la Actividad 6.3
y la clase ListaPersona de la Actividad 6.10. En esta última añade las siguientes
sobrecargas de operadores:
■ Sobrecarga del operador +, sustituirá a la función insertar persona en la lista.
No devuelve ningún valor ya que la modificación la realiza sobre los
parámetros. Los operandos serán la lista de personas y la persona que
queramos añadir tal que cuando en el programa principal escribamos
arrayPersonas+Persona se agragará esta persona al array a la primera
posición vacia.
■ Sobrecarga el operador -. Este debe hacer la operación contraria a la suma.
Eliminará la persona que indiquemos como segundo operando. El operador
debe buscar la persona y si existe será eliminada, en caso contrario mostrará
un mensaje de error "La persona a eliminar no existe".
■ Si se te ocurren otras sobrecargas ponías en práctica.
14. Estamos pensando en crear un videojuego. Para ello debemos desarrollar un objeto
por cada componente de este. Empezamos creando una clase llamada Marciano. Esta
clase almaeenar infonnación relativa al alto y ancho del objeto, una matriz del ancho
y alto especificados donde dibujaremos el objeto, el carácter representativo de este,
etc. El objetivo es que tengamos un marciano dibujado en pantalla que sea similar a
esto:
Definir un objeto Pantalla que delimitará la zona en la que se puede mover el marciano.
Crear un programa principal tal que al pulsar una de las teclas de flecha el Marciano se desplace
una posición siempre que sea posible, es decir, no llegue al limite de la pantalla. Usa métodos del
tipo Console.ReadKey para averiguar qué tecla ha pulsado el usuario.
15. Crea una pequeña aplicación de consola que gestione una tienda de móviles. La
tienda distribuye dispositivos móviles tales como télefonos y tablets. Se mantiene
información sobre todos los productos de la tienda, elimina o inserta un nuevo
producto, visualiza precios individuales según producto solicitado, etc. Echa un poco
de imaginación a la actividad y crea todos los métodos y atributos que consideres
necesitará la aplicación.
CAPITULO 7
CONTENIDOS OBJETIVOS
Recordamos que bytecode es un código intermedio anterior al lenguaje máquina que posteriormente
es traducido para el equipo donde se esté usando.
Capítulo 7. Lenguaje de programación Java 279
■ Alto rendimiento. Genera aplicaciones rápidas y más óptimas que otros lenguajes de
programación.
■ Fácil de aprender. Java es un lenguaje de programación cada vez más usado en
entornos educativos, ya que es un lenguaje provisto de herramientas que lo
configuran como un entorno amigable y relativamente fácil de usar. Además, el
manejo de memoria, hilos y errores de ejecución (excepciones), lo denotan de
bastante potencia para desarrolladores tanto principiantes como especializados.
■ Basado en estándares. Java y su tecnología asociada avanzan gracias a Java
Community Process. Java Community Process es im proceso formalizado que
pennite que se definan nuevas versiones y características de la platafonna. Se puede
localizar más información en la referencia web http://www.jcp.org/en/home/index.
■ Uso a nivel mundial. Java es una platafonna libre con lo que su uso se ha extendido
a nivel mundial, tal que dispone de multitud de desarrolladores (número que aumenta
progresivamente en el tiempo), atraídos por la gran cantidad de información, librerías,
herramientas, etc., que existen.
■ Entornos runtime consistentes. Un entorno runtime o entorno de ejecución actúa
como un intennediario entre el sistema operativo yJjava. En Java esta formado por la
Máquina Virtual de Java o JVM, un conjunto de bibliotecas y otros elementos
necesarios para que una aplicación Java sea ejecutada.
■ Optimizado para el control de dispositivos embebidos. Proporciona soporte para
dispositivos embebidos.
■ Recolector de basura. Al igual que C# usa este elemento de forma que elimina
automáticamente aquellos objetos que no referencien ningún punto en memoria, es
decir, hayan sido asignados a nuil en im momento determinado.
CcKnfíguration: <de^uita>nf¡g>
Ubraries
S o Buld
Cwnpdng pnjeba.Prutí»
o Pad'^ging
' >-> Documentmg Arguments:
Woriang Directory:
0 O Appbcabon
-> Web Start VM Opbons:
o Formattmg
(e.g. -XmsU^)
Además de la función maín y la palabra reservada package ^^seguida del nombre del
paquete al que pertenece la clase, en un programa Java solemos encontrar una o varias líneas
precedidas por la palabra import ^^en la zona superior de la pantalla justo después del nombre
del paquete. Estas líneas incluyen referencias a otras clases ya creadas que incorporan
funcionalidad ya que penniten hacer uso de métodos creados en ellas en nuestro programa, son
equivalentes a los usíng en C#.
pacicage prueba;
irrpsrr java.io.*;' ''
) >
public static vcid main(Strmg(] args) <
int r.uir.i;
int nuir2;
Posterionnente se define la clase podemos incluir más de una clase en el mismo fichero
siempre que solo una de ellas sea pública, esta debe denominarse de igual modo que el fichero
.java como ya se ha indicando anterionnente. A continuación se establecen los datos y métodos
miembros que necesitemos. En el ejemplo se presenta ima función miembro de la clase llamada
suma que posteriormente será usada en la función principal dado que maín es una
función estática la función suma también debe serlo.
Java
En Java se determinan como palabras reservadas las que se incluyen en la siguiente tabla.
Estas no pueden ser usadas por desempeñar otra función que no sea para la que fueron diseñadas.
public transient
Capítulo 7. Lenguaje de programación Java 283
■ al definir constante usaremos siempre palabras con todas sus letras en mayúsculas,
por ejemplo PI.
Como ya sabemos debemos escoger identificadores claros y, como su nombre indica, que
identifiquen adecuadamente la variable, constante, función, etc. Nunca podemos usar como
identificador alguna de las palabras reservadas estudiadas en el Apartado 7.3.1.
/**Comentario de documentación */ ;
Un comentario de documentación se utiliza en la generación de documentación automática.
Java dispone de una herramienta llamada javadoc.exe que usa los comentarios encasillados entre
!** y */ para generar un documento que resume las características de los componentes de nuestra
aplicación.
Veamos un ejemplo de uso de javadoc, vamos a desarrollar documentación para el código
mostrado en la Figura 7.3; incluiremos algún comentario de documentación.
package prueba;
import java.io.*;
* Función principal
* 0param args —> Aunque se define no vamos a incluir opciones en el
código
*/
public static void main(String[] args) {
int numl;
int num2;
System.out.println("Introduce un valor");
try {
y **
* BufferedReader; Objeto para el control de entrada de
información desde teclado
*/
BufferedReader teclado=
new BufferedReader(new InputStreamReader(System.in));
numl=Integer.parseint(teclado.readLine());
num2=Integer.parseint(teclado.readLine ());
System.out.printIn(suma(numl,num2));
/**
* Captura de errores en la entrada/salida de información
*/
} catch (lOException ex) {
System.out.println("Error de E/S");
Package prueba
Class Summarj'
Figura 7.4. Página de inicio de documentación para la aplicación de ejemplo que incluye la clase Prueba.
Si hacemos clic en la clase, visualizaremos su contenido y los comentarios que anterionuente
hemos incluido entre las líneas de código fuente.
Capítulo 7. Lenguaje de programación Java 285
Constructor Detail
Prueba
putl:.c Prueba(
Method Detail
Comentario de documentación^ I
Función sinna --> ReaEza la suma de los operandos incluidos como parámteros
Parameters:
r.l —> Primer operando, debe ser entero
r.2 —> Segundo operando, debe ser entero
Retums:
—> Resultado de sumar ni v a2
Parameters:
ares - "> Aunque se define no \-amos a incluir opciones en el código
V '
Tipos enteros: byte (-128 a 127), short (-32768 a 32767), int (-2^' 2^'-l) y
long(-2" a 2"-l).
—> Tipos reales: float (-3.4x10^^ a -1.4x10^^, 1.4x10"^^ a 3.4x10^^) y double (-
1.8x10^°^ a -4.9xl0-^^\ 4.9x10"^^^ a 1.8x10^°®).
Recordamos que los tipos referencia eran aquellos que generaban variables que apuntaban a
una dirección de memoria en lugar del dato concreto. Entre estos encontramos los objetos de
Java que hayan sido creados por el usuario o propios del lenguaje, además de los tipos de datos
compuestos como arrays.
7.3.5. LITERALES EN JAVA
■ Literales lógicos. Los literales lógicos serán los que usemos a la hora de dar valor a
variables de tipo booleanas: true y false.
■ Literales carácter. Los literales de este tipo se representan mediante el uso de
comillas simples ('). Son literales de tipo carácter todos aquellos valores
alfanuméricos incluidos en el código ASCII. Entre este tipo encontramos una serie de
valores especiales (secuencias de escape):
Secuencia
carácter
de escape
Salto de línea
Tabulación
Retomo de carro
Comilla simple
Contrabarra
Comillas dobles
Salto de página
Carácter nulo
típo_dato nombre_yariable:
tipojiato nombre_yariable=literal;
tipo_dato vari, var2, var3;
int num=3;
float reales=2.4f;
char letra;
boolean encontrado;
encontrado=t.rue;
Al declarar una variable Java, si esta no es inicializada, adquiere un valor por defecto. Así, las
variables de tipo numérica, tomar el valor cero, las variables booleanas el valor false, los tipos
String (cadenas de caracteres) u otros objetos el identificador nulo nuil y los caracteres el valor
'\uOOOO'.
Aunque const es una palabra reservada del lenguaje, actualmente no se usa para definir ima
constante. La palabra que antepone Java al tipo de dato de la constante que vamos a crear es
final. La sintaxis de declaración de una constante se muestra a continuación.
Cuando creamos una variable o usamos literales, podemos convertir estos para adaptarlos,
asignarlos, a variables de otros tipos. La conversión se realiza de fonna implícita entre
determinados tipos de datos o explícita mediante la realización de casting o uso de las Clases
envolventes de las primitivas.
NOTA: Las clases envolventes de las primitivas son clases que referencian los tipos
de datos primitivos ya estudiados.
Tipo de dato Clase envolvente
b5de Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
Estas clases trabajan con el tipo de datos primitivos y su rango de valores
proporcionando métodos de conversión de tipos, comprobación, etc.
i int num=20; |
; Integer entero=new Integer(num); ;
; byte numeroCorto=entero.byteValue(); i
Los tipos de datos que ocupan un menor tamaño son convertidos implícitamente, es decir, si
hemos declarado una variable long y le asignamos el 34, aunque este literal se toma como entero
al ser long un tipo mayor convierte implícitamente el entero 34 a long. Igualmente ocurre con el
tipo de datos double y float, siendo double el de mayor tamaño, podemos asignar a un double un
float o int pero nunca al contrario.
La conversión mediante casting sigue la siguiente sintaxis:
variable — (tipo_de_dato)variable_tipo_mayor;
variable =(tipo_de_dato)expresión;
byte num=(byte)12;
char caracter=(char)199;
Las clases envolventes proporcionan métodos estáticos del tipo parseClaseQ, por ejemplo
parselníQ. Si usamos objetos de clases envolventes podemos utilizar métodos del tipo
tipoValueO por ejemplo doubleValueQ- Véase a continuación los siguientes ejemplos.
int num;
System.out.println("Introduce un número");
num=Integer.parseInt(teclado.readLine());
Capítulo 7. Lenguaje de programación Java
Integer dividendo=13;
int divisor=2;
doiable resul tado=dividendo.doubleValue()/divisor;
char digito;
System.out.println("Introduce un digito (0-9):");
digito=(char) System.in.read();
if(Character.isDigit(digito)) {
System.out.println ("0)<. Buen trabajo");
}
else {
System.out.println ("Te dije que escribieras un dígito");
}
ACTIVIDAD 7.1
Busca en la web o referencia aportada por el profesor las clases envolventes estudiadas en
este apartado y observa los métodos que incluyen. Localiza algún programa ejemplo que las
utilice y estudia su funcionamiento, si es necesario, ya que aún no se han estudiado todos los
elementos del lenguaje, pide ayuda al profesor.
Nombre Descripción
Positivo Indica que el número es positivo. Operador unario.
Negativo Se usa para establecer el número como negativo. Operador
unano.
class Circulo{
int radio;
public calculaArea()throws IOException{
BufferedReader teclado=new BufferedReader(
new InputStreamReader(System .in))
System.out.println("Introduce un nuevo radio");
radio=Integer.parseint(teclado.readLine());
System.out.prinln((radio<100)?PI*2*radio:"Radio excesivo");
}}
Capitulo 7. Lenguaje de programación Java 291
ACTIVIDAD 7.2
Realiza la Actividad 3.4 en Java. Usa System.out.println("texto") para mostrar los textos en
pantalla.
El operador instanceof pemiite realizar una comprobación entre objetos, interfaces o arrays
de fonna que devuelve verdadero si el operando de la izquierda es exactamente igual al operador
de la derecha. Este operador presenta utilidad cuando trabajamos con clases que heredan unas de
otras.
!
I
■ (1). Creamos un array de Objetos (Object). De esta clase heredan todas las demás.
Aún no hemos estudiado el concepto de herencia así que podemos decir algo así
como que si creamos un array de este tipo posteriormente, al ser la clase de la que
heredan todas, cada casilla puede ser inicializada con cualquier tipo de objeto que
deriva, por ejemplo Integer, BufferedReader, etc.
■ (2). El objetivo de la aplicación es obtener la media aritmética de todos los números
enteros y reales insertados en el array a partir de objetos Integer o Double, por esa
razón se crean las variables inediaEnteros, mediaReales, totalEnteros y
totalReales.
■ (3). Inicialización del array. Al ser un array de objetos, cada casilla debe ser
inicializada a partir del operador new como ocurría en C#. Si observamos en cada una
de ellas incluimos diferentes tipos, Integer, Double o Character. Recalcar que esto es
posible gracias a la herencia. Estudiaremos en profundidad estos conceptos en
capítulos posteriores.
■ (4). El bucle Para (for) se encargará de recorrer el array de objetos llamado números
y analizar cada casilla.
" (5). En este punto entra en juego el operador instanceof. Para cada casilla
comprobamos si la instancia de clase u objeto almacenado es de tipo Integer, si es así
usamos su valor para almacenar en mediaEnteros, si no, comprobamos la siguiente
condición que nuevamente usa el operador.
■ (6). En esta segunda sentencia (else if) comprobamos si el tipo de objeto almacenado
en el array es una instancia de Double, si es así, recogemos su valor en mediaReales.
■ (7). Estas instrucciones muestran los resultados obtenidos tras realizar la media
aritmética de números enteros y reales.
Clase instanceof Objeto(instancia) i
Desplazamiento a la
izquierda, cada bit es
recorrido x posiciones a la
izquierda.
Desplazamiento a la derecha.
» / »> Cada bit es recorrido x bits a
la derecha.
Complemento.
□ O
++ - ! ~
new (tipo_dato)expresión
* / %
« » »>
<><=>=
= += .= *= /= %= A=: 1= »>=
7.3.10. OPERACIONES DE ENTRADA/SALIDA DE DATOS EN
JAVA
En apartados anteriores en este mismo capítulo hemos usado métodos que permitían la
entrada/salida de datos. En estos párrafos vamos a estudiarlos en profundidad.
Hasta el momento, tanto en Java como en C# estamos realizando aplicaciones de consola, y
según esto las operaciones de entrada y salida de datos se realiza a través del teclado o la consola
del sistema, los dispositivos de entrada/salida estándar.
Los objetos que referencian la entrada y salida estándar son System.in y System.out
respectivamente.
7.3.10.1. MÉTODOS PARA LA VISUALIZACIÓN DE INFORMACIÓN A
TRAVÉS DE LA SALIDA ESTÁNDAR
A la hora de escribir información en pantalla la sintaxis a seguir será la siguiente;
System.out.métodoQ;
//Siendo método cualquier método de impresión de información en la salida estándar
Método Descripción
rintln(char)
println(char[]) El método println() se sobrecarga de fonua
rintln(double) que podemos usar como parámetro cualquiera de
los tipos de datos primitivos, arrays, objeto
rintln(int) String y cualquier otro objeto derivado de
irintln(Iong) Object.
rintlnCi ava.Iang.Object)
rintIn(java.lang.String)
El método printQ imprime información en
pantalla sin realizar un salto de línea.
printO
Encontramos print(boolean), print(char),
print(char []), etc.
Permite escribir una cadena usando los
printf("cadena de formato",
valores de variables sin necesidad de utilizar el
variables)
operador +
son: seguido de un número entero (así lo denota %d), este será el valor almacenado en la primera
de las variables después de la cadena de fonnato (numl). A continuación se muestra un guión -
para finalizar con un nuevo número entero(%d)equivalente a num2.
Suponiendo que numl=2 y num2=4 la salida es: Los números son: 2-4.
A la hora de generar la cadena de formato, en Java se debe especificar con el símbolo
adecuado, el valor concreto que se va a referenciar. Por ejemplo, si en la cadena de control
escribimos %d la variable o literal que debe encontrarse en la posición adecuada debe ser entera,
en caso contrario se produce un error de ejecución, ya que los tipos de datos no serían los
mismos.
■ (2). Si queremos mostrar por pantalla el carácter pulsado o utilizarlo en una sentencia
altemativa, repetitiva, etc., debemos realizar un casting a la variable tal y como se
especifica en esta línea.
Existen otros objetos Java que proporcionan nuevos mecanismos de recogida de información
de la entrada estándar. Los objetos InputStreamReader y BufferedReader penuitcn identificar
el flujo de información de entrada e incluir métodos para procesar este flujo.
Un Stream se refiere a un flujo de bytes, de forma que si observamos el nombre del objeto
InputStreamReader podemos deducir que está diseñado para encargarse de tratar un flujo de
entrada de datos (InputStream) que solo va a ser leído. A la hora de utilizar el objeto
InputStreamReader debemos indicarle qué flujo de datos va a usar.
La sintaxis básica para definir un flujo de datos de entrada no es más que la definición y
creación de un objeto de la clase InputStreamReader.
! InputStreamReader nombre_yariable=new InputStreamReader(flujo); !
±nc num=SY3teia.in.read();
ACTIVIDAD 7.3
Las sentencias de control alternativas en Java son en sintaxis iguales a las vistas en C#.
SENTENCENCIA ALTERNATIVA SIMPLE
int numerol,numero2
char Operación;
Buf feredReader teclado=new Buf feredReader (new InputStreamReader (System. in) ) ;
ACTIVIDAD 7.4
Realiza las Actividades 3.8 a 3.11 del Capítulo 3 en Java. Observa que los codigos fuente son
muy similares, a excepción de las operaciones de entrada/salida de información.
NOTA: En Java, como en C#, los identifícadores son visibles entre el par de llaves
donde son definidos. Así, si creamos una variable entre las llaves de una función esta será
local a la función y solo podrá ser usada en ella.
BUCLE WHILE
while (condición){
Sentencias;
}
' BUCLE DO
do{
Sentencias,
}while (condición),
'BÚCLÉ FÓR
for (inicialización; condición; modificación){ :
Sentencias; i
} i
Además de las sentencias repetitivas vistas en Java podemos usar las palabras reservadas
break, continué y return. Si el lector necesita refrescar su uso véase el Apartado 3.3.13.4.
Capítulo 7. Lenguaje de programación Java 299
i++;
)while(i<10);
ACTIVIDAD 7.5
Realiza un programa que pida un número al usuario y devuelva la suma de todos sus dígitos.
ACTIVIDAD 7.6
Realiza un programa que pida al usuario número y muestre por pantalla si estos son primos o
no. La aplicación finalizará cuando el usuario escriba -1.
ACTIVIDAD 7.7
Procedimientos !
- ^
Funciones
return expresión;
7.4.1. PARÁMETROS
En Java los parámetros son siempre pasados por valor, es decir, siempre usamos una copia de
la variable que se utiliza en la invocación o llamada del subprograma, a excepción del tipo
compuesto array. Los objetos, pese a que podamos pensar que son pasados por referencia, son
pasados por valor, aunque si se realizan modificaciones sobre sus propiedades estas prevalecen
generando un pseudo paso por referencia. Véase el siguiente ejemplo para entender el concepto.
Supongamos que tenemos un proyecto en Netbeans que incluye la definición de una clase
llamada Ejemplo y la clase que contiene el programa principal llamada Parámetros. En
Ejemplo se define un único atributo de tipo entero, int numero; además de un constructor que
inicializa el atributo y los métodos necesarios para visualizar y modificar este.
public class Ejemplo {
//Atributo
int numero;
//Constructor
public Ejemplo(int n){
this.numero=n;
}
modificaObjeto_2(objEl); //(7)
System.out.printf("Después de usar la función modificaObjeto_2,
objEl=%d y objE2=%d\n",objEl.getNumero(),objE2.getNumero()); //(8)
(4). Realizamos una primera comprobación. Mostramos por pantalla los atributos de
objEl y objE2 antes de ser modificados. En pantalla visualizaremos la fi-ase: Antes
de usar la función, objEl=10 y objE2=20.
(5). Usamos el primer método de modificación pasando como parámetro el objeto
obJEl. Al llamar al método, accedemos a su código y se ejecutan sus líneas de forma
que se genera un objeto Ejemplo auxiliar y se asigna a objEl.
(6). Al volver a comprobar los valores de nuestros objetos de prueba, observamos que
la salida que obtenemos es: Después de usar la función modificaObjeto, objEl=10
y objE2=20. No se ha producido modificación alguna, es decir, el objeto ha sido
pasado por valor de fonna que al realizar la asignación objE=objAux se usa una
copia del parámetro y al finalizar la función este sigue presentando el mismo valor
que antes de ejecutarse el procedimiento.
(7). Invocamos nuestro segundo subprograma de modificación. El objeto objEl es
pasado como parámetro pero en el interior de la función se modifica su propiedad, no
el objeto como tal.
(8). Al realizar una nueva comprobación mediante el uso de una cadena de
caracteres, observamos la frase: Después de usar la función modificaObjeto_2,
objEl=30 y objE2=20. Aunque el objeto no es pasado como referencia en su
totalidad o tal y como conocemos y hemos estudiado el paso de parámetros por
referencia, si se modifican sus propiedades los cambios permanecen una vez finaliza
la función.
ACTIVIDAD 7.8
En Java podemos definir multitud de funciones con el mismo nombre siempre que contengan
diferente número de parámetros, parámetros de diferentes tipos o ambas cosas.
Así, podemos encontrar código fuente como el que sigue:
public void mostrar O {
7.5. ARRAYS
La sintaxis de declaración y creación de un array en Java es similar a la vista con anterioridad
en el Capítulo 5 para C#.
~ — - — - -- — _ _ _ -—
tipo_dato[]nombre_array;//Declaración. •
nombre_array=new tipo_dato[TAM_MAXJ;//Reserva de espacio en memoria, creación. :
tipo_dato[]nombre_array=ne}v tipo_dato[TAM_MAX]; ¡
^ No todos los lenguajes de programación que utilizan esta estructura compleja empiezan a contar en
cero la primera posición de un array. Existen lenguajes que trabajan en base 1, es decir, el primer Índice de
posición de una tabla es 1 no 0.
Capítulo 7. Lenguaje de programación Java 303
//Inicialización del Segundo elemento del array con las suma de las posiciones
array[2]=array[0]+array(4];
Para inicializar todos los elementos del array a la vez, usaremos normalmente estructuras
repetitivas que soliciten un valor al usuario o bien introduzcan un valor aleatorio o fijo a cada
celda.
En Java como en C# un array tiene una serie de métodos o propiedades asociados, entre estos
elementos encontramos la propiedad length que devuelve el número de valores que puede
almacenar el array.
int [] array=new int[10];
array[1]=3;
array[5]=4;
System.out.println ("El número total de valores
que podemos almacenar es:"+array.length);
7.5.1. MATRICES
Seguimos en Java haciendo uso de arrays de más de una dimensión. Su sintaxis es similar a la
usada en C# para matrices escalonadas. Introducimos un par de corchetes por cada dimensión
adicional. Usaremos normalmente arrays bidimensionales, llamados también matrices.
i tipo_dato[][]nombre=new tipo_dato[TAM_MAX][TAM_MAX2];
8 9
//La variable pos será usada para la búsqueda de la letra indicada por el I
usuario en la palabraSecreta. Si existe la letra se devolverá su posición en ;
esta variable, que a su vez será utilizada para rellenar el array palabra. ;
int pos; I
int aciertos=0;
return posición;
/*Método que irá modificando la matriz pantalla que se encarga de contener el
estado del "ahorcado". A cada nuevo fallo se dibujará una parte del
ahorcado.*/
/*Función principal*/
static void main(String[] args) throws lOException {
'^^s.r []palabraSecreta={'a','r','r','a','y');
char []palabra=new char[palabraSecreta.length];
char [][]pantalla=new char[5][5];;
char letra;
int pos;
boolean ganador=false;
int fallos=0;
int aciertos=0;
System.out.println("EMPIEZA EL JUEGO!!!");
inicializaJuego(palabra,pantalla);
mostrar(palabra,pantalla);
mostrar(palabra,pantalla);
if(aciertos==palabraSecreta.length){
ganador=true;
if (ganador==true){
System.out.println ("Ganaste! I !");
}
else {
System.out.println("Ohhhi !! Has perdido!! i");
ACTIVIDAD 7.9
ACTIVIDAD 7.10
String trimO- Devuelve una copia de la cadena eliminando los espacios en blanco.
String vaIueOf(tipo variable). Devuelve la cadena de caracteres resultante de
convertir la variable del tipo pasado como parámetro.
ACTIVIDAD 7.11
Modifica el ejemplo del juego del ahorcado visto en el Apartado 7.5.2. de forma que en lugar
de arrays de tipo carácter uses objetos de tipos String.
En el ejemplo se ha querido realizar una pequeña aplicación, que puede ser modificada
posteriomiente cuando conozcamos todos los elementos del lenguaje, convirtiéndose en un
software de interés para sistemas operativos Linux.
Los sistemas operativos Linux almacenan en un fichero llamado /etc/passwd los nombre de
los usuarios registrados en el sistemas e infonnación relativa a ellos como cuál es su directorio de
trabajo.
En el programa de ejemplo suponemos que analizamos una línea de este programa y
obtenemos su directorio de trabajo usando la función split. Posterionnente puede ser modificado
para que leamos directamente del fichero /etc/passwd línea a línea y podamos extraer más
infonnación.
ACTIVIDAD 7.12
Realiza un pequeño programa que dada una cadena de caracteres almacenada en un objeto de
tipo String devuelva el número de letras en mayúsculas y minúsculas.
ACTIVIDAD 7.13
Realiza un ejercicio tal que dada una cadena de caracteres devuelva esta invertida.
Declaración de atributos:
r 1
I tipo_dato nombre_atributo; i
Normalmente un atributo no suele incluir modificadores antes del tipo de dato ya que deben
ser privados o de la clase y no accesibles con facilidad. Si bien es cierto, existen propiedades
estáticas que deben ser públicas ya que suelen ser desarrolladas para ser usadas directamente
desde la clase y no desde instancias de esta.
Declaración de métodos en Java:
j ^
■ Selectores.
■ Modificadores.
NOTA: Java, al igual que C#, usa el denominado Recolector de basura (Garbage
collection) tal que pasado cierto tiempo aquellos objetos que no están referenciados,
apuntan a nuil, son eliminados de forma directa. En Java, no podemos definir destructores
por clase como hacíamos en C#, ya que el uso del recolector garantiza el cierre de flujos
de datos, eliminación de objetos, etc. El lenguaje dispone de una función, finalizeQ,
heredada por todas las clases desarrolladas y que se encarga de llamar a recolector de
basura para que se encargue de eliminar antes del tiempo previsto elementos no
necesarios. La sintaxis de la función es:
//Declaración
Nombre_Clase nombre_yariable;
//Creación
nombre_yariable=new Nombre_ClaseQ;
//Declaración y creación
Nombre_Clase nombrejyariable=new NombreJZlaseQ;
Es importante como en C# recalcar la necesidad de crear o usar el operador new para reservar
espacio en memoria, ya que si solo se realizará la declaración el objeto no podría ser usado.
Una vez instanciado un objeto, el acceso a los miembros de la clase se realiza a través del
operador punto (.). En Java, como también vimos en C#, usaremos el operador this para
referenciar a la propia clase, así como los métodos y atributos de esta.
Recordar que a la hora de crear arrays de objetos es necesario inicializar cada objeto de cada
casilla de la clase debido a que la declaración y creación del array no realiza esta operación. Asi,
a la hora de usar un objeto almacenado en un array debemos antes haberlo creado, ya sea en el
inicio de la aplicación o antes de ser usado.
NOTA: Normalmente solemos tener un paquete con todas las clases no ejecutables y
otro con clases ejecutables. Por lo pronto, y hasta que no se estudien los paquetes,
usaremos el package por defecto para almacenar todas.
Capítulo 7. Lenguaje de programación Java
ACTIVIDAD 7.14
Crea un nuevo proyecto en Java llamado Figuras e incluye en él una clase por cada figura
geométrica que prefieras. Corno mínimo usa Círculo, Rectángulo y Triángulo.
ACTIVIDAD 7.15
Configura cada clase de Figuras con los atributos y métodos que desees. Puedes incluir
métodos del tipo: Perímetro, Area o Mostrar. Los atributos deben ser los parámetros
fundamentales de cada figura geométrica, por ejemplo del círculo el radio.
NOTA: C# es un lenguaje que surge de C, C-H- y Java, las similitudes con Java son
muchas. Hemos estudiado que existen componentes que ircopora C#, debido a su
procedencia de C y C++ que no incluye Java, sin embargo si el lector ha entendido todos
los conceptos vistos para C# en Capítulos anteriores no le será complicado programar en
Java.
COMPRUEBA TU APRENDIZAJE
1. ¿Cuáles son las características principales de Java?
2. ¿Cuál es la estructura básica de un programa Java?
3. ¿Qué es un comentario de documentación? ¿Para qué se usa? ¿Qué es Javadoc?
4. ¿Cómo se realiza la conversión entre tipos de datos primitivos en Java?
5. ¿Para qué se usa el operador instanceof?
6. ¿Qué clases se usan para la introducción o salida de datos en Java en aplicaciones
de consola? ¿Qué métodos son los más usuales?
7. ¿Cómo se realiza el paso de parámetros en Java? Explica el paso de parámetros a
funciones.
ACTIVIDADES DE AMPLIACIÓN
1. Crea una clase llamada libro. Incluye los atributos que creas sean
representativos de un libro, constructores, métodos getter y setter (selectores y
modificadores) y la sobrecarga del método toString que devuelva una cadena
de caracteres con el nombre y autos del libro.
2. Crea una clase llamada ListaLibros que incluya un an-ay de libros. La clase
debe contener métodos que permitan gestionar el array, es decir, insertar un
libro, eliminar un libro, modificar o mostrar, etc.
3. Implementa una pequeña aplicación de consola que use las clases desarrolladas
en las Actividades 1 y 2 tal que presente un menú en el que puedas gestionar
los libros de una biblioteca.
7. Desarrolla en Java una clase que refleje una estructura tipo cola de números
enteros. Una cola es un conjunto de elementos tal que el último en llegar se
coloca al final de la cola y se van eliminando o sacando elementos de la cola
desde el principio de esta (recordad el funcionamiento de la cola del cine).
8. Crea una clase Persona de la que sólo debemos mantener infonuación
relacionada con su Nombre, Apellidos y NIF. Configúrala añadiendo los
métodos y propiedades que creas oportunas.
9. Usa las clases creadas en las Actividad 7 y 8 de fonna que desarrolles un
programa para un cine. La cola será una cola de personas (copiamos el código
fuente de cola y lo modificamos). La cola se rellenará con x personas y de
forma repetitiva se irá pidiendo a cada una el número de entradas que se desea
comprar (agregando esta característica a la clase) y las butacas (se mostrará el
aforo tal que el usuario pueda escoger un asiento). Una vez acabe la compra se
eliminará el usuario de la cola. Debemos mantener variables que almacenen el
número de entradas disponibles, número de entradas vendidas así como
información sobre la pantalla y el texto escrito (podemos crear una matriz de
20x20 como información de asientos en la sala).
Capítulo 7. Lenguaje de programación Java 315
10. Realiza una pequeña aplicación que pida al usuario que escriba su correo
electrónico y compruebe si este es correcto.
11. Crea una clase llamada Equipo donde almacenes información relativa a un
sistema infomiático: número de serie, modelo y marca de placa base,
características del micrprocesador, memoria RAM, etc. Incluye los métodos
que creas oportunos teniendo en cuenta que deben almacenarse además de las
incidencias que puedan producirse.
12. Crea una clase listaEquipos que pennita mantener una lista de ordenadores
(clase Equipo) de fonna que podamos realizar operaciones del tipo eliminar,
modificar o agregar.
13. Crea una pequeña aplicación de consola que gestione una serie de ordenadores.
Debes usar las clases anteriores.
CAPITULO 8
ENTORNO GRÁFICO
CONTENIDOS OBJETIVOS
Hola Mundo!!
CamDtar Texto
{
this.buttonl « nevv Systea5.Windows.Foras.£jttcn();
thi5.SuspendLoyout();
//
Q buQonl D
// buttonl
//
this.buttonl.Location • new Systea.Drawing.Pcint(25, 56);
this.buttonl.Narre • "büttonl";
this.buttonl.Sire ■ new Systena.0rawing.Sirc(75, 23);
this.buttonl.Tabindex « O;
this.buttonl.Text = "buttcnl";
this.buttonl.UseVisualStyleBackColor ■ true;
4. Clic en Aceptar.
Una vez se han seguido estos pasos veremos en pantalla los elementos que se agrupan en la
Figura 8.3. En la zona de la izquierda se encuentra el formulario en vista de diseño. Iremos
agregando controles según vayamos necesitándolo a partir del cuadro de herramientas. El
cuadro de herramientas proporciona todos los elementos que se pueden incluir en un fonnulario.
Cada componente puede ser configurado con una serie de características, es decir, podemos
modificar sus propiedades en función de su tipo y las restricciones establecidas para ella. La
modificación de una propiedad se realiza a partir del cuadro de propiedades, situado en la zona
inferior derecha de la Figura 8.3. Para finalizar observamos el explorador de soluciones, desde el
que podemos agregar nuevos formularios o contenedores a nuestra aplicación siempre que lo
creamos oportuno.
Capítulo 8. Entorno gráfico 321
Explotador de solucionen
(Zi 'o - íf Q ® la O ^¡
SuiCiji en el EApícradoi de soÍuc«ones (Ctrl*")
P ^ Fcrml.cs ~
P C* Program.cs
Probablemente nuestras aplicaciones están fonnadas por más de un formulario tal que todos
interactúen de alguna fonma entre ellos. Por defecto, cuando creamos un proyecto gráfico en
Visual Studio, el proyecto dota a esta aplicación de un único objeto Fonn. Si necesitamos incluir
alguno más:
1. En el Explorador de soluciones clic con el botón derecho del ratón sobre nuestro
proyecto. Nos colocamos sobre Agregar... y Agregar Windows Form...
2. En el cuadro de diálogo localizamos el cuadro de texto nombre, escribimos en él el
nombre que daremos a este nuevo contenedor.
3. Clic en Agregar.
Forml,es Finalizados estos pasos veremos en el Explorador
Form2.cs Windows el nuevo componente. Sabremos que se
Figura 8.4. .Iconos representativos de objeto tratavisual
de imStnHin
formulario debido a la simbología que
formulario en el Explorador de soluciones. ^
8.4.1.2. ENTORNO DE TRABAJO
Una vez hemos creado un nuevo proyecto gráfico en Visual Studio veremos una pantalla
similar a la que observamos en la Figura 8.5.
ICaXAR VER PROVECTO COfcV&.&R| DfPÜ^ CQUPO rORM&TO HERIUMimAS PRUCBA VimAyU ATUCU
O- > ► kycaALctb^
^ Cufdro d< hcrtKTxenUi • 9 X FemO a*
* KSctoKh
6 tnu^m Tc*1
A \ Texto jtcctjdo jJ
StdrtPodtion
siempre que
^
los atributos sean V.IndowStíte
v:.ndcv«Drf.uttLo«t«o
\^.'mdcwsDeíautlLo<at»©o
Normal
Normal
accesibles de algún modo. Para s VCfttMU
B Est3o de vent^n»
ContrclBox Tnjt ^
modificar algún valor solo debemos sác°"
Sáe A
localizar la propiedad y hacer clic Tjm,ñodticAtrdi.»,pixe(a.
Tamjjno del c(»trol, en pixe^es. \
junto a ella. El cuadro de propiedades \ \
presenta en su parte superior una lista
con todos los controles incluidos en el ~
Figura 8.8. Cuadro de propiedades en
formulario
,. ,
de forma ,que
~
podemos Figura 8.8Visual
Cuadro de propiedades en
Studio.
cambiar de uno a otro de fonna rapida
y modificar así sus propiedades.
324 Programación
I Propiedad s
Forml SjAjtm.VVindc.vs.Fofms.Form
qS! i
Figura 8.9. Iconos en el cuadro de propiedades que permiten permutar entre vista de propiedades y
eventos.
Son muchos los controles que podemos usar, y a su vez muchas las propiedades exclusivas de
estos. Como programadores, conoceremos aquellas que usemos con frecuencia pero no tenemos
por qué saber las características de todos los objetos y sus atributos. Visual Studio entiende que
un programador no puede o tiene por qué memorizar todos los controles, su funcionalidad y sus
características y por eso, en la parte inferior del cuadro de propiedades observaremos como
aparece una pequeña descripción de la propiedad que se encuentre seleccionada en ese momento.
8.4.1.3. CONTROLES
En el cuadro de herramientas veremos una categoría catalogada con el nombre controles
comunes que agrupa los controles que suelen ser más usados en aplicaciones. Entre estos
controles encontramos;
■ Button (Botón). Control que tras ser pulsado provoca la ejecución de una acción.
■ CheckBox (Casilla de verificación). Elemento de un fonnulario diseñado para
presentarse en dos estados, activado y desactivado según el usuario pulse sobre él.
Activar una casilla de verificación suele conllevar la posterior ejecución de una
acción, cambio de característica, etc. Suelen usarse en sentencias alternativas de
modo que según la casilla se baya activado o no se realiza una acción u otra.
■ ComboBox (Lista desplegable). Control que muestra una lista de opciones y pennite
al usuario escoger una entre ellas. El objeto se denomina lista desplegable debido a
que veremos una única opción a la vez y para visualizar el resto debemos hacer clic
en el cuadro de control.
■ Label (Etiqueta). Objeto que permite visualizar un texto en pantalla. Básicamente su
función es esa, visualizar un texto aclaratorio sobre algún componente concreto del
formulario.
■ ListBox (Cuadro de lista). En esencia es similar al combobox ya que muestra una
lista de elementos, la diferencia está en su visualización. Veremos más de un ítem a la
vez y podremos seleccionar más de uno.
■ RadioButton (Botón de opción). Encontraremos grupos de estos controles de fonna
que solo podremos seleccionar uno a la vez en el grupo. Son similares a las casillas de
verificación debido a que son objetos que poseen dos estados, activado y
desactivado y según estos el programador podrá realizar una acción, pero se
diferencian cuando se encuentran agrupados con elementos del mismo tipo de modo
Capítulo 8. Entorno gráfico 325
form2
ComboBox
LabeH
Casillas de
verificación
Cuadro de texto
Seguiremos analizando otros conti'oles, por lo pronto conocer estos nos permitirá realizar
aplicaciones de cierta envergadura.
Formi 1 ■=■ I n) |»iii^¡jg|' Antes de nada debemos seguir los pasos del
Apartado 8.4.1 para crear un nuevo proyecto.
Calculadora Le daremos el nombre Conversor.
estos componentes (de hecho estos elementos son variables de las clases TextBox y
Button). Para asignar un nombre a un control debemos localizar la propiedad namen.
10. Accedemos al cuadro de propiedades, localizamos la propiedad ñame y clic en el
cuadro que se encuentra justo al lado. Por defecto, los objetos de tipo textBox se
denominan textBox 1, textBox2, etc., podemos usar otra nomenclatura que nos resulte
más representatix a y que nos ayude a identificar más fácilmente los cuadros de texto
de nuestra aplicación. Ya que es un cuadro de texto, vamos a comenzar el nombre del
control con las letras txt seguidas de un nombre representativo relacionado con la
información que va a tratar. Llamaremos a nuestro cuadro de texto situado jimto a la
etiqueta Euros con el nombre txtEuros.
11. Si el tamaño del cuadro por defecto nos parece inadecuado, podemos modificarlo
desde el entorno gráfico, pinchando y arrastrando uno de los pequeños anclajes
situados a cada lado del cuadro. O bien es posible establecer un valor para el ancho y
el alto del componente mediante el uso del grupo de propiedades Size entre las que se
encuentran Width (ancho) y Height (alto).
12. Insertaremos el siguiente cuadro de texto siguiendo los pasos 8 a 11. Llamaremos al
cuadro de texto txtDoIares.
Para codificar el evento clic podemos seguir uno de estos dos pasos:
■ Elacer doble clic sobre el botón. Esto provocará que se muestre el código fuente
asociado al fonnulario con el cursor activo en el método para el evento clic (ya que
este es el predeterminado para este tipo de control).
■ Seleccionar el botón, mostrar los eventos en el cuadro de propiedades, localizar el
evento clic y hacer doble clic sobre él. Obtendremos el mismo resultado que en el
punto anterior.
Acabamos de acceder al método de nuestro botón btnConvertir asociado al evento de hacer
clic con el ratón, a continuación solo debemos escribir las líneas de código que se deberán
ejecutar cuando este se dé.
Dada que la operación es una conversión en la que tenemos la cantidad de euros y teniendo en
cuenta que 1 euro equivale a 1,3194, al hacer clic en el botón:
1. Multiplicaremos los euros escritos en txtEuros por la cantidad 1,3194.
2. Mostraremos esta cantidad en el cuadro de texto txtDolares.
El código resultante es el que se muestra a continuación:
private void btnConvertir Click(object sender, EventArgs e)
{
txtDolares.Text = (int.Parse(txtEuros.Text)
* 1.3194).ToString O ;
■ Los nombres asociados a los eventos comienzan con el nombre del componente,
seguido del nombre del evento y una lista de parámetros.
■ Un cuadro de texto recibe o muestra información de tipo texto, así, a la hora de
recoger una cantidad de este debemos realizar una operación de conversión
(int.parseO).
■ Igualmente, la información que debamos mostrar en un cuadro de texto debe ser de
tipo String, de forma que a la hora de modificar el valor de un cuadro el nuevo valor
debe ser de tipo texto( de ahí la necesidad de usar el método ToStringO en el
ejemplo).
■ La propiedad que almacena el texto escrito en un textBox en Text. Usaremos la
sintaxis cuadro.Text.
Llegados a este punto nuestra aplicación está finalizada. Solo debe hacer clic sobre el botón
de ejecución. Pasados unos segundos veremos el fonnulario. Probaremos su funcionalidad
escribiendo en el cuadro de texto euros una cantidad válida y pulsando el botón convertir. Hasta
ahora no hemos tratado errores de ejecución, si no escribiéramos ningún valor en el cuadro de
texto euros o el valor no fuera un número válido, el programa exteriorizaría un código de error
cerrando la aplicación. Vamos a controlar que al menos el usuario escriba un valor en el cuadro
euros, tal que si está vacío muestre un mensaje de error. El código debe quedar algo así como:
Si(cuadro de texto euros vacio){
Mensaje "El cuadro esta vacio";
}
Sino{
cuadroDolares=euros*1,3194;
}
1. Si nos encontramos en la vista de diseño haremos doble clic sobre el botón convertir.
Desde la vista de código solo debemos localizar el evento clic del botón.
Capítulo 8. Entorno gráfico 329
2. La propiedad Text del cuadro de texto euros refiere una variable de tipo String.
Debemos saber si esta variable está vacía o no cuando se pulsa el botón. Para ello, los
objetos String disponen del método Compárelo. Claramente se debe crear una
sentencia altemati\ a doble.
else
{
txtDoIares.Text = (int.Parse(txtEuros.Text) * 1.3194).ToString();
ACTIVIDAD 8.1
£norcuddrov»dol
' Aunque a simple vista esta característica pueda parecer algo absurda tiene su sentido, ya que en
ocasiones realizaremos aplicaciones con multitud de controles que podemos desplazar de fonna
involuntaria. Al establecer Locked a true el control queda bloqueado y estático en la posición establecida
por el programador.
Capítulo 8. Entorno gráfico 331
■ Text. Determina el texto que debe verse sobre el control. En controles, tipo cuadros
de texto establece el texto que por defecto debe estar escrito sobre el componente
cuando se ejecute la aplicación.
■ Enabled. Permite habilitar o deshabilitar un control. Cuando un componente está
deshabilitado es visible pero no acepta ningún tipo de interacción con el usuario.
■ Tabindcx. Determina el número de orden del control a la hora de usar la tecla TAB.
Normalmente en una aplicación gráfica podremos desplazamos a través de ella
gracias al uso de la tecla TAB en caso de que el ratón no funcione adecuadamente.
Según se pulsa esta tecla se activa un componente u otro de la aplicación. El orden
que establece qué control se visualiza primero cuando pulsamos TAB, cuál es el
siguiente, etc., se indica en esta propiedad. Este valor es inicializado por defecto en
Visual Studio en función del orden de creación de los objetos.
■ Size. Conjunto de propiedades que penniten establecer las dimensiones de un control.
Se compone de las propiedades Width y Height.
Propiedades comunes del objeto Forni:
■ IsMdiContainer. Esta propiedad booleana pemiite configiorar im formulario
principal y el resto como secundarios, tal que hace las veces de contenedor del resto.
■ Opacity. Para indicar el grado de opacidad del formulario.
■ MinimizcBox. Propiedad booleana que permite hacer visible o no el botón minimizar
ubicado en la barra de título.
■ Icón. Permite indicar qué icono se debe usar como imagen representativa de la
aplicación. El icono se muestra en la barra de título en la esquina superior izquierda,
junto al menú de control.
" ControlBox. Propiedad referida al menú de control. A través de ella podemos
prescindir o no de este elemento típico de una ventana.
■ HelpButton. Botón de ayuda. Permite hacer visible este botón en la barra de título
del formulario.
ACTIVIDAD 8.2
■ Multiline. Controla si el cuadro de texto puede estar fonnado por más de una línea.
Útil cuando deseamos introducir cuadros de comentario o similar en nuestro
formulario.
■ Leave. Se produce cuando el objeto que tiene el foco deja de ser el objeto activo,
pierde el foco.
■ PropiedadChanged. Existe un conjunto de eventos que se producen cuando una
característica concreta del control es modificada, por ejemplo, CursorChanged,
EnabledChanged, etc. En PropiedadChanged, la palabra Propiedad es sustituida
por una propiedad válida del objeto tratado.
■ MouseDown. Se produce cuando se pulsa el botón del ratón sobre un control, se
refiere a la pulsación del botón izquierdo del ratón.
■ MouseUp. Se produce cuando soltamos el botón izquierdo del ratón sobre un control
determinado.
ACTIVTd^AD 8.3
Realiza un formulario como el que se muestra en la Figura 8.14. Asocia a cada botón el
código fuente y características según se indica.
pt* Forml
Tamaño dd te>3o
[ 1 Cursiva
Ver texlo
i.j Subrayado
^ Al hacer clic sobre la lista en vista de diseño veremos una pequeña flecha en la zona superior derecha
del control. Al hacer clic sobre ella encontraremos el texto Editar elementos. Este enlace visualizará un
cuadro de diálogo donde se irán insertando los elementos de la lista.
8. Casillas de verificación, sus nombres serán vNegrita, vCursiva y vSubrayado.
9. Etiqueta a la que modificaremos determinadas propiedades a través de los botones
descritos. Su nombre es IbITexto.
IblTexto.Font = new ;
Font(IblTexto.Font.FontFamily,IstTamaTexto.Selectedlndex+'F'); '•
5. IblTexto.ForeColor = Color.Red; (botón roJo) | IblTexto.ForeColor
Color.Creen; (botón verde)|IblTexto.ForeColor = Color.Blue; (Botón azul).
6. IblTexto.Visible = false;
7. IblTexto.Visible = true;
8. A cada casilla:
if (vNegrita.Checked)
{
IblTexto.Font = new Font(IblTexto.Font,
IblTexto.Font.Style | FontStyle.Bold);
El símbolo barra (|) concatena propiedades mientras que ('^) excluye propiedades.
Para vCursiva la enumeración FontStyle dispone del valor Italic, así, en lugar de escribir
FontStyle.Bold escribiremos FontStyle.Italic. En el caso de texto subrayado usaremos el valor
FontStyIe.Underline).
10. this.cióse O;
Debes realizar un nuevo proyecto, generar la vista de diseño tal y como se indica, dar
funcionalidad a la aplicación y analizar todo el proceso. Observa cada línea de código, en ellas se
modifican propiedades de controles vistas en el apartado, es importante que se entienda con
claridad cada una de las operaciones realizadas y el código fuente de la aplicación.
Capitulo 8. Entorno gráfico 335
Operando 1
Operando 2
Resultado
d][J][E EDGII
H B H BCE
LD CE CE I I
8.4.1.6. CONTENEDORES
A la hora de usar TabControI cada pestaña es considerada como una página (TabPage). Para
modificar cada página de este contenedor es preciso acceder a la propiedad TabPages y hacer
clic en el botón con el texto (...)junto a Colección.
Propiedades de tabPagel:
l|tabPage2
B m
^ Accesibilidad
0 AccessibleOescript
AccessibleName
AccessibleRole Defauh
a Aparíencta
BackColcr | |Transparent
Backgroundimage
| |(ninguno)
Backgroundlmagel Tile
BordcfStyle None
Cursor Default
h Font Microsoft Sans Serif; 8,1
ForeCoior ControIText
PJghtToLeft No
Text tabPagel
Supongamos que queremos realizar la aplicación con las siguientes características visuales:
Tíulaaón académica
Cargo en la empresa
Email corporativo
O Empleado cualificado
Figura 8.17. Pestaña Datos personales. Figura 8.18. Pestaña Datos profesionales.
8.4.1.7. MENÚS
Insertar un menú en Visual Studio es tan sencillo como acceder al cuadro de herramientas y
localizar la categoría Menús y barras de herramientas. Existen diferentes tipos:
■ ContcxtMcnuStrip. Menú contextual. Sus opciones varían en función del lugar
donde se hace clic con el botón derecho del ratón.
4. Veremos el texto Escriba aquí tal que podemos configurar directamente sobre el
componente los diferentes menús y submenús que contendrá.
Forml r^ir^ií
:;cr:';.3
Doclc [Top
10. Dock modifica la ubicación de la barra de Gripst>'ie: [w^ie "g'
herramientas, pudiéndose colocar arriba, abajo o a Editar elementos...
ambos lados.
Figura 8.26. Cuadro de tareas
11. Clic en Editar elementos para configurar los de ToolStrip.
botones de la barra.
12. Nuevamente veremos el editor de colección de elementos, usado en las opciones de la
barra de menús y otros controles en apartados anteriores. Clic sobre el primer botón y
escribiremos botonNuevo en la propiedad ñame.
13. A continuación vamos a asignar un icono al botón. Localizamos la propiedad Image
y clic sobre el botón de tres puntos (...) situado junto a ella.
14. Si hemos descargado o creado algún icono personalizado para nuestra aplicación, en
la nueva ventana solo tendremos que buscar este e incluirlo para ser asignado al
botón. Tras hacer clic en Aceptar el elemento de la barra de herramientas se verá
modificado con el nuevo elemento gráfico.
15. Realizamos la misma operación sobre el siguiente botón de la barra de herramientas.
Finalmente se visualizará como se observa en la Figura 8.27.
Archivo Ayuda
2. Clic en ContextMenuStrip.
3. Clic en cualquier zona del formulario. En la parte inferior será insertado el nuevo
control.
Por ejemplo, si queremos asociar al submenú Salir el método CloseQ; solo debemos hacer
doble che sobre el evento Click y escribir entre sus llaves thls.CloseO;
ACTIVIDAD 8.6
Normalmente crearemos aplicaciones formadas por más de un formulario. La fomia más fácil
de hacerlo es crear una nueva aplicación gráfica y a partir de ella ir agregando nuevos
formularios según vayamos necesitando como se explicó en el Apartado 8.4.1.1. AGREGAR
NUEVOS FORMULARIOS.
En este tipo de programas, uno de los formularios será considerado como el principal, siendo
el que se visualiza nada más se ejecuta la aplicación. Podemos establecer cualquier fomiulario
como principal modificando el código de la función Main en el fichero Program.cs.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormlO);
Solo debemos cambiar el nombre del objeto en la función Run. Si el fonnulario inicial debe
ser Form2, en lugar de escribir new FormlQ, escribiremos new FormlQ. Al cerrar el fonnulario
principal se dará por finalizada la aplicación.
A la hora de mostrar un formulario usaremos el método ShowQ, mientras que si deseamos
realizar la operación contraria escribiremos CIoseQ o HideO- Véase el siguiente ejemplo.
Disponemos de una aplicación con la siguiente interfaz gráfica:
Apeilldos Oreliana
Telefono
Guardar
Figura 8.29. Forml o formulario principal de la Figura 8.30. Form2. Accesible desde Forml haciendo
aplicación. menú Nueva.
Capítulo 8. Entomo gráfico 343
Para poder aeceder a los métodos desarrollados en cada fonnulario desde el resto estos deben
estar perfectamente conectados. Comunicaremos nuestros formularios del siguiente modo:
Método FormPadreO en Form2 y FormS. Previamente ambos declaran una variable de tipo
Forml: Forml padre;
public void FormPadre(Forml padre)
{
this.padre = padre;
Mediante estas líneas de código los tres formularios quedan perfectamente enlazados.
FormZ
Forml padre;
FormNueva.FormPadre(this);
FormB FormMostrar=null;
FormMostrar=new Form3();
Forml padre;
FormMostrar.FormPadre(this);
public void FormPadre(Forml padre)
{
this.padre = padre;
}
Si es la primera vez que entramos en esta opción crearemos la variable, en otro caso nos
limitaremos a mostrar el formulario.
El método CloseQ es diferente ya que elimina la referencia del objeto en memoria. Si
creamos la variable Form3 y posteriormente usamos CloseQ, necesitaremos volver a crear la
variable Form3 nuevamente antes de hacer ninguna operación sobre ella. Por eso en el menú
nuevo no se incluyen sentencias altemativas, siempre se ejecuta la línea FormMostrar = new
FormBQ;
El código de Forml podría ser similar al que se muestra a continuación.
i
public Forml()
{
/*E1 constructor del formulario crea el array de persona e inicializa
además de los componentes del formulario la variable numPersonas a
cero*/
personas = new Persona[MAX];
numPersonas = 0;
In i t ia1 izeComponent();
public Persona O I
{ I
this.nombre = ■
this.apellidos = 1
this.telefono = ;
} ' ;
this.nombre = nombre;
this.apellidos = apellidos;
this.telefono = telefono;
Capítulo 8. Entorno gráfico 347
return telefono;
telefono = valué;
this.padre = padre;
while((aux=padre[i])!=null)
{
listaPersona.Items.Add(padre[i].ToString());
this.Glose();
ACTIVIDAD 8.7
Hasta el momento hemos estado usando múltiples formularios de forma que todos ellos se
han estado mostrando de forma no modal. El uso de accesos no modales conlleva a que una vez
abierta la ventana esta pierde el foco si hacemos clic sobre otro formulario también visible.
Las ventanas no modales se abren a través del método ShowQ, mientras que los fonnularios
modales usarán el método ShowDialogQ. Cuando se realiza una llamada al método
ShowDialogO el código que sigue no se ejecutará hasta que no se haya cerrado la ventana,
además, ningún otro formulario será accesible.
Para que la ventana se cierre la propiedad DialogResult del formulario debe tener un valor
distinto de cero. Se asignan valores a esta propiedad cuando se hace clic sobre alguno de los
botones asociados al formulario. Serán estos botones los que de forma automática modifican esta
característica.
Véase un pequeño ejemplo. Hemos desarrollado una aplicación de dos formularios sencillos.
FoonJaito 2
Configuramos los botones de Fonn2 para que al ser pulsados generen un resultado válido para
el método ShovvDialog(), además de las operaciones que se codifiquen en zona de desarrollo.
1. Seleccionamos el botón Mostrar.
; } ;
ACTIVIDAD 8.8
Desarrolla xm pequeño editor de texto. Debe tener un menú con las opciones:
Archivo: Nuevo, Salir.
■ Al hacer clic en Nuevo se mostrará un nuevo formulario con un cuadro de texto
donde escribiremos este.
Fuente. Muestra un formulario donde dispondremos de la lista Tipo de letra, lista Tamaño,
lista Estilos (negrita, cursiva y subrayado) y lista Color del texto. Al cerrar el formulario el texto
del cuadro de texto activo se verá modifcado por las modificaciones realizadas en el formulario
Fuente.
Además la aplicación contará con una barra de herramientas con las opciones Nuevo, Lista
Fuente y Lista Tamaño.
Realiza un proyecto MDl bien estructurado que funcione tal como se indica.
pTrim*] ■ Propcrtwft ■
j tt5C*t»!i^ Bnárig t*rf** Coót
i
Oe<MnCle»eOp«r«tion OJT.OTí.CVOZ
en
* ' o^tv^rvnm*
*.-**>«0a'C9
•)-»04TecS<Ae«>^
UCLgr»»^ 0~*C?íí5*5}
8.4.2.3. CONTROLES
Antes de comenzar a hablar de controles Java es preciso que hablemos de las bibliotecas que
usa el lenguaje para desarrollo de Interfaces de Usuario Gráficas (GUIs). Si observamos el
cuadro de herramientas o paleta, veremos diferentes categorías, entre las que se distinguen
SWING y AVVT.
AWT (Abstract Windowing Toolkit) contempla el primer conjunto de clases que
refereneian componentes gráficos en Java, primer kit de herramientas gráficas. Swing aparece en
la versión 2.0 y mejora el aspecto de los controles y su funcionalidad. Hoy se siguen incluyendo
ambas bibliotecas ya que en determinados dispositivos o aplicaciones se hace más eficiente el
uso de una u otra.
Los controles Java equivalentes a los que hemos estudiado en Visual Studio son:
AWT SWING Visual Studio (C#)
Los primeros controles gráficos (AWT) no eran demasiado bonitos, similares a los que se
usaban en páginas web de la época en las que se incluían fonnularios. Los controles swing
mejoran el aspecto gráfico de las aplicaciones Java.
buttoni
AWT í SWING
La propiedad ButtonGroup muestra una lista de grupos de botones de opción, solo debemos
eseoger aquel al que se desea pertenezea el nuevo botón de opción.
Propiedades relacionadas eon cuadros de lista desplegable:
■ selectedIndex. Devuelve o establece la posición del elemento de la lista que debe
estar seleccionado.
desenvolverse en este IDE (Netbeans). Si bien es cierto, en Java quizas sea mas comoda la
configuración de propiedades de controles a través de código fuente, además, muchas
características no pueden ser cambiadas como no sea a través de la vista de código.
Desde la ventana de propiedades accedemos a los eventos que pueden aplicarse a cada uno de
los controles incorporados en nuestra aplicación. Para visualizar estos solo debemos hacer clic
sobre Events.
Al igual que hacíamos con las propiedades veamos las equivalencias de eventos entre los
lenguajes de programación estudiados.
Click actionPerformed
Move componentMoved
•iini
Enter
MouseDown
MouseUp
MouseHover
MouseMove
KeyDown keyPressed
KeyUp KeyReleased
ACTIVIDAD 8.9
Es interesante estudiar cómo gestiona Java los eventos, además de profundizar en la gestión
que también realiza C#. En este libro hemos estudiado tan solo el uso de eventos como
respuestas a iteraciones del usuario con nuestras aplicaciones y se usan eventos característicos
sin saber de dónde proceden.
Usa la web o documentación aportada por el profesor y realiza un pequeño documento donde
describas la gestión de eventos tanto en Java y C# así como cuál sería la codificación de una
pequeña aplicación con eventos desarrollando los listeners oportunos.
■ Los eventos en Java se denominan a partir del nombre del control que los provoca y
el evento en sí: btnConvertir (botón) ActionPerformed (Evento),
btnConvertirActionPerformed.
■ Java no soporta en sus clases la codificación de propiedades de forma que cada vez
que se debe modificar o seleccionar el valor de un atributo de una clase se deben usar
métodos modificadores o selectores. Por ejemplo, en C#, a la hora de cambiar el texto
de un cuadro de texto escribíamos cuadro.Text ya que Text era una propiedad de la
clase, en Java es necesario crear un método, así tenemos cuadro.setText(valor) y
cuadro.getTextO-
■ La converisión de tipos se realiza a través de las clases envolventes. Así, el típico
double.Parse se modifica a Double.parseDouble.
■ A la hora de escribir en un cuadro de texto usaremos el método setText al que
debemos pasar como parámetro una cadena de caracteres (variable String). En
nuestro ejemplo debemos escribir un valor numérico, así este debe ser convertido.
Para ello volvemos a hacer uso de las clases envolventes y el método toStringO-
A continuación debemos controlar que el cuadro txtEuros no este vacío ya que esto
provocaría una excepción. Para ello vamos a usar una sentencia alternativa tal que si no se ha
escrito nada en el cuadro de textos muestre un cuadro de diálogo.
C# dispone de una clase, MessageBox que genera de forma automática cuadros de diálogo de
advertencia, en Java debemos "fabricar" estos.
1. Activamos la vista de diseño del fonnulario.
En la paleta de herramientas desplegamos la categoría Swing Windows.
Clic en Dialog. A continuación haremos clic sobre cualquier zona del formulario.
Veremos que en el Navegador aparece bajo Other Components el componente
JDialog.
Cambiamos el nombre al cuadro de diálogo haciendo clic con el botón derecho del
ratón sobre él en el Navegador. El nuevo nombre será CuadroMensaje.
El formulario ha sido ocultado y en su lugar vemos un panel vacío. Para que simule
un cuadro de mensaje debemos agregar al menos una etiqueta con el texto de error a
mostrar y un botón que permita cerrarlo.
Agregamos una etiqueta a la que asignaremos el texto Debes escribir una cantidad
numérica en el cuadro euros. Podemos modificar el panel de fonna que en la
propiedad title se especifique un título al cuadro de diálogo, por ejemplo Error en la
conversión.
ACTIVIDAD 8.10
Añade a la actividad de ejemplo una nueva funcionalidad de fonna que la conversión pueda
realizarse en ambos sentidos. Si el cuadro euros está relleno se realizará la conversión a dólares.
Si el cuadro dólares está relleno, la conversión se realizará a euros. En caso de que ambos
cuadros estén vacíos o llenos se mostrará un cuadro de diálogo alertando de esta situación ya que
no se podrá realizar ninguna operación hasta que solo uno de ellos tenga un valor.
Los contenedores como ya hemos estudiado son elementos gráficos que agrupan a un
conjunto de controles. En Java encontramos dos tipos de contenedores:
■ Superiores: JFrame, JDialog y JApplet. En Netbeans se localizan en el cuadro de
herramientas bajo la categoría Swing Windows.
■ Intermedios. JPanel, JSplitPane, JscrollPane, JToolBar o JInteraalFrame. Estos se
encuentran en la categoría Swing Containers en el cuadro de herramientas^.
Los contenedores superiores pueden incluir contenedores intermedios y están diseñados para
albergar menús o barras de herramientas además de disponer un aspecto similar a ventanas del
sistema operativo (poseen barra de título, botones de acción maximizar, minimizar o cerrar y
menú de control).
A la hora de diseñar una aplicación gráfica Java debemos:
1. Crear y configurar un contenedor superior. Para ello establecemos el tamaño del
contenedor a partir del método setSizeQ o propiedad correspondiente en el cuadro de
propiedades, y posterionnente hacemos este visible (selVisibleQ) al arrancar el
programa.
■ Menú Item (JMenuIntem). Representa una opción concreta del menú que al ser
pulsada generará una acción. Encontraremos varios tipos de menús finales. Menú
Item CheckBox (JCheckBoxMenuItem) y Menú Item RadioButton
(JRadioButtonMenuItem).
y Capítulo 8. Entorno gráfico
jusb&caoo p-
l^bniefiús(Ménu)
Menú ttpo boton de
opción(Menú
iift il: tadioButton) 7
6. De los dos nuevos menús a agregar, uno de ellos cuenta con submenús y el otro
no, para añadir el menú que contiene más ítems haremos clic en Menú y a
continuación clic en la barra de menús. Veremos el nuevo elemento con el nombre
jMenu3, modificamos este por Fuente. Repetiremos la operación y añadiremos el
último componente de nuestra barra. Lo llamaremos Ayuda.
7. A continuación pasamos a ir configurando las opciones internas de cada menú.
Usaremos Menú Item de forma que el proceso será repetitivo pero no
complicado. Clic en Menú Item, colocamos el cursor sobre archivo y al visualizar
este con un recuadro punteado y anaranjado volvemos a hacer clic. Acabamos de
asignar un submenú al menú Archivo. Lo llamaremos Nuevo.
8. Repetiremos el punto 7 hasta completar el menú de la aplicación, tal que:
■ Archivo contiene los submenús: Nuevo y Salir.
■ Editar contiene los submenús: Cortar, Copiar, Pegar y Seleccionar todo.
■ Fuente contiene los submenús: Tipo de letra. Tamaño de Letra y Estilo.
■ Ayuda no contiene submenús.
9. Sería interesante modificar los nombres de las variables que representan cada
elemento de la barra de menús. Podríamos haber realizado esta operación al
mismo tiempo que hemos ido insertando un nuevo menú. Recordamos que
debemos hacerlo a través del navegador de objetos. Para el ejemplo se ha llamado
a cada menú de igual modo que el texto que visualizan.
10. El navegador de objetos se muestra tal y como se observa en la Figura 8.41.
;iMenu4[jfjenu]-Navigator a I B j^ Agregamos adeiuás uua pequeña barra de
heiTamientas en la que incluiremos los botones
9 BJfarne] guardar, cortar, copiar y pegar. Clic en Swlng
barraMenus [J-lenuBar] ® . •' t* i t»
0-^ Ardiwo [JMenu] Containers y a continuación Tool Bar.
• Nuevo [JJ4enuItem]
-[—"i Salir [3MenuItem] 12. Clic en el formulario. El contenedor no se ajusta
automáticamente ni en tamaño ni posición de forma
1
- Copiar [JMenuItem]
- p-"| Pegar [JMenuItem] que
^ debemos moverlo
i• • a 1 la zona superior y
; a íj Fuente [jMenii] posteríoimente redimonsionario.
'F1 TipoLeIra [Jlteiultetn] ^ .
; - TamaLeíra [JI4enuItem] 13. Clic en Swing Controls y Button. Seguidamente clic
s ^1 en el contenedor ToolBar que acabamos de añadir.
Aparece el primer botón de nuestra barra.
14. Modificamos el botón para que se muestre un icono''.
Clic en él y localizamos la propiedad ¡con. Pulsamos
Figura 8.41. Navegador de objetos , botón oara seleccionar el icono asociado. Este será
del formulario con la barra de menús ,, , ^ ,
configurada. el boton guardar.
"Es preciso que dispongamos de una serie de icono para agregar a nuestra aplicación. Los que vamos a
usar son los tipicos de guardar, cortar, copiar y pegar.
Capítulo 8. Entorno gráfico 363
Borramos el texto de la propiedad Text para que solo sea visible la imagen sobre él.
15. Agregamos los tres botones restantes cambiando su aspecto como en el ptmto 14.
Los botones referencian las órdenes de cortar, copiar y pegar.
16. Cuando el usuario haga clic en el menú Nuevo debe mostrarse un panel^ en el que
incluiremos un Text Area. Clic en Swing Containers y Panel. A continuación clic
en el formulario. Redimensionamos el panel para que ocupe toda la zona
disponible de la ventana.
1 7. Insertamos en Text Area en el Panel. Igualmente redimensionamos este para que
ocupe todo el panel.
18. Desde el menú Fuente vamos a poder cambiar características de la letra.
Agregaremos tres cuadros de diálogo que se mostrarán al seleccionar una u otra
opción del menú.
19. Para insertar un nuevo cuadro de diálogo clic en Swing Windows y a
continuación en Dialog. El proceso de creación de im cuadro de diálogo ya se ha
explicado de forma que en función de la información que ya tenemos del proceso
vamos a desarrollar los cuadros tal que se visualicen del siguiente modo:
Tamauo Estilo
Tipo de letra
|Arial rn Negrita
jrimes New Román
Courier New []]Cursiva
Comic Sans
Verdaña n Subrayada
Aceptar
Aceptar
20. Llegados a este punto damos por finalizada la interfaz gráfica. Comenzamos a
codificar cada una de las opciones. Básicamente usaremos métodos que permitan
hacer visibles cuadros de diálogo y paneles (setVisible) y modificaremos las
características de nuestro texto.
21. Para asociar el evento click a cada elemento del menú sólo debemos hacer doble
clic sobre él. En caso de necesitar otro evento usaremos el cuadro de propiedades
tras activar Event.
~ ...... — - — - —... 1
^ Utilizaremos paneles para ver su funcionalidad aunque podría usarse Frame o Infernal Erame y así
generaríamos una interfaz MDI.
//Código menú Archivo Nuevo
PanelNuevo.setVisible(true);
//Código del menú Editar -> Copiar y botón copiar de la barra de herramientas
texto=jTextAreal.getSelectedText();
//Código del menú Editar -> Pegar y botón pegar de la barra de herramientas
jTextAreal.replaceSelection(texto);
/*Ya que solo cambiaremos la letra y usaremos el objeto Font debemos mantener
el tamaño y el estilo*/
int tama=jTextAreal.getFont().getSizeO;
int estilo=jTextAreal.getFont().getStyleO;
String letra="";
//La nueva letra será la seleccionada de entre los elementos de la lista
String letra=jListl.getSelectedValue ().toStringO;
jTextAreal.setFont(new Font(letra,estilo,tama));
DialogoLetra.dispose();
//Botón Aceptar del cuadro de diálogo Tamaño de letra
int tama=Integer.parseint(jComboBoxl.getSelectedItem().toString());
int estilo=jTextAreal.getFont().getStyle();
String letra=jTextAreal.getFont().getFontName();
jTextAreal.setFont(new Font(letra,estilo,tama));
DialogoTama.dispose();
ACTIVIDAD 8.11
Finaliza el editor de texto escribiendo el código para el botón Aceptar del cuadro de diálogo
Estilos.
ACTIVIDAD 8.12
Nuestro editor puede optimizarse. Configurarlo de forma que los menús estén habilitados o no
en función del momento de ejecución en el que nos encontremos. Por ejemplo, si aún no se ha
i Capitulo 8. Entorno gráfico 365
pulsado el botón Nuevo y no tenemos un cuadro de texto en pantalla no podemos hacer clic en
ninguna de las opeiones de los menús Editar y Fuente.
ACTIVIDAD 8.13
Mejora la aplicación de fomia que añadas un nuevo submenú a Archivo. Este se denominará
Guardar. Usa un array de objetos que almacene los textos creados. Para ello, cada vez que se
pulse Archivo -> Nuevo se debe comprobar si existe un documento escrito y si se desea guardar
este. Agregar además un submenú Cerrar al menú Archivo tal que al hacer clic sobre él se cierre
el panel acti\ o y se pregunte al usuario si se desea almacenar el texto.
Sabías que...
Los entornos de desarrollo Visual Studio y Netbeans proporcionan atajos al
programador para facilitar su trabajo a la hora de picar código. Si hacemos clic con el
botón derecho del ratón sobre cualquier zona de la vista de código en Netbeans veremos
el menú Inserí Cede... Este permite generar código deforma automática:
II Si hacemos clic en Constructor el IDE generará
Generate
COMPRUEBA TU APRENDIZAJE
1. ¿En qué consiste la programación dependiente de eventos?
2. ¿Qué entiendes por formulario? ¿Y control?
3. Define evento.
ACTIVIDADES DE AMPLIACION
1. Busca información en la web o bibliografía aportada por el profesor en la que
se explique cómo desarrollar aplicaciones MDI en Java. Crea una pequeña
aplicación en la que al menos dispongas de un formulario padre y un
formulario hijo.
2. Crea una pequeña aplicación gráfica en Java tal que veamos la pantalla
dividida en dos zonas. En la superior veremos opciones relacionadas con
características de ordenadores, por ejemplo, cuadro de lista para escoger el tipo
de microprocesador, botones de opción para poder escoger el tipo de memoria
RAM del PC, capacidad de disco, etc. En esta veremos un botón de añadir de
forma que al hacer clic sobre él crearemos un objeto llamado PC con las
características establecidas (usar la clase Equipo creada en la Actividad de
Ampliación 11 del Capítulo 7). En la otra zona encontraremos los botones de
Añadir, Eliminar y modificar (usaremos la clase LlstaEquipos de la Actividad
de Ampliación 12 del Capítulo 7).
3. Desarrolla el Editor de ejemplo visto en el capítulo usando C#. Mejora su
funcionalidad agregando más funciones al editor.
4. Crea una aplicación en C# tal que incluyamos en ella tres clases llamadas
Triángulo, Rectángulo y Circulo. La aplicación estará compuesta por tres
botones con los textos epecificados relacionados con cada una de las figuras
geométricas. Cada vez que se pulse uno de los botones debemos mostrar en
pantalla el objeto en una posición aleatoria.
5. Usar la clase persona creada en la Actividad de Ampliación 8 del Capítulo 7,
ampliar esta de forma que almacene sexo, dirección, código postal, provincia y
población. Desarrollar un entorno gráfico en C# tal que permita dar valores e
instanciar tantas personas como se desee (usaremos un array de personas para
almacenar estas). La interfaz debe estar formada por un menú con las opciones
nueva, guardar y mostrar. Al hacer clic sobre nueva se verá una nueva
ventana tal que en ella se incluyan los controles necesarios para recoger
Capítulo 8. Entorno gráfico 367
HERENCIA,POLIMORFISMO E INTEREACES
CONTENIDOS OBJETIVOS
9.1. INTRODUCCIÓN
Hasta ahora hemos introducido la programación orientada a objetos y sus conceptos
esenciales, de forma que sabemos qué es una clase, las partes que la forman, y hemos estudiado
peculiaridades además de usado diferentes tipos de clases e instancias de estas.
En este capítulo seguimos estudiando conceptos fundamentales de la programación orientada
a objetos como son la herencia y el polimorfismo. Además, comenzaremos definiendo los
conceptos de paquete y espacio de nombre que se han ido usando a lo largo del libro pero no se
han presentado formalmente.
namespace espaciof
Tipojiatol
Tipo_daton;
class Pelicula{
class Socios{
class Proveedores{
Debido a que podemos estructurar los espacios de nombres tal que podemos declarar unos
dentro de otros, en ocasiones, el acceso a un tipo es una tarea algo tediosa, ya que debemos
escribir todos los espacios hasta llegar al tipo concreto:
espacio 1.espacio l_l.espaciol_12.tipo.método.
Si tux iéramos que escribir esta línea repetida veces modificando el método a usar en cada
una, configuraríamos un código fuente dificil de leer y complejo. Para evitar esto, C# utiliza la
palabra reservada using seguida del nombre de espacio: using namespace; de forma que
podemos usar todos los tipos incluidos en él sin necesidad de estar escribiendo este
continuamente.
Agregaremos a nuestro código tantas sentencias using como espacios de nombre queramos
usar. Estas se colocarán nonnalmente al comienzo del fichero para evitar posibles errores.
A la hora de usar using debemos prestar especial atención a la casuística de que en dos
espacios incluidos en un programa se defina un tipo con el mismo nombre, por ejemplo,
imaginemos que tenemos los espacios de nombre espacio_A y espacio_B y en ambos tengamos
declarada una clase llamada Dato. ¿Qué ocurriría si declaráramos una variable de tipo Dato en
nuestro código?
using espacio_A; \
using espacio_B; I
t
I
Dato var; I
En este caso, tal y como se ha planteado el código, el compilador no sabría si la variable tipo
Dato referencia a la clase Dato de espacio_A o espacio_B. Así, es necesario escribir el nombre
completo de acceso al tipo: espacio_A.Dato var o espacio_B.Dato var.
C# nos pemiite la creación de alias para estos casos, tal que podemos dar im pseudo-nombre a
una de las clases Dato en uno de los espacios de nombres y así pueda ser perfectamente
identificada.
i using alias=nombre_completo_deljipo;
using espacio_A;
using espacio_B;
using Dato_A=espacio_A.Dato;
namespace espacio C{
class Tipo{
Dato A var;
9.2.2. PAQUETES
En Java los paquetes al igual que espacios de nombre se encargan de agaipar clases. Si
observamos el directorio donde se almacena nuestro proyecto en Netbeans veremos en la carpeta
src una subcarpeta por cada paquete creado.
Indicamos que una clase pertenece a un paquete a través de la palabra reservada package al
comienzo de la clase.
package nombre_del_paquete; i
En Java un paquete puede contener subpaquetes estableciéndose una estructura jerárquica a la
que se accede nuevamente a través del operador punto. Así, si necesitamos incluir una clase de
un paquete concreto indicaremos el nombre de este seguido de la clase separadas ambas partes
por el símbolo punto.
nombre_paquete.clase i
Al igual que ocurría con los espacios de nombres, cuando usamos paquetes podemos declarar
tipos con el mismo nombre pertenecientes a diferentes paquetes, solo debemos tener precaución a
la hora de usarlos.
Para facilitar el acceso a los tipos de datos declarados en un paquete usamos la sentencia
import justo después del nombre del paquete, import permite incluir en nuestro proyecto una
clase concreta o todas las clases pertenecientes a un paquete en función de la forma en que
usemos la palabra reservada.
import nombre_paquete.tipo_dato;(1)
import nombre paquete.*;(2)
■ En la primera sentencia (1), agregamos solo el tipo de datos con el nombre tipo_dato.
■ En la segunda sentencia (2), agregamos todos los tipos de datos declarados en el
paquete con el nombre nombrejpaquete.
; package ejemplo; ;
; iirport System.io.*; //Importamos todas las clases de io incluido en System. ;
import java.net.Socket; //Importamos solo la clase Socket incluida en net. j
En Netbeans agregamos paquetes con facilidad siguiendo los pasos que se indican a
continuación:
1. En el explorador de proyectos clic con el botón derecho del ratón sobre el proyecto al
que queramos agregar el nuevo paquete.
2. En el menú contextual, clic en New y a continuación Java Package.
3. Escribimos el nombre del paquete y clic en Finish.
El nuevo paquete se muestra de color gris ya que aún no contiene ningún tipo.
fonna de andar, etc., una clase, se dice que hereda de otra cuando adquiere de forma
implícita características (color de ojos) y métodos (gestos, forma de andar) de esta. La
herencia pemiite jerarquizar nuestro grupo de clases y aprovechar propiedades y
métodos sin tener que volver a crearlas o implementarlas.
■ Polimorfismo. El paso del mismo mensaje a varias clases da como resultado
diferentes respuestas. Básicamente así podemos definir polimorfismo, imaginemos
varias clases que disponen de un método con el mismo nombre, cada método realiza
una función diferente aunque se llamen igual. Si ejecutamos el método de una clase
este dará una respuesta diferente que si la ejecución se produce desde otra clase. El
polimorfismo cobra gran importancia si se une a la herencia, en los siguientes
apartados entenderemos por qué.
9.3.1. HERENCIA
Cuando estudiamos la herencia debemos distinguir entre dos tipos de clases: clases base y
clases derivadas.
Supongamos que nos piden el desarrollo de im software para una empresa en la que trabajan
diferentes tipos de empleados, podríamos establecer el esquema que se muestra en la Figura 9.3.
La empresa tiene dados de alta a ima serie de empleados, todos ellos tienen en común que poseen
un nombre, un DNI, apellidos y un sueldo base, así, se ha creado ima clase llamada Empleados
que englobe todas esas características comunes a todos los empleados de la empresa.
A continuación, la empresa está formada por empleados con titulación que trabajan en
diferentes departamentos (contabilidad, infonnática, administración, etc.), y empleados sin
titulación que trabajan a pie de calle en plena obra. Por este motivo hemos creado una clase
llamada Cualificados y otra Obreros. Además, cada departamento dispone de un Jefe de
departamento que también debe ser teniendo en cuenta como clase independiente ya que posee
propiedades y funciones añadidas, así tendremos la clase JefeDepartamento.
A la hora de afrontar un problema de este tipo siempre debemos buscar similitudes,
propiedades y métodos similares de forma que vayamos agrupando estos y formando ciases base
o derivadas.
Empleados
- Nombre
-Apellidos
-Sueldo base
<-Dm j
Cualificados Obreros
-Titulación -DestinoTrabajo
- Plus - Horas extra
• Departamento - Precio hora extra
JefePepartamento
-TotaITra baja doresACa rgo
- Proyectos
)
Figura 9.3. Esquema de clases del software de una empresa.
La sintaxis básica de definición de herencia es la siguiente:
c# Java ;
class Base{ ciass Base{ ;
} } i
class Derivada:Base{ class Derivada exíends Base{ ;
\l... } j
Usamos el símbolo dos puntos (:) para Usamos la palabra reservada extends para
establecer la herencia con una clase base. establecer la relación de herencia.
Debemos tener en cuenta que:
■ Una clase derivada solo puede accede a los miembros publíc y protected de la clase
base, los miembros prívate nunca son accesibles, al menos de forma directa, ya que
sí podremos acceder a ellos a través de métodos públicos o protegidos que los usen.
■ La clase derivada incluirá los miembros definidos en la clase base.
Según esto, nuestra definición de clases para las clases definidas en la Figura 9.3 será la
siguiente:
c# ; Java
class Empleados{ 1 class Empleados{
string nombre, apellidos; ¡ String nombre, apellidos;
; doiíble sueldoBase;
double sueldoBase;
String DNI;
string DNI;
i }
Capítulo 9. Herencia, polimorfismo e ¡nterfaces
class JefeDepartamento
class Je fe Departamento:Cualificados{ extends Cualificados {
int totalTrabajadoresACargo; int totalTrabajadoresACargo;
string []proyectos; String []proyectos;
double plus; double plus;
ACTIVIDAD 9.1
Cuando una clase hereda de otra esta adquiere los atributos de la clase base y estos deben ser
inicializados. Si los atributos de la clase base son privados no son accesibles desde la clase que
hereda pero sí de algún modo podemos hacer un llamamiento a estos a través de sus métodos
constructores.
Así, a la hora de crear el constructor de una clase derivada realizamos una llamada al
constructor de la clase base, esto no es necesario cuando la clase padre no cuenta con
constructores o usa el constructor por defecto. Resumiendo:
■ Cuando declaremos una instancia de la clase derivada se llamará de forma automática
al constructor de la clase base.
■ Si la clase base tiene definido un constructor es necesario que la clase derivada haga
referencia a este en su constructor.
constructor :
class Empleados!
string nombre, apellidos;
double sueldoBase;
string DNI;
class Base{
tipo atributol;
tipo atributol;
class Derivada:Base{
tipo atributoS;
class Cualificados:Empleados{
string titulación;
double plus;
string departamento;
this.departamento=dep;
class Base{
tipo atributo1;
tipo atribiitoZ;
class Derivada:Base{
tipo atributo3;
En los ejemplos observamos que usamos la palabra reservada base en C# para hacer
referencia al constructor de la superclase mientras que en Java usamos la palabra reservada
super. C# sigue en este aspecto la sintaxis usada por C-H-. En ambos lenguajes, al hacer la
llamada al constructor de la clase base se pasa como parámetros las variables anteriormente
definidas en la cabecera del método (parámetros del constmctor que deriva). Además, usamos
tantos parámetros como variables necesitemos inicializar contando clase base y clase derivada.
A la hora de establecer jerarquías en la que prima la herencia, es posible realizar asignaciones
entre clases base y derivada. Esto es muy útil combinado con la implementación del
polimorfismo. Así, cuando comencemos a instanciar las diferentes clases podemos asignar a una
clase base cualquiera de sus clases hijas, no al contrario.
Empleados empleado;
Cualificados maria=new Cualificados("maria"
,"Pérez",1000.00,"44.233.350","Técnico informática".
500, "informática");
empleado=maria;
class Cualificados:Empleados{
string titulación;
double plus;
®tring departamento;
En el ejemplo la clase Cuah'fícádos hereda de Empleados y tanto una como otra definen un
método llamado InformacionQ, más correctamente podemos decir que la clase Empleados
redefíne el método Información y oculta este método en la clase Empleados de forma que cuando
realicemos la llamada al método desde una instancia de Cualificados se ejecutará el código de
esta misma clase y no el definido en Empleados.
Capítulo 9. Herencia, polimorfismo e Interfaces
Si queremos acceder desde la clase derivada a alguno de los métodos ocultos debemos
hacerlo mediante el uso de la palabra reservada base en C# o super en Java. Así, si quisiéramos
usar los datos que devuelve el método InformacionQ en la clase Empleados:
class Empleados{
class Empleados!
Empleados aux=maria;
aux.Informacion O ; /*En C# Ejecuta el método información de la clase base, ya
que aunque al objeto aux se le tiaya asignado maria de tipo
Cualificados el objeto es de tipo Empleados. Si
codificáramos el problema en Java ejecutarla el método de
la clase Cualificados.*/
NOTA: Aunque es opcional en C# se usa la palabra new delante de los miembros
redefínidos:
Como ya hemos estudiado, podemos crear clases que deriven unas de otras y realizar
asignaciones entre ellas, es decir, podemos crear una instancia de la clase base y asignar a esta
una instancia de una clase derivada. Esto es interesante cuando necesitamos mantener gran
cantidad de objetos de forma que podemos crear un array de la clase base y asignar a cada casilla
un objeto de la clase derivada que deseemos.
Empleados []listaEmpleados=new Empleados[100]; •
listaEmpleados[0]=new Cualificados (...) ; j
listaEmpleados[1]=new Obreros (...) ; ;
listaEmpleados[2]=new Obreros (...) ; ;
/*Creamos un objeto auxiliar del tipo que queremos comprobar y realizamos una
conversión mediante as: convertimos listaEmpleados[O] al tipo de datos
Cualificados si es posible y asignamos el resultado a aux. Si se produce fallo
ya que listaEmpleados[O] puede no ser un objeto de Cualificados, aux será
igual a nuil, en otro caso aux recogerá el objeto Cualificados concreto*/
Cualificados aux=listaEmpleados[O] as Cualificados;
if(aux!=null){
Consolé.WriteLine("¿A qué departamento perteneces?")y }
Capítulo 9. Herencia, polimorfismo e interfaces
ACTIVIDAD 9.2
Crea un pequeño programa que use la jerarquía de clases definida en la Actividad 9.1 de
fonna que manten un array de FigurasGeométricas al que vayas asignando las diferentes figuras
representadas por las clases Rectángulo, Círculo, Rombo y Triángulo. Incluye una función que se
encargue de contar el número de figuras geométricas de cada tipo incluidas en el array, la salida
de este método podría ser:
2 Círculos; 1 Triángulo; 4 Rombos; 10 Rectángulos
9.3.2. POLIMORFISMO
■ Al definir un método de igual modo en una clase derivada y una clase base, el método
de la clase base se oculta, de modo que cuando un objeto de la clase derivada usaba el
método siempre se hacía referencia a su método redefinido y no al de la clase base.
Para conseguir que en tiempo de ejecución en C# se ejecuten las fimciones propias del objeto
asignado debemos usar las llamadas funciones virtuales.
NOTA: En C# es obligatoria la definición de funciones virtuales mientras que en Java
toda función que se sobrescribe o se redefine es tomada como virtual. Normalmente,justo
antes de la definición de una función redefinida en Java en una clase derivada
encontraremos el texto @override. Este es indicativo y se usa para comunicar al
compilador que el método que sigue sobrescribe un método de la clase base de forma que
si a la hora de definirlo se ha producido algún error léxico el compilador lance un fallo de
compilación. Si no se especifica @override no se lanzarán fallos de compilación en caso
de errores en la definición y será tomado como otro método de la clase.
Obreros
Cualificados
Cualificados
Obreros
Figura 9.4. Representación gráfica de un array de Empleados en C# al que asignamos a cada casilla un
objeto de la clase derivada. Hasta el momento, tal y como hemos definido los métodos a la hora de
ejecutar la función lnformacion() en cada casilla se ejecutará la definición dada en Empleados y no en cada
objeto derivado.
Para definir en C# una función de la clase base como virtual será necesario incluir la palabra
virtual en su cabecera, mientras que en las funciones de las clases derivadas redefinidas
antepondremos la palabra reservada override. Aunque es obvio decir que es necesario que los
métodos definidos como virtuales deben ser a su vez públicos.
class Base{
class Derivada:Base{
class Empleados{
NOTA: El orden de las palabras virtual y override puede alterarse con respecto a la
palabra public. Así, es igual escribir virtual public / override public que public virtual
/ public override.
class Base{
@Override
public String Información() {
return "Titulación: "+this . titulaciont
" Departamento:"+this.departamento;
Al usar la palabra virtual en C# cuando definimos una estructura de datos de tipo Empleados
(clase base) a la que asignamos objetos de tipo Cualificados u Obreros (clases derivadas) la
ejecución del método InformacionQ referirá al método correspondiente a la clase asignada en
cada momento y será en tiempo de ejecución cuando el compilador decida qué método debe
utilizar. Recordamos que en Java el proceso se realiza de forma automática ya que la redefinición
lleva implícito el concepto de virtualización.
ACTIVIDAD 9.3
Agrega a las clases definidas en la Actividad 9.1 un método llamado arca() tal que calcule el
área de cada figura geométrica. Modifica el programa diseñado en la Actividad 9.2 de fomia que
además muestre por pantalla el área de cada una de las figuras geométricas almacenadas en el
array.
Empleados []listaEmpleados;
Cualificados []listaEmpleados,•
Obreros []listaEmpleados;
Sin embargo, si creamos una estructura de clases jerárquica en la que tenemos una clase base
y otras clases derivadas que heredan de esta, podemos crear un array de la clase base y
posteriormente asignar a cada casilla un objeto de la clase derivada, de forma que indirectamente
estamos construyendo un array de diferentes tipos de datos: Empleados, Cualificados y Obreros:
i Empleados []listaEmpleados=new Empleados[10]; j
I listaEmpleados[O]=new Cualificados (...) ; '
listaEmpleados[1]=new Obreros (...); i
En ocasiones, la clase Base apenas contiene información, y se usa básieamente para poder
crear las estructuras que acabamos de explicar, de forma que no es necesario instanciar esta, ya
que se diseña principalmente para agrupar a un conjunto de clases.
Estas clases base, que no necesitan ser instanciadas se declaran como clases abstractas.
Cuando definimos una clase abstracta:
" No podremos crear instancias de la clase.
■ Una clase abstracta puede contener descriptores de acceso (en C#, get y set) y
métodos abstractos.
■ Las clases derivadas de clases abstractas deben incluir la implementación de todos los
métodos abstractos heredados y descriptores(en C#).
Para definir una clase como abstracta usamos la palabra reservada abstract tanto en Java
como C#.
C# : Java !
i
} i
Capitulo 9. Herencia, polimorfismo e interfaces 385
Como hemos comentado, además de clases abstractas podemos definir métodos abstractos.
Un método abstracto sólo puede incluirse en clases que a su vez son abstractas y es
implícitamente un método virtual.
Al igual que las clases abstractas no penniten la instanciación de objetos, un método abstracto
no permite la inclusión de código en él, es decir, son métodos que no contienen cuerpo ya que
están destinados para ser implementados en las clases derivadas. Así, a la hora de declarar un
método abstracto en una clase abstracta será definido del siguiente modo:
class Derivada:Base{
@override
public tipo nombrejnétodo(parámetros){
//Código Java
abstract class Empleados{
@override
public string Información()
{
return "Titulación:" + this.titulación +
" Departamento:" + this.departamento;
ACTIVIDAD 9.4
Modifica las clases creadas en la Actividad 9.1 de fonna que la clase base sea abstracta.
Además, el método area() añadido en la Actividad 9.3 también debe ser abstracto.
9.5. INTERFACES
Una interfaz es una definición de un conjunto de métodos para los que no se realiza
implementación, es similar a una clase abstracta compuesta exclusivamente de métodos
abstractos.
Una clase puede implementar una o varias interfaces. La implementación de una interfaz
consiste en el desarrollo de los métodos definidos en la interfaz.
En muchas ocasiones se usan interfaces para de algún modo representar herencia múltiple en
nuestros programas ya que lenguajes como C# y Java no la soportan. La sintaxis para la creación
de interfaces es similar en C# y Java:
modificador ínterface nombre{
tipo nombre(parámetros);
tipo nombre_2(parámetros);
Además es posible la herencia entre interfaz de forma que podemos disponer de interfaces
base e interfaces derivadas. La definición de herencia para interfaces es similar a la vista para
clase con la diferencia de la palabra reservada interface.
C# .... J
modificador interface¡Derivada:IBase{
}
Java
Supongamos que nuestra empresa emplea a personas que aún están estudiando, becarios, tal
que nuestro esquema de clases se mostraría como en la Figura 9.5.
Estudiantes Empleados
ExamenesO - Nombre
Universidad!) -Apellidos
NotaMediaPracticasO -Sueldo base
-DNl
JefeDepartarnento
-TotalTrabajadoresACargo
- Proyectos
- Plus
0Override
public void Examenes O{
System.out.println("Los exámenes debido a las prácticas
comenzarán el 15 de septiembre");
}
0Override
public void UniversidadO {
if (this.departamento.compareTo("Informática")==0) {
System.out.println("Universidad de la Rabida");
else if(this.departamento.compareTo("Recursos Humanos")==0) {
System.out.println("Universidad de la Merced");
else{
System.out.println("Universidad del Carmen");
0Override
double NotaMediaPracticas(double []notas) {
double resultado=0.0;
/*Se definen tres notas para el alumno: adquisición de conceptos
teóricos, prácticos y proyectos*/
for (int i=0;i<3;i++){
resultado+=notas[i];
}
return resultado;
Capítulo 9. Herencia, poUmorfismo e Interfaces 389
A la hora de definir una interfaz podemos usar como nombre cualquier identificador válido.
Se aconseja para diferencias clases e interfaces, comenzar estas últimas con la letra I seguida del
nombre de interfaz que deseemos.
En C# el código será bastante similar a diferencia de la sintaxis del lenguaje:
interface lEstudiantes í
l i
public void Examenes O; ¡
public void Universidad O ; 1
public double NotaMediaPracticas(double[] notas); I
) i
class Empleados I
{ i
string nombre; ;
string apellidos; 1
double sueldo; ¡
string DNI; '
pxiblic Empleados(string nom, string apell, double sueldo, string DNI) 1
this.nombre = nom;
this.apellidos = apell;
this.sueldo = sueldo;
this.DNI=DNI;
)
}
class Becarios : Empleados, lEstudiantes
{
string carrera;
int curso;
string departamento;
this.carrera=carrera;
this.curso=curso;
this.departamento=dep;
}
COMPRUEBA TU APRENDIZAJE
1. ¿Qué es un espacio de nombres?
2. ¿Qué elementos podemos incluir en un espacio de nombres? ¿Cómo usamos un espacio
de nombres? ¿Y un paquete?
3. ¿Qué entiendes por herencia? ¿Qué diferencia existe entre una clase base y una clase
derivada? ¿Qué tipos de herencia hemos contemplado en el capítulo?
4. ¿Cómo se deben tratar los constructores cuando una clase deriva de otra que tiene
implementado un constructor con parámetros? Pon ejemplos en Java y C#.
5. ¿Qué es la redefmición de métodos?
6. ¿Para qué se usan los operadores is, as e instanceof?
7. Define polimorfismo. ¿Para qué se crean métodos virtuales en C#?
8. ¿Qué es una clase abstracta? ¿Cuáles son sus características?
9. ¿Qué entiendes por interfaz? ¿Cuál es su utilidad?
10. ¿Qué utilidad encontramos en el uso de clases abstractas si además se crean métodos
virtuales?
ACTIVIDADES DE AMPLIACION
1. Desarrolla el siguiente diagrama de clases tanto en Java como C#. Configura cada clase
en función de las características reales de cada objeto. Incluye todos los componentes en
un espacio de nombre y paquete denominado seres.
4. Configura un método denominado seAlimenta() en cada clase tal que devuelva una
cadena de caracteres donde se indique el tipo básico de alimentación de cada ser vivo.
5. Crea una estructura de clases similar a la que se muestra en la Figura 9.7. Configúrense
propiedades y métodos, como desee el lector.
6. Desarrolla una aplicación gráfica que use las clases creadas en la Actividad 5. La
aplicación debe ser MDI, disponer de un menú y opciones que visualizarán formularios
para:
■ Añadir productos.
■ Modificar productos existentes.
■ Abrir una cuenta corriente.
7. Imagina que tienes que iinplementar una aplicación para un videoclub. En él tendremos
películas y música. Los dos tipos de elementos que se pueden alquilar tienen en común
una serie de características, como número identificativo, precio, etc. Desarrolla un
diagrama de clases que se ajuste a las necesidades del negocio que se quiere informatizar.
Siempre atender a la realidad, a fin de cuentas se pretende captar esta.
8. Crea una interfaz gráfica para usar las clases creadas en la Actividad 7. El objetivo es
desarrollar una aplicación que pennita gestionar el videoclub teniendo en cuenta todas las
actividades que en él se realizan.
9. Dada la siguiente implementación el programa da error, ¿por qué? Justifica tu respuesta.
abstrae class Vehículos{
10. Crea una clase llamada alumno y haz que esta implemente el método coinpareTo() de la
interfaz Comparable en Java tal que puedan compararse dos alumnos. A la hora de
comprobar si dos alumnos son iguales se tienen en cuenta su nombre y apellidos tal que
devolvemos -1 si alfabéticamente el nombre y apellidos está antes del nombre y apellidos
que realiza la comparación, O si son iguales y 1 si es mayor.
11. Crea una interfaz denominada sonidos. En ella tendremos un método llamado
sonidoProducidoQ- La función sonidoProducido devuelve una cadena de caracteres con el
sonido que realiza un objeto concreto. Crea una estructura de clases ta! que se disponga
de una superclase llamada IntrumentosMusicales de la que derivan InstrumentosViento e
InstrumentoPercusion. Haz que las clases implementen la interfaz sonidos.
12. Desarrolla un esquema de clases tal que dispongas de una superclase llamada Animal de
la que deriven perro y gato. Haz que las clases implemente la interfaz realizada en la
Actividad 11.
CAPITULO 10
CONTENIDOS OBJETIVOS
Llegados a este punto hemos estudiado la gran mayoría de elementos que fonnan
programas estructurados u orientados a objetos. Parece oportuno que en este Capítulo se
estudien los flujos de E/S que permitan al menos almacenar la información usada en
nuestras aplicaciones, además de la gestión de errores en tiempo de ejecución.
10.1. INTRODUCCION
Hasta ahora hemos estado usando estructuras de datos, variables, ciases y hemos estado
manipulando información que una vez finalizada la ejecución del software desaparece de
memoria, ya que esta es almacenada en memoria principal durante el tiempo que se está
ejecutando el programa.
Llegados a este punto se hace necesario el estudio de nuevas estructuras o métodos que nos
permitan conseguir que la información no se volatilice, siendo almacenada en dispositivos de
almacenamiento secundario tales como discos duros extemos o internos, memorias USB, etc.
Así, en este capítulo vamos a estudiar las clases que se usan tanto en C# como en Java para la
gestión de ficheros, el control de los errores que estos lenguajes mantienen durante el proceso de
lectura/escritura u otros procesos, así como otros tipos de flujos de entrada/salida de información.
Registros
I Cinta Cumbreras
Campos [
Figura 10.1. Estructura de un fichero organizado en registros que guardan información reiativa a número
de orden, nombre y primer apellido.
■ Aleatoria o directa.
■ Secuencial indexada.
En los ficheros secuenciales los registros ocupan posiciones consecutivas y solo es posible
acceder a ellos comenzando desde el principio y recorriendo estos de uno en uno.
Además, solo es posible realizar una operación de lectura o escritura a la vez, es decir, cuando
el fichero está siendo leído no es posible realizar una operación de escritura así como cuando el
fichero está siendo escrito no puede llevarse a cabo ninguna operación de lectura.
Las actualizaciones de este tipo de ficheros se realizan mediante la creación de nuevos en los
que se incluyen los registros existentes más las actualizaciones. Véase la Figura 10.2.
Para leer el Registro N antes debe haber recorrido y leído
los N-1 registros anteriores
Posición de lectura
Posición de escritura
Este tipo de ficheros se caracterizan por la rapidez con la que se accede a los datos.
Posición de
lectura/escritura
En este tipo de ficheros cada registro es identificado de manera única a partir de un campo
llamado campo clave. Estos campos se utilizan para formar índices que relacionan campo clave
con posición del registro en el fichero.
Este tipo de organización permite el acceso secuencial y aleatorio al fichero, tal que:
■ En primer lugar se busca de forma secuencial el campo clave del registro que se
necesita.
Capitulólo. Flujos de Entrada/Salida y control de excepciones 397
■ Cuando se conoce el campo clave del registro, el acceso a este es directo, ya que solo
tenemos que acceder a la posición que dicho campo clave o índice indique.
Los índices se encentran ordenados para conseguir un acceso más rápido y en ocasiones
además del fichero de datos, el conjunto de índices se encuentra almacenado en tm fichero
igualmente.
J 1 Registro 1
i/ 2 Registro 2
Campos clave 3
\ 4 Registro 4
N Registro N
Normalmente, hoy día, cuando se crean aplicaciones que gestionan grandes cantidades de
datos, estos son almacenados en bases de datos a las que accede el programa, pocas veces
encontraremos esta información almacenada en ficheros.
Si usamos ficheros en nuestro programas, estos serán de tipo texto o binario y el acceso
preferido es el secuencial, ya que aunque es algo más lento no complica demasiado la
programación.
■ Apertura. Debemos abrir el fichero tal que en el proceso se indique qué tipo de
acceso vamos a realizar sobre él. Al abrir un fichero relacionamos un objeto de
nuestro programa con un archivo almacenado en disco a través de su nombre e
indicamos el modo en que vamos a operar sobre él.
■ Operaciones de lectura y escritura. Leeremos la infonnación del fichero prestando
especial atención en la posición que se encuentra el manejador de archivos. Este
indica el punto desde el que empezar a leer y si nos encontramos en el final del
fichero esta operación no sería posible.
■ Cierre. El fichero queda liberado y finaliza el proceso de almacenamiento de la
información, es decir, se tennina de escribir en el dispositivo físico la información
guardada aún en el buffer\
A la hora de abrir un fichero es necesario indicar para qué vamos a usarlo, es decir, si solo
vamos a realizar operaciones de lectura sobre un archivo su modo de apertura será diferente a si
vamos a realizar operaciones de lectura y escritura.
Los modos de apertura son los siguientes:
■ Lectura. Vamos a realizar solo operaciones de lectura sobre el fichero.
■ Escritura. Realizaremos operaciones de escritura. En caso de que el fichero que se
quiera escribir ya exista este será borrado.
■ Añadir. Parecido al de Escritura ya que realizaremos esta operación sobre el fichero
con la diferencia de que si este existe con anterioridad no será eliminado.
■ Lectura/Escritura. Realizaremos operaciones de lectura/escritura en el fichero.
Lectura secuencial
//Variable de tipo Fichero
Fichero/;
//Apertura delfichero
/Abrir/lectura);
//Cierre delfichero
fCerrarO;
Lectura aleatoria
//Vaiable de tipo Fichero
Fichero/;
//Apertura delfichero
f.A brir(lectura);
Mientras condición según programa hacer //No siempre usamos una sentencia repetitiva
Situar el puntero delficherojusto antes del registro requerido
fLeer(registro);
operaciones con registro leído;
finMientras
Escritura secuencial
//Apertura de!fichero
/Abrir(lectura);
//Cierre delfichero
fCerrarQ;
Escritura aleatoria
//Vaiable de tipo Fichero
Fichero/;
//Apertura delfichero
/A brir(lectura); ■
f:Q?rrPJ)()i/L delfichero
Figura 10.5. Representación gráfica del uso de flujos en el acceso a la información almacenada en
diferentes dispositivos.
Flujo intermedio^
iyfelba^''
Cadena de
...DESTINO
caracteres
El acceso a un flujo de datos se puede realizar de forma secuencial o aleatoria como veíamos
al estudiar los ficheros (al hablar de flujos generalizamos a movimiento de bytes entre otros
dispositivos). Este dispondrá de un mecanismo por el que se pueda extraer o añadir información.
Por defecto, la primera operación a realizar sobre el flujo de byte se realiza al comienzo, es decir,
cuando abrimos el flujo el puntero o manejador de flujo se coloca al principio de fonna que si
realizamos una operación de lectura o escritura, esta se realizará sobre los primeros datos.
A partir de la primera operación las siguientes operaciones se llevan a cabo a partir de la
última posición accedida, en caso de que el acceso sea secuencial. Si el acceso es aleatorio, como
ya hemos estudiado, podemos modificar la posición a partir de la que operar con los datos.
Véase las siguientes figuras.
^ Podríamos decir que el flujo intermedio procesa la información mientras que el base realiza
básicamente la función de envío de bytes de un lugar a otro.
Capitulo 10. Flujos de Entrada/Salida y control de excepciones
Stream BinaryWriter
TextReader
StringWriter
StreamWriter
Stream es la clase base para todas las secuencias o movimiento de bytes, ya se produzcan en
un fichero, en una tubería de comunicación entre procesos o un proceso de comunicación entre
diferentes ordenadores a través de TCP/IP.
La clase Stream posee multitud de clases que derivan de ella, en la Figura 10.9 solo hemos
incluido algunas de ellas.
A continuación vamos a estudiar los métodos que usa la clase para la lectura o escritura de
bytes. Es importante entender que la clase solo escribe o lee bytes, es decir, no sabe cómo
procesar los tipos primitivos del lenguaje tales como int, double, char, etc.
■ int Read(byte[] buffer, int Inicio, int totalBytes) . Operación de lectura. Leerá
tantos bytes como indique el parámetro totalBytes (siempre que sea posible, es decir,
no se haya alcanzado el final del flujo) comenzando en la posición indicada con el
parámetro inicio. Los bytes leídos serán almacenados en parámetro buffer que no es
más que un array de bytes. Devuelve el total de bytes leídos, cero en caso de que
hayamos llegado al final del fichero.
■ int ReadByteQ. Lee un byte de la secuencia y lo devuelve como número entero sin
signo. En caso de llegar al final del fichero el valor devuelto será -1.
■ void Write (byte[] buffer, int inicio, int totalBytes). Escribe el total de bytes
especificado en el parámetro totalBytes. La información es obtenida desde el buffer
y empezamos a escribir desde la posición establecida por el parámetro inicio.
■ void WriteByte (byte valué). Escribe el valor pasado como parámetro (el byte) en el
flujo.
■ long Seek (long inicio, SeekOrigin origen). Método necesario en accesos aleatorios.
Posiciona el puntero en la posición correcta que debe ser leída o escrita. El parámetro
origen determina un lugar de referencia, es decir, el principio del fichero
(SeekOrigin.Begin), el final del fichero (SeekOrigin.End) o la posición actual
(SeekOrigin.Current), mientras que inicio indica el número de posiciones que
saltaremos desde la posición de referencia.
■ CanRead. Propiedad que devuelve verdadero o falso en función de si el flujo puede
ser leído o no.
Clase derivada de Stream que permite operaciones sobre flujos que almacenan o leen los
datos desde ficheros.
Capitulólo. Flujos de Entrada/Salicia y control de excepciones 403
ACTI^D^AD 10.1
Accede al Framework .NET y observa los diferentes modos y accesos de FileStream.
Debemos tener en euenta que la clase FileStream sigue leyendo im flujo de bytes, es decir, no
reconoce los tipos de datos primitivos del lenguaje (será necesario realizar operaciones de
traducción a bytes en cada lectura o escritura para que la información pueda ser interpretada o
escrita).
El proceso a seguir en la lectura o escritura de un archivo a partir de FileStream será el
siguiente:
■ Abrir el fichero. Para ello tenemos que crear una variable de tipo FileStream y en el
constructor indicar el nombre del fichero y el modo de apertura de este, tal que:
—>■ Abrir para lectura -> FileMode.Open.
Abrir para escribir sin sobrescribir el fichero -> FileMode.Append.
-> Abrir para crear el fichero en caso de que no exista y si existe lo sobrescriba
-> FileMode.Create.
Si queremos abrir el fichero para poder leer y escribir sobre él además del modo indicaremos
el acceso FileAccess.ReadWrite.
Busca en el Framework .NET la clase File. Redacta un pequeño documento donde incluyas
los métodos más característicos. Busca un ejemplo donde se use de forma conjunta FilcStream y
File.
ACTIVIDAD 10.3
ACTIVIDAD 10.4
Modifica la Actividad 10.3 de fonna que crees una aplicación gráfica con un único
formulario. En la ventana debes incluir un cuadro de texto para especificar el nombre del fichero,
un cuadro de texto multilinea donde visualizar el contenido del fichero y un botón que de la
orden de apertura y lectura del mismo.
ACTIVIDAD 10.5
Las siguientes serían clases que implementan flujos intermedios de alto nivel para trabajar
con ficheros de texto:
Las siguientes serían clases que implementan flujos intennedios de alto nivel para trabajar
con ficheros binarios:
ACTIVIDAD 10.6
Realiza una función que permita la lectura desde un fichero de texto y otra que pennita la
escritura usando las clases StreamReader y StreamWriter. Usa las msdn en caso de dudas.
ACTIVIDAD 10.7
ACTIVIDAD 10.8
Codifica un programa que lea un fichero de texto y contabilice el número de veces que
aparece cada una de las letras del alfabeto en él.
{ i
string nombre; ¡
string apellidos; ;
I
t
I
return nombre;
nombre = valué;
public string Apellidos
return apellidos;
apellidos = valué;
Para indicar que la clase es serializable solo debemos escribir la marca [Serializabie]:
[Serializable]
class Persona
{
string nombre;
string apellidos;
ACTIVIDAD 10.9
Realiza una pequeña aplicación de consola tal que use la clase Persona (amplia su
funcionalidad y atributos). Al comenzar las personas almacenadas en el fichero que indiquemos
son leídas y guardadas en un array de tipo Personas. Si no hubiera almacenada aún ninguna
persona en el fichero el array no contendrá datos. Veremos un pequeño menú con las opciones
insertar, modificar, eliminar, buscar persona y mostrar (todas las operaciones asociadas a los
elementos del menú se realizan sobre el array). Al cerrar el programa el fichero inicial será
sobrescrito con la nueva lista de personas.
ACTIVIDAD 10.10
Desanolla una aplicación gráfica basada en la Actividad 10.9. Configura la aplicación con
tantos fomiularios como se desee y los controles que se creen oportunos para que se puedan
realizar las operaciones indicadas.
FileInputStream
DatalnputStream
|
FilterlnputStream
InputStream BufferedInputStream
0H1SSI
OutputStream
StnngBufferlnputStream j
ObjectOutputStream 1
StringReader
BufferedWriter
OutputStreamWriter FileWriter
Writer FilterWriter
StringWriter
PrintWriter
NOTA: Todas las clases vistas se incluyen en el paquete java.io. Debemos usar j
sentencias import para hacer uso de ellas, ya sea de forma individual: import j
: java.io.FileOutputStream; o conjunta: importjava.io.*; |
I I
Es necesario, ya sea en la cabecera o a través de sentencias try...catch que ya veremos los
posibles errores de ejecución, de ahí que la declaración contenga la línea:
Existen otras clases que no se han incluido en la Figura. Acceder a la API de Java para obicner todo el
listado.
Capitulo 10. Flujos de Entrada/Salida y control de excepciones
Desde ella se controla el error en tiempo de ejecución producido por no localizar el fichero
(FileNotFoundException) y los errores en operaciones de escritura/lectura de datos
(lOException).
A la hora de realizar una operación de lectura secuencial desde un fichero, el proceso es
similar al visto en C#, cambian las clases que usamos para ello.
public static void LeerFicheroBinario(String nombreFichero)
throws FileNotFoundException, lOException{
FileInputStream flujo=new FileInputStream(nombreFichero);
byte []buffer=new byte[10];
while(flujo.read(buffer)>0){
String cadena = new String(buffer) ,•
System.out.println(cadena);
)
flujo.cióse();
■ write(char [] buffer, int inicio, int tamaño). Envía al flujo de datos la información
almacenada en el array de caracteres buffer. Es posible indicar dónde comenzar a
enviar a través de inicio y la longitud de los datos, tamaño. Existen sobrecargas para
este método tal que podemos enviar una cadena de caracteres write(String cadena,
int inicio, int tamaño) o bien un solo carácter expresado como valor del código
usado, write(int carácter).
Las clases FileReader y FileWriter heredan de estas tal que utilizan estos métodos.
A la hora de usar estas clases debemos prestar atención a sus constructores, ya que en el caso
de InputStreamReader y OutputStreamWriter se precisa un flujo base de tipo InputStream o
derivado de este como FileInputStream. Si optamos por el uso de InputStream recordad que es
una clase abstracta y no puede ser instanciada. Véase el siguiente ejemplo. En las clases
FileReader y Filewriter será necesario usar una variable de tipo File.
public void copiar(String nombreFicheroOrigen,String nombreFicheroDestino)
throws FileNotFoundException, IOException{
int letra;
double numReal;
System.out.println("Escribe número real y pulsa ENTER.
-1 para finalizar");
do{
numReal=Double.parseDouble(teclado.readLine());
if(numReal!=-l){
escritura.writeDouble(numReal);
}
jwhile(numReal!=-l);
escritura.cióse O ;
flujoSalida.cióse();
teclado.cióse();
}
void leerNumeros(String nombreFichero)
throws FileNotFoundException, IOException{
InputStream flujoEntrada=new FileInputStream(nombreFichero);
DatalnputStream lectura=new DatalnputStream(flujoEntrada);
try{
double numReal;
while(true){
Capítulo 10. Flujos de Entrada/Salida y control de excepciones 413
numReal=lectura.readDouble();
System.out.println(numReal);
catch(EOFException ex){
lectura.cióse O;
flujoEntrada.cióse();
)
Al llegar al final del fichero, si usamos DataínputStream en conjunto con alguno de los
métodos readXXX (readlnt(), readDouble(), etc.) el programa lanzará la excepción
EOFExcption. En el ejemplo se ha optado por configurar un bucle infinito que finalizará cuando
se produzca el error de ejecución tal que en ese momento se cerrarán los flujos abiertos.
El método readLine() de DatalnpuStream, en cambio, devuelve nuil si no existe más
información a leer de fonna que podemos usar esto para finalizar el bucle:
p
ACTIVIDAD 10.11
Realiza un programa en el que crees un directorio vacío y en él copies los ficheros ubicados
en otro directorio.
escribir.writeObject(listaPersonas[i]);
escribir.cióse();
import java.io.DatalnputStream;
import java.io.DataOutputStream;
import java.io.lOException;
import java.net.ServerSocket;
import java.net.Socket;
//Declaración de flujos
DatalnputStream leer=null;
DataOutputStream escribir=null;
package redes;
import java.io.DatalnputStream;
import java.io.DataOutputStream;
import java.io.lOException;
import java.net.Socket;
Abrir
: * * Ba>fcetfc« » DocwncnSos «
^ Í4M«vé
* Mwr>«i«rp«U
■C 'r>««tot
j.
j Bibiioteca Oocumemos
C^frw per Csrp^t *■ *lh' ' 1l1
11 ñ •
mM—
ir,-.-
Aácibtjit'df ho< V«fi«n Cue
qaed«w
W
. )
• OecwiHf** ll
tm Ir«t*9*rv«t |
B 'TWrvM#! 6afr»«S«Mm««« V«*w«n Cu* JUAepUy M|
et 0cw9nflr'
O'vpe «n «I ^ 0<Mra<c<«
¿_P»p«lefa de wtic^e_
Lid Abrir
En C#, el método que pennite visualizar los diferentes cuadros de diálogos es ShowDialogO-
Este no pennite que se realice ninguna otra operación hasta que la ventana se cierra, es decir, los
cuadros de diálogos pasan a ser modales.
En Java, debido a que tenemos un único cuadro para las funciones de abrir, guardar y buscar
archivo, disponemos de los métodos showOpenDlalogO, showSaveDialogQ y showDialogO-
Botones del cuadro de herramienta referentes a los cuadros de dialogo en C#
en FolderBrowserDialog [ ^ OpenFileDialog I SI SaveFileDialog
Botón del cuadro de herramientas referente al cuadro de diálogo en Java
Combinaremos estos cuadros de diálogos con los flujos y archivos vistos en el capítulo.
Veamos los siguientes ejemplos.
/*Para finalizar imaginemos que tenemos una aplicación que realiza la función
de guardar entre otras, vamos a codificar un menú tal que recoja la
Capitulólo. Flujos de Entrada/Salida y control de excepciones 419
Los códigos escritos son bastante simples, se pueden modificar para controlar posibles errores
de ejecución por parte del usuario. En los cuadros de diálogo Abrir y Guardar se puede
configurar la propiedad FileName de antemano, de fonua que se muestre en el cuadro nombre el
texto relacionado con esta propiedad. Posterionuente, como hemos visto, FileName nos servirá
para saber qué fichero se ha escogido.
La propiedad Filter se usa para configurar el cuadro de texto tipo en estos cuadros de
diálogo. En el cuadro tipo solemos especificar la extensión de los ficheros que nuestra aplicación
puede leer o guardar. Por ejemplo podemos asignar a la aplicación el valor: Archivos
b¡narios|*.dat|Archivos de texto |*.txt; de forma que estaremos indicando que se visualicen en
el cuadro de diálogo los ficheros con estas extensiones. El formato para el valor de Filter es:
ACTIVIDAD 10.12
En Java la fonua de operar con cuadros de diálogos es similar a como hemos visto en C#.
Crea una pequeña aplicación gráfica con un menú y las opciones guardar y abrir. Usa los
controles que creas oportunos tal que cuando se pulse en guardar se visualice un cuadro de
dialogo de guardar y, posterionuente cuando el usuario pulse en Aceptar, se extraiga la
infonuación de algún otro control y se almacene en el fichero seleccionado en el cuadro de
diálogo. El menú abrir realizará la operación inversa.
10.10. EXCEPCIONES
Cuando se diseñan programas, se configuran de forma que se tienen en cuenta todos los
posibles en-ores que se pueden producir durante la ejecución del mismo, sin embargo, si
desarrollamos programas complejos es muy probable que se produzcan errores en tiempo de
ejecución.
Cuando escribimos código fuente podemos observar si se producen errores de compilación
gracias a las nuevas interfaces de desarrollo en modo gráfico o bien el programa no podrá ser
ejecutado hasta que el error sea corregido. Este tipo de errores se denominan errores de
compilación mientras que a los errores que se producen en tiempo de ejecución se les denomina
Excepción.
Al producirse un error en tiempo de ejecución, si este no es controlado, el programa finaliza
de forma brusca, en este apartado vamos a estudiar el modo de asegurar que nuestra aplicación,
pese a estos tipos de errores, funcione adecuadamente y en caso de que se produzcan fallos
resolver estos de un modo u otro, o al menos aportar una vía alternativa de ejecución ante los
fallos ocasionados.
Así, a partir de ahora, se diseñarán las aplicaciones de forma que si el código presenta una
excepción, esta será tratada en otra zona del código fuente siempre que la excepción producida
haya sido "nombrada" de algún modo. A continuación estos párrafos comenzarán a cobrar
sentido.
}catch(codigoError ex){
Los bloques try...catch además pueden ir acompañados de una sentencia finally. El bloque
de código incluido en el finalIy se ejecuta siempre existan o no errores. Así, con el uso de finally
podemos aseguramos de que los recursos usados sean liberados, los objetos eliminados
correctamente, etc.
Podemos incluir tantos bloque eateh como errores queramos capturar. Es fácil encontrar
estructuras como esta:
catch(TipoError2 ex2){
catch(TipoErrorN exN){
Bloque controlado
con try ^
Error de tipo 1
Código
Error de tipo 2
^ El código está escrito en C# aunque es bastante similar en Java, la diferencia se encuentra en las
clases diseñadas para la escritura en pantalla y lectura de teclado.
Consolé-Write("Escribe el divisor:");
divisor = double.Parse(Consolé.ReadLineO);
división = dividendo / divisor;
Consolé-WriteLine("El resultado de dividir (0) entre (1) es {2}"
,dividendo, divisor, división)
Consolé.WriteLine("Pulsa una tecla para finalizar el programa");
Consolé.ReadLine();
Mientras escribamos valores numéricos la ejecución será correcta pero, ¿que ocurriría si en
lugar de un número escribiéramos una letra cuando nos solicitan los datos referidos a dividendo y
divisor?
Al ejecutar el programa, si cuando nos piden un dividendo escribimos por ejemplo la letra 'q',
Visual Studio se detiene mostrando un cuadro de diálogo en el que se infonna de que se ha
producido un error no controlado en tiempo de ejecución y el programa debe finalizar. El en'or
concretamente viene definido por la clase FormatException. Este fallo se da cuando intentamos
convertir un valor a un tipo no penuitido (double.parse(Console.ReadLine()), intentamos
convertir un carácter a double y esto no es posible).
Para subsanar el problema cambiamos el código como sigue:
I
double dividendo;
double divisor;
double división;
Consolé.Write("Escribe el dividendo:");
dividendo = double.Parse(Consolé.ReadLineO);
Consolé.Write("Escribe el divisor:");
divisor = double.Parse(Consolé.ReadLineO);
división - dividendo / divisor;
Consolé.WriteLine("El resultado de dividir {0} entre {1} es (2)"
, /-l-ix7-¡Hí=nHo.
dividendo, divisor,
Hivi c: nr. div
H-itr isión);
(FormatException error)
Código de error:{O}",error.Message);
Consolé.ReadLine();
Recordamos que a la Wra de' hacer uña división podemos dividir por cualquier número
siempre que este no sea cero, en cuyo caso el resultado de la división es infinito. ¿Qué ocurrirá
en nuestro programa si asignamos a divisor el valor O?
En este caso, C# en las actuales versiones controla este tipo de error indicando que el
resultado de dividir entre cero es infinito, no se produce un cierre inesperado. Si este mismo
código lo ejecutáramos en Java se observaría algo similar, eso sí, en lugar de mostrar el texto el
resultado es infinito se visualizaría el resultado es Infinity. A continuación se indica el código y
excepciones Java.
Capítulo 10. Flujos de Entrada/Salida y control de excepciones
NOTA: Al realizar una lectura de teclado en Java se deben usar flujos y capturarse
posibles excepciones de E/S. Por este motivo se añade un catch para lOException.
Como decíamos con anterioridad, no es necesario incluir el bloque fínally. Si se añade, debido
a que tengamos componentes en nuestro programa que deban ser tratados de un modo concreto,
debiendo controlar su finalización, este se incluirá detrás de todos los bloque catch.
En nuestro ejemplo vamos a agregar un pequeño bloque finally. Este no tiene demasiada
utilidad pero aclarará su funcionamiento al lector.
— 1
double dividendo;
double divisor;
dot±)le división;
Consola.Write("Escribe el dividendo:");
dividendo = double.Parse(Consolé.ReadLine());
Consolé.Write("Escribe el divisor:");
divisor = double.Parse(Consolé.ReadLineO );
división = dividendo / divisor;
Consolé.WriteLine("El resultado de dividir {0} entre {1} es {2}"
, dividendo, divisor, división);
}
catch (FormatException error)
{
Consolé.WriteLine("No ha sido posible continuar con el programa.
se ha producido un error en la introducción de datos. Código de
error:{0}", error.Message);
}
finally
{
Consolé.WriteLine("Pulsa una tecla para finalizar el programa");
Consolé.ReadLine();
Se produzca o no error la aplicación finaliza con el mensaje "Pulsa una tecla para finalizar el
programa".
ClassNotFoundException
lOException
Exception
W ArithmeticException I
RuntimeException CassCastException i
P IndexOutBoundException
Figura 10.15, Jerarquía de clases de error en Java. Existen otras muchas, véase la API de Java.
Exception
-i>>| FileNotFoundException I
tp="^LpivÍdeByZeroException
=>-- EndOfStreamException
|
L^'|^ExceptÍo^=^^ -íí'^TFDataFormatException
NuIIReferenceException
\ SystemException IndexOutOfRangeException
Figura 10.16. Jerarquía de clases de error en C#. Al igual que en la Figura 10.15 se han omitido algunas
para no hacer extenso el gráfico. Véase el framework .NET.
La clase Exception, tanto en Java como C#, dispone de una serie de métodos y propiedades
que son usados en las clases que derivan de ella.
Propiedades de Exception en C#;
■ Message. Propiedad. Devuelve una cadena de caracteres con un mensaje descriptivo
del error.
■ InnerException. En caso de que una excepción sea producida a causa de otra esta
propiedad devolverá esta. Devuelve un objeto de tipo Exception o derivado.
■ Source. Almacena o devuelve información relativa al componente que causó la
excepción. Es una propiedad.
■ HelpLink. Devuelve una cadena de caracteres con la URL donde se puede localizar
información relativa al error producido.
Métodos de la clase Exception en Java;
■ getMessageO. Método que devuelve una cadena de caracteres descriptiva del tipo de
error producido.
En este apartado vamos a estudiar cómo crear nuestras propias clases de error y cómo lanzar
estas en detenninados momentos del programa.
10.10.4.1. CREACIÓN DE CLASES DE ERROR EN C#
Las clases de error son similares a cualquiera de las clases que hemos estado desarrollando
hasta ahora, con diferencia de la fimción para la que se diseñan. En C# las clases de error deben
derivar de Exception o AppIicatlonException, normalmente suelen derivar de la segunda de
ellas.
Así, a la hora de crear nuestra propia clase de error declararemos esta como sigue:
class nombre_clase:ApplicationException{ '.1 ' :
i Í.ÍV''- i. ■ i
string mensaje;
this.mensaje = mensaje;
return this.mensaje;
Acabamos de crear una nueva"¿lasé"de eiTÓr"Err^^^^ Ahora solo queda hacer uso de ella
en el programa principal.
0Override
public String getMessage(){
return mensaje;
Las clases de error diseñadas en los Apartados 10.10.4.1 se crean con el objetivo de que en el
momento en que un usuario escriba incorrectamente su información de acceso sea lanzada, pero,
¿cómo lanzamos nuestras propias excepciones? Si bien es cierto, hasta el momento, solo
sabemos capturar errores.
Indicamos que se produzca una excepción creando una instancia de esta en la zona crítica del
código, incluyendo este en un bloque try...cateh, y anteponiendo a esta la palabra reservada
throw.
Así, en nuestro ejemplo, deberíamos incluir a la hora de producirse el login de un usuario algo
similar a los que se muestra a continuación:
Código C#
static bool login(string usuario, string password)
Consolé.WriteLine(error.Menssage);
finally
Código Java
static boolean login(String usuario, String password){
if(ilogin(nombre,passwd)){
throw new ErrorLoginException ("Usuario o password incorrecto.
Vuelva a intentarlo de nuevo.");
}
}
catch(ErrorLoginException error){
System.out.print(error.getMessage());
}
finally{
NOTA: Podemos lanzar cualquier tipo de excepción con la sintaxis vista, ya sea
creada o no por el usuario.
En muchas ocasiones Java da la posibilidad de omitir los bloques try...catch y añadir una
sentencia throws en la cabecera del método indicando que este es posible que genere o lance un
tipo concreto de excepción.
public static void main(String[] args) throws ErrorLogin, ;
lOException, NumberFormatException{ ;
Esta codificación permite indicar que puede producirse errores de ejecución pero no controla
qué hacer con ellos.
COMPRUEBA TU APRENDIZAJE
1. ¿Qué tipos de ficheros hemos estudiado? ¿Qué caracterizan a cada uno de ellos?
2. ¿Qué operaciones básicas realizamos sobre ficheros?
3. A la hora de abrir un fichero existen diferentes modos,¿cuáles son?
4. ¿Cuáles son los algoritmos de lectura y escritura secuencial y aleatoria?
5. Define flujo. ¿Qué tipos de flujos existen? Explícalos brevemente.
6. ¿Qué se entiende por señalización?
7. ¿Qué es una excepción? ¿Qué mecanismos existen en los lenguajes vistos para controlar
estas?
ACTIVIDADES DE AMPLIACION
1. Amplía la Actividad Ampliación 3 del Capítulo 9 de forma que se de opción al usuario a
almacenar la información en un fichero binario (almacenamos objetos) y cargar datos
desde un fichero.
7. Crea una pequeña aplicación gráfica en la que se muestre un formulario con dos cuadros
de texto, usuario y password, y un botón, login. Los cuadros de texto no pueden estar
vacíos, si al pulsar el botón alguno no contiene infonnación se lanzará la excepción
VacioException. El cuadro de texto usuario sólo puede contener letras, mayúsculas o
minúsculas, en caso de que contenga otro tipo de símbolo se lanzará la excepción
FormatoErroneoUsuarioException. Para el cuadro password debemos aseguramos de que
se escriban letras, números y alguno de estos símbolos ($, _ % o &), es decir, la
contraseña debe ser una combinación de estos, en caso contrario lanzaremos la excepción
FormatoPasswdErroneoException.
8. Crea un pequeño programa que trate objetos de tipo Casa. Un objeto Casa tiene
propiedades del tipo dirección, portal, piso, localidad, código postal, metros cuadrados,
número de habitaciones, etc., y métodos que modifican estas operaciones, calculan el
precio de venta, etc. La aplicación debe permitir almacenar y cargar estas casas en
ficheros binarios. A la hora de crear una nueva casa se lanzará una excepción en caso de
que alguno de los datos sea incorrecto, esta excepción se llamara NuevaCasaException. Si
cargamos un fichero y este está vacío se debe lanzar la excepción
CasasInexistentesException.
9. En el Capítulo 7 veíamos como ejemplo práctico de uso de arrays el juego del ahorcado.
Añade funcionalidad al programa de forma que almacenemos en un fichero los nombres
de los ganadores así como el número de letras usadas.
10. Realiza un programa que cuente el número de dígitos que contiene un fichero dado por el
usuario.
11. Realiza un programa que muestre, tras leer un fichero dado, el porcentaje de aparición de
cada carácter.
12. Lee un fichero de texto tal que en él se almacenan una serie de operaciones a realizar.
Estas operaciones pueden ser;
■ crear fichero
■ leer directorio
■ contarFicheros directorio
■ EspacioDisponible unidad
El objetivo es que tras leer el fichero se realicen las órdenes especificadas en él.
CONTENIDOS / OBJETIVOS
Bases de datos relaciónales. Saber qué es una base de datos
Creación de aplicaciones de acceso relacional y entender el proceso a
a bases de datos relaciónales en seguir para la creación de
C#. aplicaciones que las gestiones en C#.
Bases de datos orientadas a Entender el concepto de base de
objetos en C# y Microsoft SQL datos orientada a objetos.
Server.
Saber cómo configurar bases de
Bases de datos orientadas a datos orientadas a objetos en C# y
objetos en Java y db4o. Java así como las aplicaciones de
conexión que necesitaremos en cada
\ lenguaje e DDE.
Access, aunque no es de los mejores sistemas de gestión, se usa con frecuencia en la actualidad
en pequeñas/medianas empresas, así, vamos a usar esta aplicación de Microsoft para generar
nuestra base de datos ejemplo. En este libro no vamos a enseñar al lector a crear una base de
datos, tan solo mostraremos las tablas y relaciones entre ellas, si el lector desea conocer más
sobre la creación de bases de datos puede hacerse con el libro de esta misma editorial que
comentábamos párrafos más arriba.
Decir que cada grupo de información vendrá definido por un objeto llamado tabla. A su vez,
en cada grupo de datos realizamos subgrupos de información, por ejemplo, de los clientes
almacenamos referencia, nombre, dirección, etc., a cada uno de estos elementos se les denomina
campo. Por último, cuando empezamos a dar un valor exacto a cada campo vamos configurando
los denominados registros. Un registro almacena información relacionada con una entidad
concreta, es decir, cada cliente es un registro y cada cliente da una infonnación diferente a los
campos nombre, dirección, etc.
A su vez, los datos no pueden estar aislados, los clientes deben estar en contacto directo con
los pedidos que realizan, los proveedores con los artículos que proveen, de fonna que se
establecen relaciones entre las tablas o grupos de información más que justificadas.
Capítulo 11. Gestión de bases de datos. Bases de datos orientadas a objetos 433
Finalmente nuestra información debe estar organizada siguiendo el esquema que se muestra
en la Figura 11.1.
Campos
Registros
P- ;
S/ RefPc&do
R<tA/tiCUtO
í RdProveodof X
CjntidJd
Detru<nto
Nombre de ^<r«ed
Oifítcicn X
fccKide pedido
Ciudid X
í RerCi»ent< -
Nombre de Clienti
9 RetArucutc j
RrfPravecdoi 9
Dtfecoon
Nombre de Artin
Ciudad
Nofr.b(e de Catej
Codpottal j Pteoo unidad
P*i>
Unidades en eut
Tfjífftnrt
Figura 11.1. Esquema de relaciones Access entre las tablas que forman la base de datos y elementos
de una tabla relacional.
A partir de ahora, nuestro objetivo es crear aplicaciones tanto en C# como en Java que hagan
las veces de sistemas de gestión tal que actualicen la información de la base de datos, la
modifiquen o eliminen, la visualicen, etc. Así, dispondremos de una base de datos ya creada,
conectaremos con ella, y en la aplicación usaremos las herramientas oportunas para gestionar los
datos.
Le permite cenecterse a une bese de datos y elegir les objetes de base de datos para la aplicación.
El modelo de base de datos que elija determina los tipos de objetos de datos que utiliza el código de la aplicación.
Se agregará un archivo de conjunto de datos a! proyecto.
7. Elegir conexión de datos. En esta ventana debemos establecer qué conexión de base
de datos vamos a usar, es decir, se debe indicar qué fichero contiene la base de datos
con la información. Es necesario dar a conocer una serie de características, el nombre
del archivo no es suficiente, así haremos clic en Nueva conexión.
8. En Origen de datos debemos especificar Archivo de base de datos de Microsoft
Access. Existen otros orígenes tales como SQL Server.
9. Clic en examinar para localizar el fichero de base de datos. Seleccionamos nuestra
base de datos tienda. Si hubiéramos establecido un password de acceso a la base de
datos debemos escribir en la zona Conexión con la base de datos. Clic en Siguiente.
Capítulo 11. Gestión de bases de datos. Bases de datos orientadas a objetos
10. Si la base de datos no se encuentra en la carpeta del proyecto se nos alertará de ello y
dará la opción de agregarla a este. Clic en Sí para que añada el archivo de base de
datos al proyecto que va a usarla.
11. Los pasos que se acaban de dar establecen una conexión con una base de datos
representada mediante la denominada cadena de conexión. Esta presenta un nombre
dado por Visual Studio. Si queremos modificar solo tendremos que escribir en el
cuadro de texto. Daremos a la cadena de conexión el nombre conexionTlenda.
12. Clic en Siguiente. Si la conexión con las base de datos se realizó correctamente
veremos una pantalla con las tablas y vistas (consultas) almacenadas.
13. Seleccionamos todas las tablas haciendo clic en la casilla junto a Tablas y
especificamos el nombre del DataSet antes de hacer clic en Finalizar. El DataSet es
el componente que englobará toda la información de la base de datos con la que
conectamos. Estará fonnado por DataTable relacionados cada uno con tina de las
tablas de la base de datos en cuestión.
14. Tras unos segundos, la paleta orígenes de datos cambiará de forma que en ella se
visualizarán todas las tablas de nuestra base de datos.
ni? Forml
; N < O de{0} ► H ■!> X y
Nombre de Nombre de
RefArticulo RefProveedor
Artículo Categoría
M artículosBíndingNavigator
Figura 11.6. Vista de diseño del formulario que visualizará la información referida a la tabla Articules.
■ datos. Objeto de tipo dataSet (conjunto de datos) que incluye una referencia a los
datos de la base de datos. Al arrastrar una de las tablas al fonnulario de fonna
automática se incluye este elemento, pues contiene totas las tablas de la base de datos
enlazada.
&
Cudsd
Código postal
Be^
122S9
MoveFirstO- Desplaza la vista al primer registro de la
íte.™ tabla. Lo usaremos en el botón Primero.
Teléfono
Teléfono C3!>0C7íE2T
C3!>0C7íE21 " " i • l • •
MovePreviousO- Desplaza la vista al registro anterior
Lp""»" i[ ]i I [ !>.■»» i qyg actualmente activo. Lo usaremos en el botón
j\iit0rior
Figura 11.10. Vista del formulario
clientes una vez se ha ejecutado la
aplicación.
Capítulo 11. Gestión de bases de datos. Bases de datos orientadas a objetos
c 1 ientesBindingSource.ttoveFirst();
A continuación vamos a agregar nuevos botones al formulario que permita eliminar y añadir
nuevos registros (los botones se pueden configurar para que en lugar de un texto muestren ima
imagen).
La vista del formulario debe mostrarse de forma similar a la Figura 11.11.
Clientes ^ [ rr. j B Los mótodos dc BiudingSource que
penniten la eliminación e inserción de datos en
Referendfl de Chente EDEa
Referencia de Chente _ la tabla del origen de datos son
Nombredeioente «fredsFüiakide
Nombre dd Chente Affreds Futtefkiste RcmoveCurrent y AddNcw.
Dirección Obeie Str. 57
Obere
Gudad Berfin
Qudad Berfin AddNewQ inserta una nueva fila en la
Código postal
Código postal 12209
12209 I I tabla, eso sí, antes de dejar de usarla debemos
País Alemania
País Alemania I I actuallzar la Infonnaclón para que permanezca
Teléfono 030-0074321 ii t* ^ ' i 'j
en ella. RemoveCurrent eliminara el registro
I 1, i, , 1—^ 1 actual.
^ J Configuraremos los botones Añadir y
Figura 11.11. Formulario dientes modificado. Se Elimina, además del evento FormClosing
han agregado los botones Añadir y Eliminar. como sigue:
NOTA: Existen dos eventos relacionados con el cierre del formulario. El primero de
; ellos es FormClosing. Este se produce antes de cerrar el fonnulario. El otro evento es
FormClosed que se da una vez se ha cerrado el formulario. A la hora de actualizar la
j infonnación de nuestro formulario cliente debemos hacer uso del evento FormClosing, ya
1 que debemos actualizar antes de cerrar la vista.
prívate void btnEliminar Click(object sender, EventArgs e)
clientesBindingSource.RemoveCurrent();
clientesBindingSource.AddNew();
Para finalizar nuestro formulario Clientes vamos a agregar un cuadro de texto que pennita
buscar un registro según su posición. La vista del formulario debe ser algo similar a la Figura
11.12.
ACTIVIDAD 11.1
Añade un nuevo formulario, denomínalo Proveedores. Configura este para que se visualice la
información de los proveedores de nuestra base de datos. Agrega los botones oportunos para el
desplazamiento, eliminación, anexado de nuevos proveedores y búsqueda según índice como
hemos hecho en este apartado para el formulario Clientes. Haz que se muestre al hacer clic en el
menú Datos Tablas -> Proveedores.
ACTIVIDAD 11.2
y 09 OientesOataGríd
Referencia de Qente
Código postal
Tareas de DataGrídView
Nombre de
Gente Elegir origen de datos: clientesBindingSource [vj
Editar columnas...
AutoSizeMode NotSct
(Ñame)
, Indica el nombre utilizado en el código para identificar el
objeto.
:1 subpro<l.iT7:
Si lo deseamos, en lugar de visualizar todos los registros podemos ver el resultado de realizar
una consulta sobre ellos. Para ello seguimos los siguientes pasos:
1. Clic para visualizar las tareas de ClieutesDataGridView (flecha en la zona superior
derecha).
2. Clic en Agregar consulta.
3. Aparecerá el cuadro de diálogo Generador de criterios de búsqueda. Por defecto el
dataCridView muestra todos los datos de la tabla, de fonua que la consulta SQL que
se observa en Texto de la consulta en una seuteucia SELECT en la que se incluyen
todos los campos y todos los datos. Clic en Generador de consultas. Vamos a
especificar qué información queremos que se muestre en el DataCridView de
clientes.
4. Para aquellos lectores que estén acostumbrados a realizar consultas en Access la
ventana Generador de consultas les debe resultar familiar ya que es similar a la vista
de diseño de una consulta en Access (aunque los campos y criterios se muestran en
filas en lugar de columnas), en Visual Studio se añade el texto de la consulta por
defecto en la parte inferior, algo que no sucede en la aplicación de Microsoft. Véase
Figura 11.16.
5. Supongamos que sólo queramos mostrar los campos Nombre de Cliente, dirección y
Teléfono de todos los clientes que sean de Madrid. En la zona superior del generador
de consultas se insertan las tablas que van a formar parte de esta, activaremos las
casillas de verificación que coincidan con los campos que coincidan con aquellos que
deban ser visualizados, es decir, en nuestro caso. Nombre cliente. Dirección y
Teléfono.
6. Para establecer los clientes de Madrid debemos incluir el campo ciudad aunque no
visualizaremos este. Clic en la casilla de verificación junto a Ciudad.
Capítulo 11. Gestión de bases de datos. Bases de datos orientadas a objetos
Generador de consultas
[Nombre de C
Figura 11.16. Cuadro de diálogo Generador de consultas que permite configurar diferentes vistas a
partir de las tablas aportadas por la base de datos.
Visual Studio genera una barra de herramientas donde se incluye un botón que permitirá
ejecutar la consulta realizada. Podremos agregar tantos botones como consultas creamos
oportunas.
444 Programación
Tienda
o-J Clientes
Gijdad Berln
País íJemania
Teléfono 03&-007
ACTIVIDAD 11.3
Crea un formulario de consulta para artículos, puedes usar DataGrid, cuadros de texto u otro
control para mostrar la información. Es accesible desde el fonnulario diseñado anteriormente
para los artículos de la base de datos.
ACTIVIDAD 11.4
Crea un consulta a aplicar sobre la tabla artículos y cuyo resultado se muestre en el fonnulario
creado en la Actividad 11.3, en la que se indique que se filtre la infonnación a partir del campo
precio, es decir, solo se muestren los artículos cuyo precio sea inferior a 10 euros.
ACTIVIDAD 11.5
Crea una nueva consulta en la que se visualicen los artículos de la categoría de bebidas.
Cada tabla o entidad que usábamos en nuestras bases de datos relaciónales serán a
partir de ahora objetos de nuestra base de datos.
■ Cada objeto posee un identificador, similar a las claves primarias en las bases de
datos relaciónales, por el que son identificados de forma única.
■ Podemos almacenar objetos complejos sin necesidad de realizar tareas o adaptaciones
especiales.
■ Una base de datos relacional, ya que se encuentra constituida de objetos, aplica
herencia entre ellos, es decir, los objetos pueden heredar unos de otros.
■ El usuario es el encargado de decidir qué elementos fonnarán la base de datos,
atributos y métodos.
■ No será necesario la generación de métodos de acceso a los objetos ya que los
gestores de bases de datos orientadas a objetos (SGBDOO) se encargan de realizar
esta función.
En este apartado seguimos con el uso de Visual Studio y C# para la generación de bases de
datos orientadas a objetos. Vamos a desarrollar un modelo (diagrama de tablas relacionadas entre
sí) a partir de Visual Studio para posteríonnente generar de forma física, real, la base de datos y
hacer uso de ella desde alguna aplicación que conseguiremos.
A la hora de generar bases de datos orientadas a objetos será necesario que hagamos uso de
alguna aplicación de base de datos, y si esta además se integra en Visual Studio nos facilitará
mucho el trabajo. Para entender los apartados posteriores del libro es necesario saber qué vamos
a hacer. Así, a la hora de desarrollar nuestra base de datos orientada a objetos:
1. Debemos tener instalado un gestor de bases de datos que permita almacenar la
información relacionada con entidades, registros, etc. Vamos a instalar Microsoft
SQL Server.
I NOTA: Microsoft SQL Server es un software producido por Microsoft para la gestión ¡
i de bases de datos en el modelo relacional. Es la altemativa que plantea Microsoft a |
I sistemas gestores como Grade o MySQL. Ahora bien, podemos trabajar con objetos I
I usando un almacenamiento en una base de datos relacional, utilizando lo que se i
j denomina un mapeador "objeto-relación" (ORM). El mapeo se produce a nivel de i
i aplicación cliente, no en SQL. ¡
Configuraremos Visual Studio para que podamos acceder a SQL Server desde su
interfaz (automático con la instalación de SQL Express, acceda a la web de Microsoft
y localice infonnación relacionada con el proceso de instalación y configuración).
Crearemos el modelo de entidades.
ACTIVIDAD 11.6
Configura las entidades Proveedores, Clientes y Pedidos con los campos indicados en el
Apartado 11.1. Configura la propiedad nombre del conjunto de entidades para cada entidad
como sigue: Proveedores TodosLosProveedores, Pedidos TodosLosPedidos y Clientes
-> TodosLosClientes.
Para enlazar las entidades y establecer relaciones entre ellas sólo tendremos que escoger la
henamienta Asociación del cuadro de herramientas Entity Framework.
1. Clic en Asociación. Colocamos el curso sobre el campo de la primera entidad que
queremos relacionar, por ejemplo sobre el campo refProveedores de la tabla
Proveedores.
2. Pinchamos y sin soltar el ratón arrastramos hacia la siguiente tabla, segunda entidad
en la relación. En nuestro ejemplo sobre la entidad Artículos.
3. Colocamos el cursor sobre el campo de la segimda tabla a enlazar y soltamos el ratón;
en nuestro caso, refProveedor de la entidad Artículo.
4. Tras la operación veremos una línea entre ambas entidades. El proceso de asociación
es similar al de establecimiento de relaciones entre tablas de una base de datos de
Access.
- Propiedadev 'Propiedadtrv
Y? rclPfot/eedor yí refArticulo
M NombreProveed.- A nomhrrAtUtulu
^ DirrtíKin ^ NombtrCalpqofia
^ CodigoPo&ial PieCiO
A Ciudad f* CantidadStock
> País A fefProveedor
A Telefono 'Propiedades de nav.^
" Propiedades de nav.. y*!] Piijvrrdtnes
^Artículos Pedido
' Propiedades
yf f«?irii«'n!r
Norr.bie
A Dirección
f* Ciudad
- Propiedades A CodigoPostal
y? rrfPcdido A PO'S
A refArtiCuto Trlí-Ínrvo
=■ Propiedades de nav^.
Clientes
^ Artículos
metadata=res://*./TiendaModelo.c5dl|res;/,^/TiendaMcdelo.s5di|
re5://'/TiendaModelo.m5l;provider=System.Data,SqlCiient;provider connection string="data sources:.
\SQLEXPRESS;¡nitia! cataIog=Tienda;integrated
securit)'=True;MültipleActiveResultSets=True;App-EntityFrannework"
6. Pasados unos segundos se visualizará el fichero SQL (script) con las órdenes
necesarias para generar la base de datos correspondiente al modelo creado en el
Apartado 11.6.2.1.
7. Cambiamos el nombre del fichero a ModeloDeTíenda.edmx.sql y clic en Finalizar.
NOTA: Al crear un script SQL antes de ejecutar y crear la base de datos podemos
corregir posibles fallos del modelo.
Nonnalmente, nada más finalizar la creación del fichero SQL, será lazada la aplicación SQL
Server que ejecutará el script y generará la base de datos. Aún así, podemos dar orden de ejecutar
el script:
1. Clic con el botón derecho del ratón sobre cualquier zona del script.
2. Clic en Execute SQL.
3. SQL Server se inicia y configura la base de datos relacionada con nuestro modelo.
4. Accedemos al Explorador de servidores (Ver -> Explorador de servidores). Al
desplegar la conexión creada anteriormente, debemos visualizar las tablas
relacionadas con las entidades creadas en nuestro modelo.
i NOTA: Si a la hora de ejecutar la consulta SQL (Script) se produce algún tipo de fallo
' es posible ejecutar esta y conseguir que se generen las tablas a partir del SQL Server
Management studio ubicado en la carpeta de instalación de Visual Studio y accesible
desde el acceso directo en Inicio de este. Desde SQL Server Management veremos las
conexiones creadas y podremos ejecutar el script creando un nuevo fichero SQL y
pegando en él el código SQL creado a partir del modelo de entidades
, (ModeloDeTienda.edmx.sql).
11.6.2.4. USO DE LA BASE DE DATOS
Una vez se han ejecutado los pasos descritos en los Apartados 11.6.2.1 a 11.6.2.3 vamos a
desarrollar una pequeña aplicación de consola que nos permita usar la base de datos de nuestra
tienda.
nuevoProd.precio = 1.3;
entidades.TodosLosArticulos.AddObject(nuevoProd); //(3)
entidades.SaveChangesO ; //(4)
'Es posible crear varios proyectos en la aplicación, usar referencias y organizar mucho mejor nuestro
trabajo.
Capitulo 11 ■ Gestión de bases de datos. Bases de datos orientadas a objetos 451
; nuevoProd.precio =
entidades.TodosLosArticulos.Remove(nuevoProd); //(3)
entidades.SaveChangesO; //(4)
■ //(l). Creamos una instancia del modelo para poder acceder a sus elementos.
■ //(2). Se crea una variable de tipo artículo (registro artículo). A la hora de eliminar
debemos indicar qué objeto borrar, por eso cargamos las propiedades de Artículos
con los valores oportunos para posteriormente localizar este registro en la tabla.
■ //(3). Damos la orden de borrar. Pasaremos como parámetro el objeto creado, si este
se encuentra en la tabla será eliminado.
■ //(4). Al igual que al añadir un registro, para que la eliminación perdure debemos
aplicar los cambios a partir del método SaveChanges().
La generación de consultas puede realizarse de diferentes maneras, una de ellas es a través de
la creación de procedimientos almacenados.
1. En el explorador de servidores clic con el botón derecho del ratón en la carpeta
Procedimientos almacenados y Agregar nuevo procedimiento almacenado.
2. Veremos una nueva ventana con la sentencia CREATE PROCEDURE.
@nomCategoria nvarchar(255);
AS
4. Para añadir la función al modelo, cíic en él con el botón derecho del ratón en
cualquier zona vacía, en el menú contextual Add e Functionimport.
5. Seleccionamos el procedimiento que acabos de crea y agregamos este.
6. Para hacer uso de la función y modelo creado en el código escribiremos:
: List<Articulo> sqlCategorias = entidades.devolverCategoria("Fruta").ToListO;
Podemos generar la consulta a partir del Query Builder. Clic en la zona en blanco del procedimiento e
Inserí SQL.
11.6.3. GESTOR DE BASE DE DATOS ORIENTADO A OBJETOS
PARA JAVA
Hemos estudiado cómo generar una base de datos de objetos y clases en C# y hemos usado un
gestor que como ya veíamos no es un gestor de bases de datos orientado a objetos, hacíamos uso
de un mapeado. En este apartado sí vamos a usar un gestor de bases de datos orientados a objetos
en combinación con el lenguaje de programación Java. No existe gran variedad de SGBDOO en
relación con los gestores de bases de datos relaciónales, algunos de ellos son; db4o,
Objetivity/DB o EyeDB. En este libro hemos optado por el uso de db4o, SGBDOO con licencia
GPL.
NOTA: Existe una versión de db4o para la plataforma .NET, es posible descargarla
desde su web oficial, sin embargo no es compatible con la versión 2012 de Visual Studio.
I La última versión de db4o para .NET requiere la versión 2010 de Visual Studio.
Podemos descargar el gestor tanto para usar con Java como con cualquiera de los lenguajes de
la plataforma .NET desde su web oficial http://www.db4o.com/.
Ya que vamos a trabajar en Java, en el apartado Download de la web de db4o
seleccionaremos el botón de opción relacionado con la versión db4o 8.0 para Java (en el
momento de edición del libro esta es la que está vigente) y haremos clic en Download.
Tras finalizar la descarga instalamos el gestor. El siguiente paso será la configuración de
Netbeans para usar db4o a partir de este IDE.
11.6.3.1. CONFIGURAR EL PLUGIN DB40 EN NETBEANS Y AGREGAR
LIBRERÍA DB40 A NUESTRO PROYECTO
Antes de comenzar a crear un nuevo proyecto y objetos de la base de datos vamos a
configurar el plugin db4 para NetBeans. Seguiremos estos pasos:
1. Antes de nada se debe proceder a la descarga del plugin, accedemos a la dirección
web: https://code.google.eom/p/db4o-netbeans/downloads/list.
2. Clic en el enlace db4o-netbeans_0.6.0_NB6.zip (hasta el momento es el último
plugin de db40). Para versiones de NetBeans 6.0 en adelante.
3. El fichero es un .ZIP, lo descomprimimos en una carpeta y accedemos ejecutamos
NetBeans.
Lo primero que debemos hacer es generar un nuevo proyecto, este puede ser en modo consola
o gráfico, para nuestras explicaciones se ha optado por el uso de un proyecto visual.
Además, debemos indicar que usaremos db4o, así se debe incluir la librería db4o al proyecto.
1. Creamos un nuevo proyecto en modo gráfico al que llamaremos BasesDeDatosOO.
2. En el explorador de proyecto, clic con el botón derecho del ratón en la carpeta
librarles para el proyecto que acabamos de generar.
3. Clic en Add Library.
4. En el cuadro de diálogo debemos localizar la librería db4o. Clic en ella y clic en add
Library.
@Overrlde
publlc String toString() {
return "Proveedores{" + "refProveedor=" + refProveedor +
", nombreProveedor=" + nombreProveedor + ", direccion="
+ dirección + ", ciudad=" + ciudad + ", codPostal=" + codPostal
+ ", pais=" + pais + ", telefono=" + telefono +
NOTA: Al eliminar la clase principal generada por defecto con el nuevo proyecto
debemos especificar qué clase vamos a usar a partir de ahora como primera clase.
Accedemos a las propiedades del proyecto haciendo clic con el botón derecho sobre su
nombre en el explorador de proyectos y Properties. En la categoría Run cuadro de texto
Main.class especificamos el nombre del nuevo formulario (Inicio).
A la hora de trabajar con bases de datos, básicamente siempre se repetirá la misma secuencia
de pasos:
Paso 1: Abrir la base de datos.
Una vez se han configurado los objetos que vamos a almacenar en nuestra base de datos
debemos crear esta o abrirla en caso de que haya sido creada con anterioridad (la operación de
apertura conlleva una creación de la base de datos en caso de que esta no exista).
En db4o la operación de apertura se realiza a partir del método Db4oEmbedded.opeiiFUe.
Este método devuelve un objeto de tipo ObjectContainer que representará nuestra conexión a la
base de datos durante toda la aplicación.
El método openFlIe precisa de dos parámetros. El primero de ellos se refiere al tipo de
configuración que podemos obtener a partir de Db4oEmbedded.NewConfigurationO y el
segundo el nombre db4o que vamos a dar a nuestro fichero de base de datos.
Así, en nuestro proyecto, vamos a crear una variable estática que pueda ser usada en cualquier
fonnulario y que identifique la base de datos que llamaremos Tienda.db4o. Esta variable será
creada como atributo de la clase Inicio como se muestra a continuación:
^ Aunque los campos codPostal y teléfono se usan para almacenar números no vamos a realizar
operaciones aritméticas con estos, de forma que es conveniente declararlos como cadenas de caracteres ya
que así ocuparán menos espacio en memoria.
import com.db4o.Db4oEnibedded;
import com.db4o.0bjectContainer;
java.awt.EventQueue.invokeLater(new RunnableO {
public void run () {
bsTienda=
Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration()
,"Tienda.db4o");
new Inicio().setVisible(true);
Debemos aseguramos de que la base de datos es cerrada correctamente, así, vamos a añadir el
método de cierre en el evento closing para el formulario inicial tal que al finalizar la aplicación la
base de datos también sea cerrada.
~ —
Ya que estamos configurando una base de datos de objetos, a la hora de insertar un elemento
en la base de datos es necesario crear una instancia de la clase que se va a agregar. Vamos a
comenzar a añadir objetos de tipo Proveedores a nuestra conexión. Para ello, vamos a configurar
un formulario como se muestra en la Figura 11.20.
Referenda de proveedor
Códiqo Postal
Telefono
Insertar
MenuTlenda [JMenuBar]
Archivo Insertar Ver Buscar Ayuda 1
É Archivo [3Menu]
i ■t^ Salir [JMenuItem]
B Insertar [JMenu]
"0 MenuProveedores [JMenuItem]
Ver [JMenu]
i MenuVerProveedores [JMenuItem]
0 Busrar [JMenu]
1 MenuBuscarRefProveedor [JMenuItem]
i i - -1^ MenuBuscarProveedoresQudad [JMenuItem]
' ^ Ayuda [JMenu]
ACTIVIDAD 11.7
Crea un fonnulario de inserción para los objetos restantes Clientes, Pedidos y Artículos.
NOTA: La actualización de registros de la base de datos se lleva a cabo mediante la
extracción del registro en cuestión, modificación de sus propiedades y posterior
almacenamiento.
Proveedores auxProv;
ObjectSet GrupoDeProveedores =
Inicio.bsTienda.queryByExample(new Proveedores(O,nuil)); //(I)
DefaultTableModel modelo =
(DefaultTableModel) tablaProveedores.getModel();
while (GrupoDeProveedores.hasNext()){ //(2)
auxProv=(Proveedores) GrupoDeProveedores.next(); //(3)
String []fila=new String[7];
fila[0] = String.valueOf(auxProv.getRefProveedor O);
fila[1]=auxProv.getNombreProveedor();
fila[2]=auxProv.getDireccion();
fila [3]=auxProv.getCodPostal();
Capítulo 11 ■ Gestión de bases de datos. Bases de datos orientadas a objetos
fila[4]=auxProv.getCiudad();
fila[5]=auxProv.getPais();
fila[6]=auxProv.getTelefono();
modelo.addRow(fila);
DefaultTableModel modelo =
(DefaultTableModel) tablaProveedores.getModel();
while (GrupoDeProveedores.hasNext()){
auxProv=(Proveedores) GrupoDeProveedores.next();
String []fila=new String[7];
fila[0] = String.valueOf(auxProv.getRefProveedor O);
fila[1]=auxProv.getNombreProveedor();
fila[2]=auxProv.getDireccion();
fila[3]=auxProv.getCodPostal();
fila[4]=auxProv.getCiudad();
fila[5]=auxProv.getPais();
fila[6]=auxProv.getTelefono O ;
modelo.addRow(fila);
La línea
— — — — - -------- -- -- -- -- -- -- -- -- - — — — -— — ^
ObjectSet GrupoDeProveedores = ■
Inicio.bsTienda.queryByExample(new I
Proveedores(O,nuil,nuil,txtCiudad.getText(),nuil, nuil,nuil)); ;
Obtiene los proveedores de la base de datos cuyo campo ciudad sea igual a
txtCiudad.getTextO, es decir, a la ciudad que el usuario especifique en el cuadro de texto
txtCiudad.
ACTIVIDAD 11.8
Crea los formularios que desees para visualizar Clientes, Artículos y Pedidos. Puedes
desarrollar diferentes interfaces para la realización de consultas en las que tengas en cuenta
diferentes criterios, por ejemplo proveedores con código postal X, Artículos con precio inferior a
10 euros, etc.
Al igual que las operaciones vistas en los anteriores apartados, la eliminación es una
operación sencilla en el tipo de base de datos que estamos tratando.
Para eliminar un registro de nuestra base de datos debemos:
1. Buscar el registro o conjunto de registros en la base de datos. Para ello haremos uso
del método queryByExample.
2. Usar la función next para apuntar al registro a eliminar.
3. Usar la función deiete incluyendo entre paréntesis el objeto obtenido a partir del
método next, es decir objeto a borrar.
ACTIVIDAD 11.9
Añade un formulario llamado eliminarProveedores en el que incluyas una lista con todos los
campos de la tabla Proveedores, un cuadro de texto, un botón consultar y un objeto Jtable de
forma que el usuario pueda seleccionar un campo de la lista, escribe un valor en el cuadro de
texto y al pulsar el botón se muestre en el Jtable los registros que cumplen la condición
especificada. Inserta un botón eliminar tal que al hacer clic sobre el registro obtenido, este sea
eliminado.
Capítulo 11. Gestión de bases de datos. Bases de datos orientadas a objetos
COMPRUEBA TU APRENDIZAJE
1. ¿Qué entiendes por base de datos relacional? ¿Qué elementos la forman?
2. ¿Qué pasos hemos de seguir para conectar nuestro proyecto con una base de datos
relacional en C#?
10. ¿Qué tipo de operaciones realizamos en bases de datos orientadas a objetos? ¿Qué
métodos usamos en C# y Java?
ACTIVIDADES DE AMPLIACION
1. Supongamos que hemos diseñado en papel, siguiendo las instrucciones del módulo Bases
de Datos, una base de datos relacional en la que encontramos Persona tal que de ellas
derivan las clases Estudiante, Becario y Trabajador. Desarrolla la base de datos en Access
y posterionnente crea en Visual Studio ima aplicación que inserte, elimine, modifique,
busque, etc., los datos de esta base de datos relacional.
2. Crea en Netbeans, con el uso de db4o una aplicación que gestione la base de datos de la
Actividad de Ampliación 1 como una base de datos orientada a objetos.
3. Desarrolla en C# el modelo de clases de la base de datos de las Actividades de
Ampliación 1 y 2 tal que configures cada propiedad concienzudamente. Crea una péqueña
aplicación de consola en C# que la gestione.
4. Crea una nueva base de datos orientada a objetos en la que gestiones la información
relacionada con un zoo no demasiado grande. Debes incluir personas, tal que tenemos
trabajadores del zoo, usuarios (clientes, personas que acceden al zoo) y socios. Además,
los animales se clasifican en acuáticos, terrestres y voladores. Debes clasificar cada
animal del zoo en una de estas categorías. Realiza la codificación en Java y C#.
5. Tras aseguramos que la base de datos de animales del zoo está abierta, contiene
infonnación,^ realiza una serie de consultas sobre ellas, por ejemplo, algún animal
proviene de África, cuantos tipos de monos existen y en qué se diferencian, etc.
Desarrolla una base de datos para gestionar el servicio de comedor de un colegio. Es
necesario apuntar a cada niño o niña que se queda a comer en el comedor del centro así
como qué ha comido. Se deben generar al menos las clases niño y comida. Una vez que el
modelo y las clases de la base de datos estén bien diseñados, crea una aplicación que
realice todas las operaciones necesaria sobre la base de datos: insertar alumno, modificar
alumno, eliminar alumno, establecer comida para cada niño, etc.
RESUMEN DEL CAPITULO
12.2. COLECCIONES EN C#
Todas las colecciones que vamos a ver en este lenguaje de programación derivan de
ICollection, IList o IDictionary. A su vez IList e IDictionary derivan de ICollection de forma
que ya sea directa o indirectamente todas las colecciones derivarán de ICollection. Entre los tipos
de colecciones que implementan ICollection, IList o IDictionary encontramos:
■ Array.
■ ArrayList y List.
■ Hashtable y Dictionary.
■ SortedLlst y SortedDictionary.
■ Queue.
■ Stack.
12.2.1. ARRAY
La clase Array no se encuentra en el espacio de nombre System.Collection (la localizamos en
System), pero aún asi, es considerada como una colección ya que implementa IList. Proporciona
métodos para la creación, manipulación, búsqueda y ordenación de arrays o matrices, se usa
como clase base para todas las matrices.
En una Array:
■ Un elemento del Array es un valor concreto del Array.
■ La longitud es el número de elementos que puede contener.
■ El rango establece el número de dimensiones, por ejemplo si rango es igual a dos
tendremos un Array de dos dimensiones.
■ El limite inferior del Array en una dimensión es el índice inicial del Array para esa
dimensión.
■ El limite superior del Array en una dimensión es el índice del último elemento en esa
posición.
Capítulo 12. Colecciones 465
return nombre;
nombre = valué;
Para finalizar, veamos algunos de los métodos y propiedades característicos de la clase Array:
■ Length. Propiedad. La hemos usado con frecuencia. Devuelve el número total de
elementos de todas las dimensiones del Array. Encontraremos otra propiedad similar
a esta, LongLength. La primera de ellas devuelve el número como entero de 32 bits
mientras que la segunda devuelve el valor como entero largo(64 bits).
■ Rank. Propiedad. Devuelve el número de dimensiones o rango del Array.
■ CloneO- Método. Crea una copia del /Vrray que hace la llamada al método.
Capítulo 12. Colecciones 467
■ Una única dimensión. Un objeto Array puede representar rma matriz de rMgo mayor
a uno mientras que los objetos de tipo ArrayList y List representarán siempre
matrices de una única dimensión.
12.2.2.1. ARRAYLIST
Un objeto de tipo ArrayList implementa la interfaz IList. Básicamente representa un array de
una única dimensión que aumenta dinámicamente en función de las necesidades de la aplicación
que lo usa.
NOTA: Ya que ArrayList está incluida en el espacio de nombres Collections es
necesario añadir en la parte superior de nuestras aplicaciones using System.Collections.
Los métodos son similares a los estudiados para un objeto de tipo Array. Veamos un
ejemplo sencillo.
static public int menú()
{
int opcion;
Consolé.WriteLine("1. Insertar nuevo numero");
Consolé.WriteLine("2. Eliminar un número");
Consolé.WriteLine("3. Buscar numero");
Consolé.WriteLine("4. Búsqueda binaria");
Consolé.WriteLine("5. Mostrar números");
Consolé.WriteLine("6. Salir");
Consolé.WriteLine("Opcion:");
opcion = int.Parse(Consolé.ReadLineO);
return opcion;
case 1: Consolé.WriteLine("Numero:");
numero = int.Parse(Consolé.ReadLine());
números.Add(numero); //(2)
break;
case 2: Consolé.WriteLine("Numero:");
numero = int.Parse(Consolé.ReadLineO);
números.Remove(numero); //(3)
break;
case 3: Consolé.WriteLine("Numero:");
numero = int.Parse(Consolé.ReadLine());
//(4)
Consolé.WriteLine(números.Contains(numero)?
"Número encontrado en el Array":"Número inexistente");
break;
case 4; Consolé.WriteLine("Numero:");
numero = int.Parse(Consolé.ReadLineO);
números.SortO ; //(5)
Consolé.WriteLine(((posicion=numeros.BinarySearch(numero))
!=-l)?"Número encontrado en la posición"+posicion
:"Número no encontrado");
break;
case 5;
foreach (int num in números)
Consolé.WriteLine("Numero:{O}",num);
break;
■ //(5). Uso del método Sort. Este ordena la lista de objetos. Una línea más abajo se
hace uso además del método BinarySearch que busca un objeto en un ArrayList
ordenado.
//Proveedores.es \
class Proveedores:IComparable 1
{ i
int refProveedor; 1
string nombre; ;
string dirección; ;
string codigoPostal; 1
string ciudad; i
string pais; 1
string telefono; I
//ListaProveedores.es
^Is-Ss ListaProveedores
{
ArrayList listaProveedores; //Usamos un objeto ArrayList para almacenar
//Proveedores
public ListaProveedores()
pos = i;
return pos;
}
//Método de búsqueda según nombre
public int BuscarNombre(string nombre)
{
int pos = -1;
int i = 0;
while (pos == -1 && i < listaProveedores.Count)
{
if (((Proveedores)listaProveedores[i]).Nombre.CompareTo(nombre)
pos = i;
return pos;
}
public void OrdenarListaO
{
listaProveedores.Sort();
}
public void Mostrar O
{
foreach (Proveedores proveedor in listaProveedores)
Consolé.WriteLine(proveedor.ToString());
piiblic int UltimaReferencia ()
{
if (listaProveedores.Count > 0)
{
return
((Proveedores)listaProveedores[listaProveedores.Count-1]).RefProveedor;
return 0;
return listaProveedores.Count;
}
public string this[int pos]
if (pos != -1)
return ((Proveedores)listaProveedores[pos]).ToStringO;
//Program.es "
static public int menú()
{
int opcion;
Consolé.WriteLine("1. Insertar nuevo proveedor");
Consolé.WriteLine("2. Eliminar proveedor por referencia");
Consolé.WriteLine("3. Buscar proveedor por nombre");
Consolé.WriteLine("4. Ordenar proveedores por nombre );
Consolé.WriteLine("5. Mostrar proveedores");
Consolé.WriteLine("6. Salir");
Consolé.WriteLine("Opcion:");
opcion = int.Parse(Consolé.ReadLineO);
return opcion;
}
static void Main(string[] args)
opcion = menú();
switch (opcion)
{
case 1: referencia = proveedores.UltimaReferencia();
proveedores.Insertar (referencia__+__l)_;_
break;
case 2: Consolé.WriteLine("Indica referencia a eliminar:");
referencia = int.Parse (Consolé.ReadLine());
proveedores.Eliminar(referencia);
break;
case 3: Consolé.WriteLine("Qué nombre de proveedor
desea buscar?:");
nombre = Consolé.ReadLine();
posición = proveedores.BuscarNombre(nombre);
Consolé.WriteLine(proveedores[posición]);
break;
case 4: proveedores.OrdenarLista();
break;
case 5: proveedores.Mostrar();
break;
)
Consolé.WriteLine("Pulse la tecla ENTER para continuar");
Consolé.ReadLine();
Consolé.Clear();
} while (opcion != 6);
NOTA: Aunque en ninguno de los ejemplos hemos usado el método Insert para
insertar elementos en la lista sería interesante hacer uso de él ya que una lista puede ser
borrada desde cualquier posición y un elemento puede ser insertado en cualquier lugar.
12.2.2.2. LIST
Podemos decir que la clase List es el equivalente genérico de ArrayList, es decir, a la hora de
definir un objeto List indicamos el tipo de datos que va a contener. Al usar un ArrayList no
indicamos en primera instancia qué tipo de elementos contiene, con lo que se pueden producir
errores en tiempo de ejecución al intentar realizar conversiones imposibles. La clase List es
similar a ArrayList con la diferencia que indicamos el tipo de datos del objeto que se va a
almacenar en él. List implementa la interfaz IList mediante im array cuyo tamaño aumenta
dinámicamente como ya hemos explicado (Apartado 12.2.2).
-— ,
Consolé.WriteLine("Personas en la lista...");
mostrar(listaPersonas);
listaPersonas.RemoveAt(1);
listaPersonas.Sort();
Consolé.WriteLine("\nLista ordenada...");
mostrar(listaPersonas);
listaPersonas.Reverse();
Consolé.WriteLine("\nLista invertida...");
mostrar(listaPersonas);
Consolé.ReadLine();
ACTIVIDAD 12.1
Modifica la Actividad 6.4 del Capítulo 6 de forma que uses un Objeto Array, ArrayList o List.
ACTIVIDAD 12.2
12.2.3. HASHTABLE
Una colección de tipo Hashtable estará formada por pares del tipo clave - valor. En este tipo
de colección los elementos no se encuentran identificados por su posición en la lista sino por un
elemento denominado clave que los diferencia de forma única. Así, vamos a tener objetos en el
Hashtable a los que asociaremos una clave única que usaremos para su identificación.
Es interesante su uso ya que gracias a esta colección podremos realizar búsquedas en función
de un dato representativo del objeto valor que se almacena, por ejemplo, si la clave es la
referencia de un proveedor es más sencillo encontrar este entre todos los objetos de la colección.
La clave puede ser cualquier tipo de objeto, al igual que el valor, eso sí, la clave no acepta
valores vacíos o nuil, a diferencia de los elementos valor.
Son interesantes las propiedades Keys y Valúes que permiten acceder a todas las claves y
valores de una colección tipo Hashtable.
Véase el siguiente ejemplo para entender su uso. Imaginemos que en esta ocasión disponemos
de una clase llamada Clientes con los atributos y métodos que se indican.
• — - -- — — -- — —I
//Clientes.es ;
class Clientes I
{ i
string referencia; ;
string nombre; 1
string dirección;
string codigoPostal;
string ciudad;
string pais;
string telefono;
//Program.es
static public int menú()
(
int opcion;
Consolé.WriteLine("1. Insertar
Insertar nuevo el
nuevo cliente");
Consolé.WriteLine("2. Eliminar cliente por referencia");
Consolé.WriteLine("3. Buscar cliente por
pe referencia");
Consolé.WriteLine ("4. Mostrar clientes");
clientes"
Consolé.WriteLine("5. Salir");
Consolé.WriteLine("Opcion:");
opcion = int.Parse(Consolé.ReadLineO);
return opcion;
í
break;
Al igual que ocurría con ArrayList y List, Dictionary es el equivalente genérico de Hashtable.
Así, podremos usar los métodos vistos a diferencia que de antemano establecemos el tipo de
datos que vamos a almacenar en la colección.
Si para el ejemplo visto en el Apartado 12.2.3 usáramos un objeto de tipo Dictionary sólo
tendríamos que modificar la variable de tipo Hashtable por la que sigue:
Dictionary<string,Clientes> colección = new Dictionary<string,Clientes> (); |
)
El resto del código no tiene que ser modificado ya que los métodos son iguales en Hashtable y
Dictionary.
A la hora de definir un objeto de tipo Dictionary se deben indicar los tipos de datos tanto de la
clave como del valor, de ahí que en la declaración se observe: Dictionary<string,Clientes>.
Acabamos de establecer que la clave asociada a cada valor a de ser de tipo string mientras que
cada valor será una instancia de la clase Clientes.
Al ser una lista ordenada por clave, a la hora de insertar un objeto mediante el método Add
este lo coloca en la posición adecuada para mantener el orden de claves, así:
SortedList listaOrdenada = new SortedList O;
listaOrdenada.Add(1,'m');
listaOrdenada.Add(3, 'h');
listaOrdenada.Add(2, 'a');
a - h
1istaOrdenadaPersonas.Add("Jiménez",new Persona("Isabel","Jiménez"));
listaOrdenadaPersonas.Add("López", new Persona("Pablo", "López"));
listaOrdenadaPersonas.Add("Aznar", new Persona("Inma", "Aznar"));
listaOrdenadaPersonas.Add("Márquez", new Persona("José Antonio", "Márquez"));
Consolé.ReadLine();
12.2.6. QUEUE
12.2.7. STACK
El objeto Stack representa una colección tipo LIFO, último en entrar primero en salir. Es una
colección genérica (System.Collection.Generic) cuyos métodos más significativos son:
■ Peek. Devuelve el objeto situado al inicio sin eliminarlo.
■ Pop. Quita y devuelve el objeto que se ubica al principio de la lista.
■ Push. Inserta un objeto al principio de la lista.
ACTIVIDAD 12.3
Realiza una aplicación que controle la lista de personas que accede a un cine a recoger
entradas para ver una película, así como la venta de entradas. El programa parte de una cola de x
personas, cada una de ellas al llegar a la taquilla (ser la primera persona de la cola) pide un
número de entradas, la aplicación mostrará localidades libres con el fin de que la persona
concreta elija los asientos. Al finalizar la operación se indica precio, lista de asientos ocupados y
se saca a la persona de la lista. La aplicación finalizará cuando se vacíe la cola de personas o no
queden más entradas que vender.
ACTIVIDAD 12.4
■ Hashtable.
■ LinkedList.
■ Properties.
■ Stack.
■ TreeMap.
■ TreeSet.
■ Vector.
■ WeakHashMap.
Las colecciones Java se encuentran en la librería java.util.
12.3.1. ARRAYLIST
Objeto similar en funcionalidad al ArrayList visto en Java, sin embargo, podemos definir este
de forma genérica o no según nos interese.
- n
array.add(2); ■
array.add(9.6); i
array.add("Hola"); I
while(opcion != 3){
System.out.println("¿Qué deseas añadir?");
System.out.println("1. Numero entero");
System.out.println ("2. Cadena");
System.out.println("3. Salir");
opcion=Integer.parseint(teclado.readLine());
switch(opcion){
case 1:
arrayPrimitivos.add(Integer.parseint(teclado.readLine()));
break;
case 2;
arrayPrimitivos.add(teclado.readLine());
break;
while (!arrayPrimitivos.isEmpty()){
Object e1emento=arrayPrimitivo3.remove(O);
if(elemento instanceof Integer){
cuentaEnteros++;
}
else if (elemento instanceof String){
cuentaString++;
Capítulo 12. Colecciones 481
System.out.printf("Enteros:%d - Cadenas:%d"
,cuentaEnteros, cuentaString);
}
catch(NumberFormatException error){
System.out.println ("Error en la conversión de tipos.
Código de error+" + error.getMessage());
}
catch(lOException error){
System.out.println ("Error en la entrada estándar de datos.
Código de error+" + error.getMessage());
12.3.2. VECTOR
Un objeto de tipo Vector es similar a ArrayList aunque presenta mayor número de métodos.
Vector representa un array de objetos que aumenta o disminuye de fonna dinámica en función de
las operaciones que se realizan sobre los datos.
Entre sus métodos destacados:
Además se siguen manteniendo métodos del tipo add,remove, etc., vistos en el ArrayList.
ACTIVIDAD 12.5
Busca información en la web o bibliografía aportada por el profesor de las otras colecciones
Java enunciadas. Observa diferencias y similitudes con sus homólogas en C#.
ACTIVIDAD 12.6
Escoge alguna de las eoleeeiones vistas en la Actividad 12.5 y realiza un pequeño programa
donde hagas uso de ella.
COMPRUEBA TU APRENDIZAJE
1. ¿Qué es una colección?
2. ¿Qué tipos de colecciones hemos estudiado en este capítulo?
3. ¿Qué método utiliza un ArrayList en C# para añadir im objeto a la colección? ¿Y para
eliminarlo?
ACTIVIDADES DE AMPLIACION
Imagina que necesitas mantener una lista ordenada de vehículos. Cada vehículo se
enumera e identifica con una clave del tipo vXXXX, por ejemplo, vOOOl, v0120, etc.
De cada coche vamos a almacenar su matrícula, modelo, tipo, número de puertas, color,
potencia y observaciones. Crea un programa de consola con las clases necesarias para
cumplir las especificaciones dadas.
Usa las clases codificadas en la Actividad de Ampliación 1 y desarrolla una interfaz
gráfica que permita insertar un nuevo coche, visualizar un coche según una
característica dada (por ejemplo matrícula), etc. Complica la aplicación tanto como
desees suponiendo que estas diseñando la aplicación de un concesionario de vehículos.
Añade mayor funcionalidad a la Actividad de Ampliación 2 de fonna que cuando se
cierre el programa los vehículos sean almacenado en un fichero binario. Además,
incluiremos una nueva opción por la que se pueda cargar la información de un conjunto
X de vehículos a partir de un fichero binario.
Para asegurar nuestros ficheros de vehículos vamos a establecer una cabecera en ellos
cada vez que sean guardados, es decir, todos los ficheros de la aplicación desarrollada
en las actividades anteriores comenzarán con el texto: Ap. Vehiculos_v.01.
Autor:Nombre_lector.
Genera una aplicación que permita almacenar objetos de tipo Juguetes. El objetivo es
tener contabilizados y registrados todos los juguetes de un aula de infantil en una
guardería. Así, todos los objetos con los que se distraen los niños se denominarán
juguetes pero se distinguen grupos como: muñecas, carros, puzles, etc., (agregar
aquellos que el lector desees, el objetivo es generar un esquema jerárquico de herencia).
La aplicación permite; dar de alta un juguete (insertarlo en la lista), dar de baja un
juguete (en caso de que se haya roto o este deteriorado), modificar estado de un juguete
(tal que podamos especificar el estado físico en el que se encuentra el juguete), buscar y
listar el total de juguetes dados de alta. Usa alguna de las colecciones vista en el
capítulo.
Realiza una aplicación que gestione la entrada de una cola de personas a un concierto de
rock. Antes de que se abran las puertas del concierto, cada persona a cogido la vez de
forma que sabe justo detrás de que otra persona debe entrar. Al acceder a la puerta de
acceso al concierto deben indicar su DNI, primer apellido y número de entrada. La
aplicación almacenará los DNIs, primer apellido y número de entrada en un fichero de
texto. Además, debe contarse el número total de personas que han accedido al recinto.
Capitulo 12. Colecciones 483
Crea una aplicación gráfica que simule una libreta de notas. El objetivo es que la
persona inserte notas en la aplicación y vaya eliminando estas en función de si realizan
o no las tareas. Además, se debe tener opción a dar énfasis a determinadas tareas, es
decir, asociar a cada tarea un atributo que determine el grado de importancia de la tarea
en cuestión. Si esta es muy importante se visualizará cada vez que se acceda al
programa. Es conveniente mantener un fichero donde almacenar las notas pendientes.
Programación
Este texto tiene una orientación fundamentalmente
práctica; para ello, se ha intercalado un buen núme
ro de actividades entre los contenidos teóricos para
asimilar las ideas y dinamizar el desarrollo de las clases.
Además al final del libro se incluyen Actividades de am
pliación y Comprueba tu aprendizaje.
Los objetivos principales que se alcanzarán estudiando
este libro serán los siguientes:
• Conceptos básicos relacionados con el software, como
qué se entiende por programa o algoritmo y qué diferen
cia existe entre programa y proceso, lenguaje de pro
gramación, clasificación de los lenguajes de programa
ción, compilación del software o entornos de desarrollo
preparados para la creación de software. Centraremos
nuestra atención en lenguajes como C# y Java y los IDE
Visual Studio y Netbeans.
Q.^ • Metodología de la programación. Antes de comenzar a
< < programar en C# o Java se realizarán pequeños algorit
O) O
mos al mismo tiempo que se estudian los componentes
■o >, principales de un programa estructurado. Creación de
diagramas de flujo y pseudocódigos.
o < • Una vez se conocen los elementos que componen un
t Q programa estructurado se pasarán a codificar estos en
OJ
(/) C# y Java. Variables, identificadores, tipos de datos
O)
Q
simples y compuestos, sentencias de control alternati
vas o bucles, etc., consiguiendo construir aplicaciones
funcionales.
• Programación orientada a objetos. Los conceptos prin
cipales que conforman este paradigma de la programa
ción. Clases, objetos, herencia, polimorfismo, interfaz,
etc.
• Desarrollo de aplicaciones de consola y aplicaciones
gráficas. Se profundizará en los elementos que forman
una aplicación gráfica, así como en la programación
orientada a eventos.
• Flujos de datos. Programación de aplicaciones.que ges
tionan el flujo de información entre diferentes tipos de
dispositivos, sobre todo entre el software y un dispositi
vo de almacenamiento elegido.
» Gestión de errores tanto en la compilación como en
tiempo de ejecución (excepciones).
• Desarrollo de aplicaciones de gestión de bases de da
tos relaciónales o bases de datos orientadas a objetos
(BDOO) en C# y Java.
> Colecciones típicas de C# y Java como ArrayList, List,
etc.
ISBN 978-84-1545-259-1
www.garceta.es
grupo editorial
9 788415 452591
Programación
Este texto tiene una orientación fundamentalmente
práctica; para ello, se ha intercalado un buen núme
ro de actividades entre los contenidos teóricos para
asimilar las ideas y dinamizar el desarrollo de las clases.
Además al final del libro se incluyen Actividades de am
pliación y Comprueba tu aprendizaje.
Los objetivos principales que se alcanzarán estudiando
este libro serán los siguientes:
• Conceptos básicos relacionados con el software, como
qué se entiende por programa o algoritmo y qué diferen
cia existe entre programa y proceso, lenguaje de pro
gramación, clasificación de los lenguajes de programa
ción, compilación del software o entornos de desarrollo
preparados para la creación de software. Centraremos
nuestra atención en lenguajes como C# y Java y los IDE
Visual Studio y Netbeans.
Q.^ • Metodología de la programación. Antes de comenzar a
< < programar en C# o Java se realizarán pequeños algorit
O) O
mos al mismo tiempo que se estudian los componentes
■o >, principales de un programa estructurado. Creación de
diagramas de flujo y pseudocódigos.
o < • Una vez se conocen los elementos que componen un
t Q programa estructurado se pasarán a codificar estos en
OJ
(/) C# y Java. Variables, identificadores, tipos de datos
O)
Q
simples y compuestos, sentencias de control alternati
vas o bucles, etc., consiguiendo construir aplicaciones
funcionales.
• Programación orientada a objetos. Los conceptos prin
cipales que conforman este paradigma de la programa
ción. Clases, objetos, herencia, polimorfismo, interfaz,
etc.
• Desarrollo de aplicaciones de consola y aplicaciones
gráficas. Se profundizará en los elementos que forman
una aplicación gráfica, así como en la programación
orientada a eventos.
• Flujos de datos. Programación de aplicaciones.que ges
tionan el flujo de información entre diferentes tipos de
dispositivos, sobre todo entre el software y un dispositi
vo de almacenamiento elegido.
» Gestión de errores tanto en la compilación como en
tiempo de ejecución (excepciones).
• Desarrollo de aplicaciones de gestión de bases de da
tos relaciónales o bases de datos orientadas a objetos
(BDOO) en C# y Java.
> Colecciones típicas de C# y Java como ArrayList, List,
etc.
ISBN 978-84-1545-259-1
www.garceta.es
grupo editorial
9 788415 452591