Академический Документы
Профессиональный Документы
Культура Документы
USANDO
LENGUAJE JAVA
POR
CARLOS CUESTA IGLESIAS
2017
UNIVERSIDAD DE CALDAS
DEPARTAMENTO DE SISTEMAS E INFORMÁTICA
TABLA DE CONTENIDO
TEMAS Pág.
Práctica 1 ………………………………………………………………………………………………………………………. 1
Instalación del JDK
Práctica 2 ………………………………………………………………………………………………………………………. 2
Configuración de las variables de entorno
Práctica 3 ………………………………………………………………………………………………………………………. 5
Manejo básico de datos
Práctica 4 ………………………………………………………………………………………………………………………. 11
Configuración del entorno de trabajo y edición de archivos fuente
Práctica 5 ………………………………………………………………………………………………………………………. 16
Compilación y ejecución de programas
Práctica 6 ………………………………………………………………………………………………………………………. 16
Estructura de control secuencial
Práctica 7 ………………………………………………………………………………………………………………………. 18
Estructura de control condicional
Práctica 8 ………………………………………………………………………………………………………………………. 28
Estructuras de control repetitivas
Práctica 9 ………………………………………………………………………………………………………………………. 33
Lectura de archivos mediante la clase Scanner
Práctica 10 ……………………………………………………………………………………………………………………. 39
Estructuras unidimensionales y multidimensionales
Práctica 11 ……………………………………………………………………………………………………………………. 44
Funciones y métodos
Práctica 12 ……………………………………………………………………………………………………………………. 68
Introducción a la programación orientada a objetos
Práctica 13 ……………………………………………………………………………………………………………………. 80
Interfaces Gráficas de Usuario (GUI) – Una mirada a Swing
Práctica 14 ……………………………………………………………………………………………………………………. 103
Actividades y Documentación Transversales
INTRODUCCIÓN
Este compendio de prácticas busca fundamentalmente responder a dos necesidades: la primera es el
desarrollo de la lógica algorítmica de la que debe apropiarse cualquier persona que quiera desarrollar
programas de cómputo y la segunda, entender la base fundamental de los sistemas de desarrollo.
Muchas veces se pretende conocer todas las posibilidades que ofrece un lenguaje de programación, sin
siquiera conocer cómo está definido un dato desde la informática, cuáles tipos de datos existen y lo peor,
sin conocer la forma sistemática y detallada de resolver problemas algorítmicos o de dominar conceptos
básicos como las estructuras de control que permiten a los sistemas de cómputo optar por bifurcaciones
o repeticiones.
Lo expuesto, en el mejor de los casos lleva a construir programas que funcionan correctamente, pero cuya
construcción no es del todo correcta, adoleciendo esta de falta de documentación, de estructuración y de
la debida modularidad.
Erróneamente también se cae en dos extremos: el primero, utilizar un editor de texto no apto para la
escritura de algoritmos o el otro extremo, proponer un Entorno de Desarrollo Integrado (IDE) que por su
robustez impida conocer los detalles que entran en juego a la hora de compilar un programa.
Un editor de texto plano que ni siquiera diferencie mediante colores las distintas partes de las estructuras
sintácticas de un lenguaje, lo único que hace es desmotivar y, por otro lado, la curva de aprendizaje para
utilizar un IDE, unido a la alta automatización de tareas de configuración y programación que
proporcionan, no contribuyen a una temprana y buena fundamentación. Para dar sólo un ejemplo, muchos
estudiantes terminan por creer que Java y Netbeans son lo mismo o que Java y Eclipse son lo mismo, no
entendiendo que en realidad existe una definición de un lenguaje llamado Java, un JDK (Java Development
Kit) que es un conjunto de herramientas (programas y librerías) que permiten desarrollar (compilar,
ejecutar, generar documentación, de programas escritos en lenguaje Java y aplicaciones como Netbeans
y Eclipse que lo que hacen es proporcionar un entorno amigable de escritura y compilación de aplicaciones,
pero que a cambio demandan excelentes condiciones de rendimiento de las máquinas en que son usados.
Sin embargo, en medio de los limitados editores de texto plano y los IDE se ubican editores de código
fuente como Notepad++, Sublime1 y Visual Studio Code, que se convierten en el entorno ideal para llevar
a cabo las prácticas que requieren la fundamentación de la programación, que en últimas es lo que
pretende este trabajo.
Para cumplir con el objetivo, estas prácticas abordan la mínima fundamentación teórica y se centran en
un aspecto esencial: la solución algorítmica de problemas de cómputo, por lo tanto, no espere encontrar
propuestas de hermosas aplicaciones que se construyen arrastrando y soltando componentes mágicos,
sino sólo lo esencial para que más adelante las hermosas aplicaciones funcionen con la lógica esperada.
Para una segunda oportunidad estos mismos conceptos se utilizarán con el fin de profundizar en la
programación orientada a objetos y luego sí vendrán vistosas aplicaciones construidas a partir de
componentes reutilizables.
En síntesis, el autor de estas prácticas no cree que se pueda ser escritor sin antes dominar en una buena
medida, el léxico, la sintaxis y la gramática del lenguaje que se pretende utilizar para escribir.
Carlos Cuesta Iglesias
1
De los tres citados, Sublime es el único que no es totalmente gratuito por lo que, si no está dispuesto a comprarlo,
pero sí a usarlo, tendrá que lidiar con una molesta y periódica sugerencia de compra.
Prácticas de Java
Estas prácticas no sustituyen la fundamentación dada por el orientador de la asignatura, ni la apropiación
de conceptual autónoma a partir de consultas bibliográficas o de referencias de Internet.
Se diferencie entre el Java Development Kit (JDK), el conjunto de herramientas Java para construir
programas en Java y los Entornos de Desarrollo Integrado (IDE2).
Configurar variables de entorno, para facilitar la ubicación de utilidades en los sistemas operativos,
específicamente Windows.
1. Si con estas prácticas no se le entrega el instalable de Java Estándar Edition (JSE), por favor
descárguelo del enlace que se proporciona enseguida, el Java SE Development Kit (JDK):
http://www.oracle.com/technetwork/java/javase/downloads/index.html
Asegúrese de elegir la versión correcta para su sistema operativo y tenga en cuenta también si debe
elegir entre 32 o 64 bits, de acuerdo a la arquitectura de su computador.
2. Instale el JDK-xxxxxx. En la mayoría de los pasos se le guiará con un sencillo paso a paso como el que
muestra la figura siguiente:
2
El desarrollo de las prácticas de estos talleres se orientará con editores de texto y no con IDES, teniendo en
cuenta que la curva de aprendizaje de los editores de texto es mucho más rápida que la de los IDES.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 1/191
En los elementos “Development Tools”, “Source code” y “Public JRE”, seleccione “This feature, and
all subfeatures, will be installed on local hard drive”.
4. Observe que el programa de instalación le informa en qué carpeta quedará instalado Java. Recuerde
esta ruta, la necesitará unos pasos más adelante.
Para editar o agregar variables de entorno en Windows, siga los siguientes pasos:
1. Ubique Panel de control > Configuración avanzada del sistema y elija “Variables de entorno”. En la
ventana que se despliega, elija “variables de entorno”.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 2/191
2. En la nueva ventana que se muestra, se va a editar la variable PATH, para “hacerla de público
conocimiento” a cualquier proceso, dónde se encuentran las aplicaciones del JDK. Por lo tanto,
seleccione dicha variable y pulse sobre “Editar”.
Importante: para versiones anteriores a Windows 10, la interfaz para editar variables de entorno es
menos intuitiva y dichas variables aparecen separadas por punto y coma (;). Por lo tanto, deberá tener
cuidado de no modificar las existentes y de agregar la nueva variable de entorno al final de las que ya
existen y precedida por punto y coma. Enseguida el ejemplo y a pie página un video explicativo3:
C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\Common Files\Intel\Shared
Files\cpp\bin\Intel64;…;C:\Windows\system32; C:\Program Files\Java\jdk1.8.0_131\bin
4. Ahora probamos que en la variable de entorno PATH, haya quedado correctamente definida una
entrada que permita ubicar desde cualquier carpeta o unidad, las aplicaciones de Java, sin necesidad
de dar la ruta de instalación del JDK:
3
Configurar variables de entorno en versiones anteriores a Windows 10: https://www.youtube.com/watch?v=c714V-2xTSs
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 4/191
Si la ruta del JDK se ingresó correctamente a la variable de entorno PATH, se le mostrarán las opciones
que pueden ser usadas para compilar los distintos tipos de aplicaciones compilables.
Así, un dato tiene tres componentes básicos, el identificador, el tipo y el valor. Veamos un posible ejemplo
de datos de una persona:
Los identificadores comienzan con una letra, el carácter subrayado (_) o el carácter dólar ($).
Se puede incluir, pero no comenzar por un número.
No puede incluir el carácter espacio.
Distingue entre letras mayúsculas y minúsculas. Así, los identificadores horasTrabajadas y
HorasTrabajadas son distintos.
No se pueden utilizar las palabras reservadas4 del lenguaje Java como identificadores.
Antes de poder asignar un valor a un dato se debe conocer el nombre del dato o identificador y su tipo. En
Java existen los siguientes tipos de datos básicos:
4
Las palabras reservadas se pueden clasificar en las siguientes categorías:
1. Tipos de datos: boolean, float, double, int, char
2. Sentencias condicionales: if, else, switch
3. Sentencias iterativas: for, do, while, continue
4. Tratamiento de excepciones: try, catch, finally, throw
5. Estructurales: class, interface, implements, extends
6. Modificadores y control de acceso: public, private, protected, transient
7. Otras: break, super, null, this.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 5/191
Tipo Descripción
boolean Tiene uno dos valores true o false.
char Caracteres Unicode de 16 bits sin signo. Los caracteres se delimitan por comillas sencillas.
Ejemplo: 'C', 'c', '9', '$'. Un dígito encerrado entre comillas simples no es un número sino
un caracter.
byte Tamaño 8 bits. El intervalo de valores va desde -27 hasta 27 -1 (-128 a 127)
short Tamaño 16 bits. El intervalo de valores va desde -215 hasta 215-1 (-32768 a 32767)
int Tamaño 32 bits. El intervalo de valores va desde -231 hasta 231-1 (-2147483648 a
2147483647)
long Tamaño 64 bits. El intervalo de valores va desde -263 hasta 263-1 (-
9223372036854775808 a 9223372036854775807)
float Tamaño 32 bits. Números en coma flotante de simple precisión. Estándar IEEE 754-
1985 (de 1.40239846e–45f a 3.40282347e+38f)
double Tamaño 64 bits. Números en coma flotante de doble precisión. Estándar IEEE 754-1985.
(de 4.94065645841246544e–324d a 1.7976931348623157e+308d.)
Además de los tipos básicos descritos, también llamados datos escalares o simples porque sólo admiten
un valor, también existen los datos suscritos que pueden tener un conjunto de datos del mismo tipo. En la
práctica 10 se tratará en detalle el tema de los tipos de datos suscritos.
En algunos casos puede confundirse fácilmente el concepto de dato con el de objeto. Por ahora y para no
ahondar tempranamente sobre el concepto de objeto, se puede decir que un objeto se distingue porque
tiene distintas características (datos que lo describen) y admite unas funcionalidades determinadas. Por
ejemplo, un objeto de tipo String en realidad es un conjunto de caracteres que, dentro de sus
funcionalidades está la de poder conocer la cantidad de caracteres que conforman el String, la conversión
a mayúsculas o a minúsculas, etc.
Teniendo en cuenta lo expuesto, los datos de la persona del ejemplo anterior, se podrían describir en Java
de la siguiente manera:
String credencial = "52710695";
String nombre = "Carlos Cuesta Iglesias";
int horasTrabajadas = 20;
boolean activo = true;
Como se observa, los String o cadenas de caracteres, se delimitan por comillas dobles (").
Los lenguajes de programación difieren de los lenguajes humanos en que son muy estrictos en su sintaxis,
por lo tanto, siempre que se vayan a definir datos con un valor inicial deberá utilizarse la forma del
ejemplo, es decir:
tipo identificador = valor;
También pueden definirse datos sin asignarles un valor, en cuyo caso el contenido será nulo. Por ejemplo:
String credencial;
String nombre;
int horasTrabajadas;
boolean activo;
Si se quiere definir un dato como constante, es decir para no ser cambiado durante la ejecución de la
aplicación, se le antepone la palabra reservada final. Ejemplo:
Cuando se tienen dos operandos numéricos, dos datos numéricos, éstos se pueden relacionar mediante
un operador binario y obtener una operación aritmética con ellos. En Java existen los siguientes
operadores binarios, es decir que requieren dos operandos para poder ser usados:
OPERADOR DESCRIPCIÓN
+ Suma o concatenación5 según el contexto
– Resta
* Multiplicación
/ División
% Resto de una división entre enteros
Además del operador de asignación (=) que asigna al dato de la izquierda la expresión de la derecha,
existen los operadores de asignación que se describen en la tabla siguiente:
También existen los siguientes operadores aritméticos unarios, es decir que se usan con un solo operando:
5
Si alguno de los operandos relacionados mediante el operador (+) es un String, el resultado es la concatenación de
los operandos. Por ejemplo: 20 + "2017" no es una suma sino una concatenación de la que resulta: "202017". En
cambio, de la expresión '9' + 10 resulta el valor 67, porque al relacionar un caracter y un valor mediante el operador
(+), se tiene en cuenta el valor del código ASCII del carácter, en este caso 57.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 7/191
Importante: para la solución de los ejercicios que están al final de esta práctica, tenga en cuenta que
cuando en una expresión, los operadores ++ o -- preceden al operando, el valor del operando se altera
antes de evaluar la expresión, no así cuando dichos operadores van después del operando.
Cuando lo que se requiera es comparar datos según las relaciones de igualdad o desigualdad o según sean
estos mayores o menores, se utilizan los operadores relacionales que devuelven siempre un valor boolean:
Operador Significado
> Mayor que
< Menor que
== Iguales
!= Diferente
>= Mayor o igual que
<= Menor o igual que
Para cerrar el tema de los tipos de operadores6, se describen a continuación los operadores lógicos y el
operador ternario, que permiten construir expresiones lógicas:
Finalmente, se llama la atención de manera especial sobre la precedencia de los operadores, un conjunto
de reglas de Java que controla el orden en que el compilador realiza las operaciones cuando se evalúa una
expresión. Las operaciones con mayor precedencia se realizan antes que las de menor prioridad. Por
ejemplo, la multiplicación se realiza antes que la suma y la resta y las operaciones unarias antes que la
multiplicación y la división. Enseguida se incluye una tabla con la precedencia de los operadores que se
utilizarán en estos talleres.
Descripción Operadores
Operadores sufijos unarios op++ op--
Operadores prefijos unarios ++op --op +op -op !
Multiplicación y división */%
Suma y resta +-
Operadores relacionales < > <= =>
Equivalencia == !=
And booleano &&
Or booleano ||
Condicional ?:
Operadores de asignación = += -= *= /= %= &=
6
Por no ser parte del curso, se ha omitido cualquier explicación sobre los operadores a nivel de bits: >>, <<, & y |
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 8/191
Ahora pasemos de la teoría a la diversión. Suponga que se tienen las variables a = 10, b = 12, c = 13, d =
10, v = '5' (el dígito '5' está codificado como 53 en la tabla ASCII) y lleve a cabo los ejercicios propuestos.
2. Indique si es falso o verdadero que los resultados de las siguientes expresiones aritméticas
corresponden al valor resaltado en la parte izquierda de las expresiones:
27 = 4 + 2 * 5 + c++
Math.pow(a, 2) + Math.pow(b, 2)
Math.pow(a + b, 2)
Math.pow(b, 1.0 / 3) + 34
(x + y) / (u + (w / b))
x + (y / u) + (w / b)
(x / y) * (z + w)
Tomando como base los ejemplos anteriores convierta las siguientes expresiones aritméticas a
expresiones algorítmicas:
Importante: he observado que al elevar con Math.pow a un exponente fraccionario, si el numerador del
exponente no está expresado como un número real, se pueden dar resultados erróneos.
Se recomienda crear las carpetas con el mismo nombre dado aquí, para que siga con mayor facilidad
las instrucciones.
2. En la carpeta parte1, cree cada uno de los archivos fuentes de Java que se incluyen a partir de la
página siguiente, teniendo en cuenta:
El nombre del paquete (package) corresponde al nombre de la carpeta donde se guarda cada
archivo fuente.
El nombre del archivo corresponde al nombre de la clase que se define dentro de él.
Desde ahora adquiera la buena práctica de tabular debidamente los programas, tal como se
muestra en los demos de este tutorial.
3. Enseguida puede utilizar editores como Sublime, Visual Studio Code, NotePad++ o incluso el bloc
de notas, para abrir la carpeta donde se dispondrán los programas y luego crear un nuevo archivo
(New file) en donde escribirá el programa fuente, que luego se compilará.
Tenga en cuenta que todos los programas fuente de Java, tienen la extensión .java, tal como se
muestra en el panel de la izquierda del editor Sublime.
4. Terminada la creación de archivos, active la consola de Windows (cmd) y utilice los comandos
resaltados para entrar a la carpeta fundamentos y ver el contenido de ésta y también de la subcarpeta
parte1. Deberá obtener unos resultados similares a los que se muestran en la figura siguiente:
Ahora se tienen una carpeta (paquete) con cuatro pequeños programas fuente para realizar las primeras
pruebas de compilación y ejecución de aplicaciones.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 14/191
Nota complementaria: los comandos CD y DIR son parte de los comandos de consola de Windows,
heredados del DOS (Disk Operating System). Enseguida se describe brevemente su uso básico:
Si estando en el Explorador de archivos, se desea abrir la ventana de comandos en una ubicación específica
lo que hay que hacer, es pulsar Mayúscula + Clic derecho y de la ventana que aparece elegir la opción
“Abrir ventana de comandos aquí”. En el ejemplo dado en la figura siguiente, al utilizar este atajo, se abriría
la ventana de comandos con la carpeta “fundamentos” seleccionada.
Los nombres de los archivos fuente de Java, tienen exactamente el mismo nombre de la clase
La tabulación que debe dar a la estructura del código fuente (sangrado, Indentación) para dar
elegancia al código y facilitar su lectura. Se recomienda utilizar la tabulación y evitar el uso de la
barra espaciadora para forzar el sangrado.
La facilidad de lectura que proporciona Visual Studio Code, al colorear distintamente el código.
Los espacios interlineales que se utilizan para dar claridad al código.
La forma de concatenar cadenas y/o valores para mostrarlos por consola (pantalla).
El uso de nextTipoEntrada para permitir que el usuario ingrese datos al sistema.
También se puede deducir que un paquete de clases es un grupo de clases que agrupamos juntas
en una carpeta, porque consideramos que están relacionadas entre sí o tratan de un tema común.
Se compila el archivo fuente Demo000.java utilizando la instrucción javac. Observe que ésta
instrucción va seguida del paquete donde se encuentra el archivo fuente a compilar + “/” + nombre
del archivo fuente a compilar.
Se ejecuta el archivo compilado (.CLASS) mediante la instrucción java + “.” + nombre de la clase
compilada.
Compile cada una de las clases creadas en la práctica anterior, siguiendo el mismo procedimiento.
7
Un bloque de código en Java es el conjunto de instrucciones que está delimitado por llaves { … }
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 16/191
Al terminar esta práctica, se espera que domine los temas relacionados con definición de identificadores,
estilo de programación, documentación de código y sobre todo que siga el procedimiento correcto para
el análisis, diseño y construcción de aplicaciones con lógica secuencial.
Cree una carpeta (paquete) al mismo nivel de parte1, llamada estructura_secuencial y guarde en ella las
clases resultantes de resolver los ejercicios siguientes. Recuerde que antes de pensar en escribir código
debe analizar cada problema y llenar, para cada uno, una tabla como esta:
tipo2 dato2 … …
tipoX datoN … …
1. De acuerdo a los ejemplos dados en la parte inicial, complete el código del ejemplo de la figura
anterior, para convertirlo en la primera clase que guardará en el paquete estructura_secuencial.
Compile y pruebe la ejecución de la nueva clase.
2. Para éste y los siguientes enunciados de problemas, realice el análisis de cómo solucionarlo,
determine qué datos deben ingresarse y de qué tipo, qué cálculos son necesarios y cuál es la salida
que debe mostrarse. Hecho lo anterior, proceda a elaborar el código correspondiente:
Calcular lo devengado por un catedrático, conociendo las horas trabajadas, el valor de cada hora
y el descuento sobre el total pagado a un catedrático.
4. Calcular la nota definitiva de un estudiante del que se conoce su código, sabiendo que se le
califican dos parciales que valen el 20% y el 30%. Un taller que vale el 15%. Quices 5% y proyecto
final 30%.
5. Convierta grados sexagesimales a grados radianes, con dos cálculos distintos en la misma clase.
6. Cree una nueva clase para comprobar los resultados de las siguientes instrucciones:
int i = 1, j = 2, k = 3;
Al ejecutar la aplicación, asegúrese de entender por qué se dan los resultados que se dan.
7. Partiendo del supuesto de tener definidas las siguientes constantes: i = 7, f = 5.50, C = 'w'8,
determine manualmente el resultado que se da de evaluar las siguientes expresiones Java:
8
Para la constante “C” con valor 'w', la instrucción es: final char C = 'w';
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 17/191
Expresión Resultado Expresión Resultado
c >= 10 * (i + f) i + f <= 10
Importante: Tenga especial cuidado con el uso de comillas que se hace en la tabla anterior.
8. Elabore una aplicación que le permita verificar si los resultados obtenidos en el punto 7, son
correctos.
9. Deduzca qué resultados se obtienen del siguiente código y luego codifique la solución:
int i = 5, j = 7;
double f = 5.5, g = -3.25;
i += 5;
System.out.println(i);
f -= g;
System.out.println(f);
j *= (i - 3);
System.out.println(j);
f /= 3;
System.out.println(f);
i %= (j - 2);
System.out.println(i);
10. Con base al código anterior, elabore una aplicación que le permita verificar los resultados
obtenidos.
11. ¿Necesita reforzar este tema? – Consulte el anexo 1 al final de estas prácticas.
En la figura siguiente, se muestra el diagrama de flujo y la sintaxis utilizada en Java, para implementar el
tipo de condición descrita.
instrucción(es)
Como ejemplo de la anterior estructura, suponga un sistema de ofertas para compras superiores a 150 mil
pesos, en las que se aplica un descuento del 10%.
1 package condicion;
2
3 import java.util.Scanner;
4
5 public class If002 {
6
7 public static void main(String[] args) {
8
9 // si compra es superior a 150000, aplicarle un descuento a la compra del 10%
10 Scanner in = new Scanner(System.in);
11
12 double compra;
13
14 System.out.println("Ingrese valor de la compra: ");
15
16 compra = in.nextDouble();
17
18 if (compra > 150000) {
19 compra = compra * 0.90;
20 }
21
22 System.out.println("Valor de la compra total: " + compra);
23
24 }
25 }
Otro ejemplo puede ser pensar en que, para el cálculo del valor de la factura de agua, se tiene en cuenta
una multa del 11.5% para consumos superiores a 30 metros cúbicos.
1 package condicion;
2
3 import java.util.Scanner;
4
5 public class If004 {
6 /*
7 Dado los litros consumidos y el valor de cada litro,
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 19/191
8 si el consumo esta por encima de 30 metros cubicos, aplicar
9 una multa equivalente al 11,5% del valor total a pagar.
10 */
11 public static void main(String[] args) {
12 Scanner in = new Scanner(System.in);
13 double litrosConsumo, valorLitro, valorTotal;
14
15 System.out.println("Ingrese litros consumidos: ");
16 litrosConsumo = in.nextDouble();
17
18 System.out.println("Ingrese valor del litro: ");
19 valorLitro = in.nextDouble();
20
21 valorTotal = litrosConsumo * valorLitro;
22 if (litrosConsumo > 30) {
23 valorTotal = valorTotal * 1.115;
24 System.out.println("Su consumo sobrepasa 30 litros. Se le aplica multa de 11.5%");
25
26 }
27 System.out.println("Por el consumo de " + litrosConsumo +
" litros El valor es de " + valorTotal);
28 }
29 }
Otra forma posible se da cuando la aplicación debe decidir, ejecutar las instrucciones de la parte verdadera
o de la parte falsa. Observe el diagrama de flujo y la sintaxis de Java, en la figura siguiente.
if (condición) {
instrucción(es) parte verdadera
} else {
instrucción(es) parte falsa
}
Un ejemplo es tener las tres notas de un estudiante y promediarlas. Si el promedio es inferior a 3.0, la
aplicación informará “perdió la materia”, de lo contrario imprimirá “ganó la materia”.
1 package condicion;
2
3 import java.util.Scanner;
4
5 public class If007 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9
10 double nota1, nota2, nota3, definitiva;
11
12 System.out.println("Primera nota: ");
13 nota1 = in.nextDouble();
14
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 20/191
15 System.out.println("Segunda nota: ");
16 nota2 = in.nextDouble();
17
18 System.out.println("Tercera nota: ");
19 nota3 = in.nextDouble();
20
21 definitiva = (nota1 + nota2 + nota3) / 3;
22
23 System.out.println("Definitiva: " + definitiva);
24 if (definitiva < 3) {
25 System.out.println("Perdió la materia");
26 } else {
27 System.out.println("Ganó la materia");
28 }
29 }
30 }
Otra forma condicional consiste en verificar varias alternativas, lo cual da lugar a una construcción como
la que se muestra enseguida:
if (condicion1) {
Instrucciones-1
} else if (condicion2) {
Instrucciones-2
} else if (condicion3) {
Instrucciones-3
.
.
} else if (condicionN) {
Instrucciones-N
} else {
Instrucciones por defecto
}
Un sencillo ejemplo de este caso, es permitir al usuario ingresar el número correspondiente a un mes y
mostrar el nombre de dicho mes. Veamos:
1 package condicion;
2
3 import java.util.Scanner;
4
5 public class If006 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9
10 int mes;
11 System.out.println("Introduzca el número de mes: ");
12 mes = in.nextInt();
13
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 21/191
14 if (mes == 1) {
15 System.out.println("Enero");
16 } else if (mes == 2) {
17 System.out.println("Febrero");
18 } else if (mes == 3) {
19 System.out.println("Marzo");
20 } else if (mes == 4) {
…
36 } else if (mes == 12) {
37 System.out.println("Diciembre");
38 } else {
39 System.out.println("Número de mes incorrecto");
40 }
41 }
42 }
El siguiente ejemplo de varias alternativas, supone que se necesita implementar un programa que, dados
los datos: categoría, días trabajados y número de horas extras, calcula según la tabla que se presenta más
abajo: pago de horas extras, aporte a un fondo de solidaridad, auxilio de transporte, aportes a EPS y
pensión (10%) y salario neto recibido.
1 package condiciones;
2
3 import java.util.Scanner;
4
5 public class TablaSueldos {
6
7 public static void main(String[] args) {
8 Scanner scanner = new Scanner(System.in);
9
10 final double EPS_PENSION = 0.10;
11 int categoria, horasExtras, diasTrabajados;
12 double eps_Pension, salarioNeto, salarioBase, fondoSolidaridad, transporte, pagoExtras = 0, vrHora;
13
14 System.out.println("Ingrese la categoría: ");
15 categoria = scanner.next().charAt(0);
16
17 System.out.println("Ingrese los días trabajados: ");
18 diasTrabajados = scanner.nextInt();
19
20 System.out.println("Ingrese el número de horas extras: ");
21 horasExtras = scanner.nextInt();
22
23 if ((categoria == 'A') || (categoria == 'B')) {
24 vrHora = 1000000 / 192;
25 salarioBase = (1000000 / 30.0) * diasTrabajados;
26 pagoExtras = horasExtras * vrHora;
27 salarioNeto = salarioBase + pagoExtras;
28 eps_Pension = salarioNeto * EPS_PENSION;
Se puede decir que las estructuras condicionales se pueden anidar de manera libre, según las alternativas
que sea necesario implementar. En estos casos, las instrucciones de la parte verdadera o de la parte falsa,
pueden anidar a su vez otras condiciones. El diagrama siguiente muestra uno de estos casos,
específicamente para la parte falsa de la condición.
La estructura de control switch nos permite ejecutar diferentes bloques de instrucciones (casos) en
función del resultado de una expresión. La forma general o sintaxis de la instrucción switch, es la siguiente:
Esta estructura se podría comparar con una forma de anidamiento de if…else…if…, similar al ejemplo dado
para mostrar los nombres de los meses del año, según el número del mes. Su uso no puede considerarse,
por tanto, estrictamente necesario, puesto que siempre podrá ser sustituida por el uso de if. No obstante,
en algunos casos, proporciona mejor claridad en el código.
1. No puede haber dos etiquetas de caso con el mismo valor. La aplicación marcará error si esto llega
a ocurrir.
2. La instrucción break9 es opcional y se utiliza para finalizar el switch tras la ejecución de un case.
Como se muestra en la figura, si la sentencia break no estuviera, al salir de un bloque case entraría
en el siguiente, aunque el valor de ese case no coincidiera con el evaluado en la expresión.
El case default se ejecuta si el resultado de la expresión no coincide con ningún case. Su uso también es
opcional. En el siguiente ejemplo se usa switch para permitir al usuario optar por un tipo de operación
aritmética (suma, resta, multiplicación o división), a ejecutar entre dos operandos:
1 package casos;
2
3 import java.util.Scanner;
4
5 public class Caso001 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9
10 int a, b;
11 char operador;
12
13 System.out.println("Primer valor : ");
14 a = in.nextInt();
15
16 System.out.println("Segundo valor : ");
17 b = in.nextInt();
18
19 System.out.println("Operación: ");
20 operador = in.next().charAt(0);
21
22 switch (operador) {
23 case '+':
24 System.out.println(a + " + " + b + " = " + (a + b));
25 break;
26 case '-':
27 System.out.println(a + " - " + b + " = " + (a - b));
28 break;
29 case '*':
30 System.out.println(a + " * " + b + " = " + (a * b));
31 break;
32 case '/':
33 System.out.println(a + " / " + b + " = " + (a / b));
34 // break; // OJO: qué pasa si se omite la instrucción break
35 case '%':
36 System.out.println(a + " % " + b + " = " + (a % b));
37 break;
38 default:
39 System.out.println("error");
40 break;
41 }
42 }
43 }
9
Más adelante se describen otros contextos de la instrucción break.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 26/191
Actividad complementaria
Antes de proceder a codificar estos ejercicios, elaborar una tabla de análisis donde se registren las
variables de entrada, los cálculos y los datos de salida.
4. Leer un caracter y deducir si está o no comprendido entre las letras I y M ambas inclusive.
5. emitir la factura correspondiente a una compra de un artículo determinado del que se adquieren
una o varias unidades. El IVA a aplicar es del 16% y si el precio neto (precio de venta + IVA) es
mayor que 50000 pesos, se aplica un descuento del 5%.
6. Dados tres números definir cuál es el central. Ejemplo: se ingresa 10, 2 y 20. El sistema determinará
que el central es 10, porque está entre 2 y 20.
7. Calcular la raíz cuadrada de un número, escribir su resultado cuando sea posible o informar cuando
la solución no sea posible.
while (expresionLogica) {
instrucciones(s);
}
Para proporcionar un ejemplo de este tipo de estructuras, se puede pensar en crear una aplicación que
permita leer valores mientras el número ingresado sea distinto de cero. Al final se debe mostrar la suma
de los valores introducidos (acumulador) y el total de valores leídos (contador).
1 package mientras;
2
3 import java.util.Scanner;
4
5 public class While002 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9 int i = 0; // contador
10 int total = 0; // acumulador
11 int num; // el valor ingresado
12
13 System.out.println("Introduzca un valor : ");
14 num = in.nextInt();
15
16 while (num != 0) {
17 total += num;
18 System.out.println(" " + num);
19 i++;
20 System.out.println("Introduzca un valor : ");
21 num = in.nextInt();
22 }
23
24 System.out.println("La cantidad de numeros leídos es: " + i);
25 System.out.println("Los valores leídos suman: " + total);
26 }
27
28 }
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 28/191
El algoritmo de Euclides es un procedimiento para calcular el máximo común divisor (M.C.D.) de dos
números, mediante el siguiente algoritmo:
2. Si:
b. La división no es exacta, dividimos el divisor entre el resto obtenido. Es decir que para la
siguiente repetición si la hay, el divisor pasa a ser el último resto obtenido.
3. Se vuelve al paso 1, mientras la división no sea exacta, es decir, mientras el resto de dividir valor1
sobre valor2 sea distinto de cero.
1 package mientras;
2
3 import java.util.Scanner;
4
5 public class While001 {
6 // Máximo común divisor entre dos números:
7
8 public static void main(String[] args) {
9 Scanner in = new Scanner(System.in);
10 int valor1, valor2, resto, mcd;
11
12 System.out.println("Primer valor : ");
13 valor1 = in.nextInt();
14
15 System.out.println("Segundo valor: ");
16 valor2 = in.nextInt();
17
18 while (valor1 % valor2 != 0) {
19 resto = valor1 % valor2;
20 valor1 = valor2;
21 valor2 = resto;
22 }
23 mcd = valor2;
24 System.out.println("El máximo común divisor es: " + mcd);
25 }
26 }
Como se comprobó, en la estructura de control while la evaluación se realiza antes de entrar al ciclo, lo
que significa que la iteración puede no llegar ejecutarse. En cambio, en un ciclo do … while, la evaluación
se hace después de la primera ejecución del ciclo, lo que significa que el bucle obligatoriamente se ejecuta
al menos en una ocasión. Observe la forma general o sintaxis de esta instrucción.
Como ejemplo, retomemos la primera demostración de la estructura de control while, en la que una
aplicación permite leer valores mientras el número ingresado sea distinto de cero. Al final se debe mostrar
la suma de los valores introducidos (acumulador) y el total de valores leídos (contador).
1 package haga;
2
3 import java.util.Scanner;
4
5 public class Haga003 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9
10 int i = 0; // contador
11 int total = 0; // acumulador
12 int num = 0; // el valor ingresado
13
14 do {
15 i++;
16 System.out.println("Paso " + i + ", introduzca un valor: ");
17 num = in.nextInt();
18 total += num;
19 System.out.println(" " + num);
20 } while (num != 0);
21
22 System.out.println("La cantidad de numeros leídos es: " + i);
23 System.out.println("Los valores leídos suman: " + total);
24 }
25
26 }
La estructura de control for, es un ciclo condicionado al comienzo que consta de tres partes que se
encuentran separadas por punto y coma. La razón de estas tres partes es la siguiente:
En el siguiente ejemplo se utiliza la estructura for para generar una tabla de multiplicar de un número
dado por el usuario. En la primera parte del ciclo se especifica que se inicia en 1, en la segunda parte se
indica que se itera mientras el contador sea menor o igual que 10 y en la tercera parte se precisa que el
contador se incrementa de uno en uno.
1 package para;
2
3 import java.util.Scanner;
4
5 public class For001 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9 int i, tabla, numero;
10
11 //Leer un numero y calcular la tabla del 1 al 10 de ese numero.
12 System.out.println("Ingrese un número para generar la tabla de multiplicar: ");
13 numero = in.nextInt();
14
15 System.out.println("Tabla del " + numero);
16 for (i = 1; i <= 10; i++) {
17 tabla = numero * i;
18 System.out.println(numero + " * " + i + " = " + tabla);
19 }
20 }
21 }
En el siguiente ejemplo se puede observar que tanto en las partes que determinan el inicio y el cambio
que se va dando en la iteración se pueden ingresar varios términos separados por comas. Para este caso,
la variable k se utiliza para generar los valores del 1 al 5 y paralelamente, la variable j se usa para generar
los valores del 10 al 6.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 31/191
public static void main(String[] args) {
Caso 1: El for puede ser utilizado sin incluir las expresiones que determinan el número de iteraciones.
Observe un ejemplo:
public static void main(String[] args) {
int k = 0;
int j = 11;
for (;;) {
System.out.println(++k + " " + --j);
if (k >= j) {
break;
}
}
}
Para el código anterior se omitieron los términos que determinan el inicio, la condición de salida y el factor
de cambio del for, por lo tanto, fue necesario incluir una condición de salida que obligue a la terminación
mediante un break.
También observe que los operadores de incremento o decremento se pueden utilizar tanto a la izquierda
como a la derecha de la variable. En este caso los contadores k y j se incrementan antes de ser mostrados.
Caso 2: tanto while como do...while pueden utilizarse de la forma que se muestra enseguida, lo que
ocasiona que los ciclos queden iterando indefinidamente si no se incluye dentro de ellos una condición de
salida.
int k = 0;
int j = 11;
if (k >= j) {
break;
}
}
k = 0;
j = 11;
do {
System.out.println(++k + " " + --j);
if (k >= j) {
break;
}
} while (true);
Es válido anidar cualquier estructura de control dentro de otra. En los ejemplos anteriores fue necesario
anidar estructuras if dentro de estructuras de control de ciclos. Lo contrario también es válido: anidar
ciclos dentro de if o ciclos dentro de ciclos.
En el siguiente ejemplo se anida un ciclo dentro de otro para generar las tablas de multiplicar del 1 al 10.
Aunque es un ejemplo trivial, servirá de base más adelante para recorrer estructuras multidimensionales.
Adicionalmente, si los datos (tokens) en el archivo están separados por un caracter especial, permite
también recuperar los tokens individualmente. Por ejemplo, para recuperar tokens separados por punto y
coma (;) se agregaría una instrucción como la de la línea 11:
sc.useDelimiter(";");
Y para pasar por cada uno de los tokens que contiene el archivo se utilizaría el ciclo de la línea 16, donde
hasNext() devolverá true siempre que hayan más tokens para leer.
while (sc.hasNext()) {…}
Como cada registro del archivo representado en la figura anterior está separado por un salto de línea,
también se necesitará la instrucción sc.nextLine(); para saltar de línea en línea, descartando posibles
tokens y los "caracteres invisibles" que representan los saltos de línea.
A partir de la línea 17 se puede ver que los tres primeros tokens se recuperarán como Strings (cadenas de
caracteres), es decir, mediante next(), el cuarto token se recuperará como un entero, mediante nextInt()
y el último como un real, mediante nextDouble(). Así las cosas, la aplicación completa que se requiere para
leer un archivo como el de la figura anterior, es la siguiente:
1 package control_otros;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.util.Scanner;
6
7 public class LeerCSV {
8
9 public static void main(String[] args) throws FileNotFoundException {
10 try (Scanner sc = new Scanner(new File("varios/datos_nomina.csv"))) {
11 sc.useDelimiter(";");
12 String cedula = "", apellidos = "", nombres = "";
13 int categoria = 0;
14 double sueldoActual;
15
16 while (sc.hasNext()) {
17 cedula = sc.next();
18 apellidos = sc.next();
19 nombres = sc.next();
20 categoria = sc.nextInt();
21 sueldoActual = sc.nextDouble();
22
23 System.out.println("Cédula: " + cedula);
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 34/191
24 System.out.println("Apellidos: " + apellidos);
25 System.out.println("Nombres: " + nombres);
26 System.out.println("Categoría: " + categoria);
27 System.out.printf("Sueldo actual: %8.2f\n", sueldoActual);
28 System.out.println("-------------------------------");
29 sc.nextLine(); // leer el resto de tokens de la línea
30 }
31 }
32 }
33 }
Importante: para probar la aplicación anterior deberá tener un archivo con el nombre
"datos_nomina.csv", con una estructura como la mostrada en la figura de la página anterior y guardado
dentro de la carpeta fundamentos\varios. Usted deberá recibir con esta guía de fundamentos de
programación en Java, el archivo que se menciona. Si no es así lo puede solicitar al docente.
Los archivos con extensión CSV (Comma-Separated Values) pueden ser creados en Excel utilizando la
opción "Guardar como" > "CSV delimitado por comas". Este tipo de archivos es ampliamente utilizado para
el intercambio de datos, por lo que muchas aplicaciones importan o exportan datos en este formato.
El resultado que obtendrá al correr la aplicación anterior, será similar a lo que se muestra enseguida:
El paquete (package) que almacena una clase, tiene igual nombre que la carpeta que la contiene.
El Identificador de una clase corresponde al nombre del archivo de la clase.
Se recomienda que las palabras que conforman el identificador de una clase, se escriban con
mayúscula inicial y no se recomienda usar el guion para separar las palabras de dicho nombre.
Para no tener que especificar el nombre del paquete cada vez que se menciona una clase de otro
paquete, se usa la cláusula import.
Actividad complementaria
Esta actividad está pensada para evaluar el razonamiento lógico algorítmico desarrollado hasta ahora. Por
lo tanto, las estructuras de programación utilizadas serán las mismas que se han venido utilizando hasta
el momento.
Se recomienda que implemente y pruebe cada punto antes de continuar con el siguiente.
1. Elabore una aplicación que genere la lista de números 0, -1, 2, -3, 4, -5, 6, -7, 8, -9, …
2. Implemente en LeerCSV la posibilidad de conocer el total de nómina que paga la empresa.
3. Implemente la posibilidad de conocer el promedio devengado por los empleados.
4. Realice las reformas y las adiciones necesarias para que, a cambio de apellidos y nombres
mostrados en líneas distintas, se muestre en una sola línea el nombre completo del empleado.
5. Adapte la aplicación para que el usuario puede elegir: 0-Mostrar todos, 1-Mostrar sólo empleados
de la categoría 1, 2-Mostrar sólo empleados de la categoría 2 y así sucesivamente.
Para cada categoría, muestre el total que se paga por nómina.
6. La empresa responsable de esta nómina proyecta un aumento de sueldo de acuerdo a la siguiente
tabla:
AUMENTO DE SUELDO SEGÚN CATEGORÍAS
CATEGORÍA 1 CATEGORÍA 2 CATEGORÍA 3 CATEGORÍA 4
7.2% 7.0% 6.8% 6.5%
Implemente los cambios necesarios para que por cada empleado se muestre el sueldo actual, el
porcentaje de incremento, el valor del incremento y el nuevo sueldo. También se requiere conocer
el total de nómina sin aplicar los incrementos, aplicando los incrementos, la diferencia entre dichos
totales y el porcentaje total de incremento.
7. Aplicado el aumento, los empleados quedarán haciendo un aporte denominado solidaridad
pensional de acuerdo a los siguientes porcentajes:
DESCUENTO PARA SOLIDARIDAD PENSIONAL SEGÚN CATEGORÍAS
CATEGORÍA 1 CATEGORÍA 2 CATEGORÍA 3 CATEGORÍA 4
0.5% 0.7% 0.9% 1.1%
Para cada empleado muestre lo descontado por solidaridad pensional, el sueldo neto aplicando
este descuento y el monto total descontado por solidaridad pensional.
1 package control_otros;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.util.Scanner;
6
7 public class NominaProfesionales {
8
9 public static void main(String[] args) throws FileNotFoundException {
10 // evite hacer cambios en el archivo CSV, podría quedar inservible
11 try (Scanner in = new Scanner(new File("varios/profesionales_contratados.csv"))) {
12 in.useDelimiter(";");
13
14 in.nextLine(); // omite la primera fila (ver encabezados del archivo)
15
16 while (in.hasNextLine()) {
17 System.out.println("Cédula: " + in.next());
18 System.out.println("Nombre: " + in.next());
19 System.out.println("Profesión: " + in.next().trim()); // << OJO
20 System.out.println("-------------------------------");
21 in.nextLine(); // leer el resto de tokens de la linea
22 } // fin del while
23 } // fin del try
24 } // fin de la función o método main
25 } // fin de la clase
a) Actualmente el listado generado no está mostrando las horas trabajadas por cada
profesional, a pesar de que dicho dato se encuentra en la cuarta columna del archivo.
Realice los cambios necesarios para que se muestren las horas trabajadas.
b) Con base en la siguiente tabla, calcule y muestre, para cada profesional: pago base,
descuento para el fondo de solidaridad, auxilio de trasporte, descuento para EPS y pensión
y, pago neto resultante.
Importante
Por favor lea detenidamente la información de pie de página, dado que se dan pautas para
tratar con un problema que es común en hojas de cálculo e incluso en bases de datos y es
la de la información inconsistente.
Para este ejercicio tenga en cuenta que aunque hay inconsistencias en el archivo CSV, no
se autoriza modificar la información del mismo, por lo tanto cualquier inconsistencia en
nombres de profesiones, debe ser tenida en cuenta por el programa que procese la
información, para poder obtener resultados correctos.
10
Este enunciado aborda un problema con el que seguramente se encontrará en la vida real y es que muchos
registros tienen la información mal ingresada y por alguna razón no se permite la corrección antes de su
procesamiento. Así que por favor tenga en cuenta las aclaraciones de las siguientes notas de pie de página, al
calcular los pagos, incrementos y descuentos necesarios. También recuerde que en Java los Strings son objetos
que no admiten el operador “==” para ser comparados, la alternativa en este caso es utilizar equals. Ejemplo:
if (profesion.equals("INGENIERA DE ALIMENTOS") || profesion.equals("INGENIERO DE ALIMENTOS") || ...
11
Los siguientes datos son análogos y no pueden corregirse o modificarse en el archivo fuente: INGENIERA DE
ALIMENTOS, INGENIERO DE ALIMENTOS, INGENIERA INDUSTRIAL ALIMENTOS, INGENIERA INDUSTRIAL DE
ALIMENTOS, INGENIERIA DE ALIMENTOS, INGENIERO INDUSTRIAL DE ALIMENTOS, INGENIRA DE ALIMENTOS,
INGENIREA DE ALIMENTOS.
12
Los siguientes datos son análogos y no pueden corregirse o modificarse en el archivo fuente: ZOOTECNISTA,
MEDICO VETERINARIO, MEDICO VETERINARIO - ZOOTECNISTA, MEDICO VETERINARIO – ZOOTECNISTA, MEDICO
VETERINARIO, ZOOTECNISTA, MEDICA VETERINARIO, MEDICA VETERINARIA, ZOOZTECNISTA ESPECIALIZADO.
13
Los siguientes datos son análogos y no pueden corregirse o modificarse en el archivo fuente: BACTERIOLOGA,
MICROBIOLOGA, MICROBIOLOGA INDUSTRIAL, MICROBIOLOGA AGROINDUSTRIAL, MICROBIOLOGO CON ENFASIS
EN ALIMENTOS.
Un array es una estructura unidimensional o multidimensional que permite almacenar cierta cantidad de
datos de un mismo tipo. Para usarlos, se requiere definirlos e inicializarlos con un tamaño determinado.
Definir e inicializar un array puede llevarse a cabo de dos formas distintas, la primera usando dos
instrucciones separadas y la segunda con una sola instrucción. Veamos:
tipo nombreArray[];
nombreArray = new tipo[tamaño];
En el ejemplo que se da enseguida se define un array para guardar números enteros y luego se
inicializa para que la estructura tenga 20 posiciones:
int edades[];
edades = new int[5];
En ambos casos el array edades quedó definido con cinco posiciones que se pueden determinar mediante
un índice que empieza en cero y va hasta la posición N-1, siendo N, el tamaño del array, en este caso 5.
Veamos:
0 1 2 3 4
Para acceder a un elemento específico, bien para asignar un valor o para conocer su contenido, se utiliza
la siguiente forma:
edades[2] = 20;
edades[4] = 25;
20 25
0 1 2 3 4
int x = edades[2]; // asigna a x el valor 20 que hay en la posición 3, indicada por el índice 2
System.out.println(edades[4]); // muestra el valor 25 que hay en la posición 5, índice 4
Como se puede ver, este array tiene la forma de una lista unidimensional que también se conoce como
vector. Y de lo explicado hasta aquí se concluye que en los vectores, para asignar un valor o para
recuperarlo, se requiere indicar mediante un índice encerrado entre corchetes, la posición en la que se
encuentran los elementos.
En la siguiente clase se construye un ejemplo completo que reúne lo explicado. El vector que se utiliza
puede contener cinco valores enteros que representan edades, y simplemente muestra cómo ingresar la
información al array para luego procesarla. Observe además en la línea 22 cómo, se puede determinar la
longitud de un vector mediante el uso de length.
1 package arrays;
2
3 import java.util.Scanner;
4
5 public class DemoArray01 {
6
7 public static void main(String[] args) {
8 Scanner scanner = new Scanner(System.in);
9
10 final int TOPE = 5;
11 int edades[] = new int[tope];
12
13 // ingreso de valores al array
14 for (int i = 0; i < TOPE; i++) {
15 System.out.print("Ingrese edad [" + i + "]: ");
16 edades[i] = scanner.nextInt();
17 }
18
19 System.out.println("-------- Resultados --------");
20 // recuperación de datos del array
21 double promedio = 0;
22 for (int i = 0; i < edades.length; i++) { // length: longitud del array
23 System.out.println("Edad [" + i + "]: " + edades[i]);
24 promedio += edades[i];
25 }
26 promedio = promedio / TOPE;
27 System.out.println("El promedio de las edades es: " + promedio);
28 }
29 }
Como ya se dijo, se pueden crear arrays de múltiples dimensiones, por ejemplo, para crear un array
bidimensional que permita ingresar tres notas parciales para cuatro estudiantes, se puede definir un array
de 4 filas por 3 columnas que esquemáticamente se vería así:
0 1 2
0 4.3 5.0 2.5
1 3.8 4.1 3.1
2 4.2 4.7 4.2
3 3.5 3.0 3.9
Según los valores del esquema utilizado como ejemplo y la definición que se acaba de hacer, notas[2][1]
tiene asignado el valor 4.7. Es decir, notas en la fila 2, columna 1, tiene el valor 4.7.
Observe que tanto las posiciones de las filas van desde 0 hasta filas – 1 y que las columnas van desde 0
hasta columnas – 1.
En el siguiente ejemplo se crea un array bidimensional como el descrito, se permite ingresar tres notas
para cada uno de los 4 estudiantes y se muestran las notas parciales y el promedio obtenido por cada
estudiante.
1 package arrays;
2
3 import java.util.Scanner;
4
5 public class DemoArray02 {
6
7 public static void main(String[] args) {
8 Scanner scanner = new Scanner(System.in);
9
10 final int FILAS = 4;
11 final int COLUMNAS = 3;
12 double[][] notas = new double[4][3];
13 double definitiva;
14
15 // Ingresar para cada uno de los 4 estudiantes, 3 notas
16 for (int i = 0; i < FILAS; i++) {
17 System.out.println("Estudiante [" + i + "]");
18 for (int j = 0; j < COLUMNAS; j++) {
19 System.out.print("Nota [" + j + "]" + " del estudiante [" + i + "]: ");
20 notas[i][j] = scanner.nextDouble();
21 }
22 }
23
24 // Calcular el promedio de cada estudiante y mostrar sus notas
25 System.out.println();
26 for (int i = 0; i < notas.length; i++) { // filas.length: número de filas del array
27 System.out.print("Estudiante [" + i + "]: ");
28 definitiva = 0;
29 for (int j = 0; j < notas[i].length; j++) { // filas[i].length: número de columnas de la fila i
30 System.out.print(notas[i][j] + " - ");
31 definitiva += notas[i][j];
32 }
33 definitiva = definitiva / columnas;
34 System.out.println("Definitiva: " + definitiva);
35 System.out.println();
36 }
37 }
38 }
1. Complemente DemoArray01 para que permita conocer la menor y la mayor edad guardada en el
vector.
3. Complemente DemoArray02 para que muestre cuál fue la menor y la mayor nota obtenida.
4. Complemente DemoArray02 para que muestre el promedio de cada una de las tres columnas del
array. Esto permitirá conocer cuánto fue el promedio del grupo en el primer parcial, en el segundo
parcial y en el tercer parcial.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
/**
* Esta aplicación recorre un CSV delimitado por (;) el cual contiene
* 15 filas x 30 columnas de números enteros, comprendidos entre -1000
* y 1000. El recorrido se interrumpe cuando logra llenar un vector de 10
* posiciones con valores positivos. Un número es positivo si no es 0 ni
* negativo.
*/
public class DemoArray03 {
while (sc.hasNextLine()) {
valor = sc.nextInt();
a) Elaborar la prueba de escritorio para la aplicación, tomando como referencia los datos del
archivo CSV y contrastar los resultados de la prueba con la lista de valores que proporciona
el programa.
b) Adaptar la aplicación para que el vector almacene 50 valores positivos en vez de los 10
que almacena actualmente.
c) Buscar en el vector el mayor valor contenido e informar al usuario cuál es y en qué posición
se encuentra.
d) Buscar en el vector el menor valor contenido e informar al usuario cuál es y en qué posición
se encuentra.
e) Calcular y mostrar la sumatoria de los valores del vector que estén entre 200 y 800.
7. Con base en el ejemplo del punto 6, cree una nueva aplicación que permita definir y llenar dos
matrices de 20 x 30 con los primeros 120 valores del CSV.
8. Sabiendo que la suma de dos matrices (A+B) de orden m x n es otra matriz de dimensión m x n,
donde A+B=(aij+bij), complemente la aplicación del punto anterior para que obtenga la matriz
suma y muestre el resultado obtenido.
9. La matriz opuesta es aquella en que todos los elementos están cambiados de signo. Agregue
también la funcionalidad necesaria para que se muestre la matriz opuesta de la matriz suma.
10. Una vector o una matriz se pueden crear e inicializar con datos directamente, de manera análoga
a como se ejemplifica enseguida:
int[][] matriz = {
{11, 12, 13},
{14, 15, 16, 17},
{18, 19, 20, 21, 22}
};
Elabore una aplicación para que muestre los datos de la matriz del ejemplo.
Las funciones pueden recibir datos externos a través de parámetros, al momento de ser llamadas y pueden
retornar un resultado. Un aspecto muy importante de usar funciones, es que éstas permiten dividir un
problema en varios problemas más pequeños, facilitando así la solución del problema general. La
programación que usa funciones parte del concepto “divide y vencerás”.
Hasta el momento todos los ejemplos sobre fundamentos de programación en Java, se han construido en
la parte que se resalta enseguida:
package nombrePaquete;
}
}
En la figura siguiente se toma como ejemplo la función main para detallar cada una de las partes que
conforman la estructura sintáctica de una función, o lo que técnicamente se conoce como la signatura o
cabecera del método:
Con el fin de ir introduciendo los conceptos lo más paulatinamente posible, por ahora nos centraremos
sólo en algunos aspectos de esta sintaxis y evitaremos detalles técnicos que forman parte del paradigma
de orientación a objetos. Veamos:
Por ahora es suficiente con saber que el modificador public hace posible que las funciones sean
visibles desde cualquier contexto, es decir que puedan ser llamadas o utilizadas por fuera de la
clase y el paquete que las contiene.
El modificador static indica que la función puede ser utilizada como un miembro de clase. Las
funciones que no tienen este modificador no son accesibles como miembros de clase y deben
utilizarse luego de definir un objeto de clase. Para intentar aclarar el asunto observe las siguientes
instrucciones:
Se dice entonces que nextInt no es un miembro de clase sino de instancia. Por eso se crea
una instancia kb de tipo Scannner, siendo dicha instancia la que permite utilizar el método
nextInt. Es decir que no se puede utilizar nextInt de la forma Scanner.nextInt(), como si se
hizo con Math.pow().
El nombre de la función debe cumplir con la regla de los identificadores, expuesta en la práctica
3 y dicho nombre sirve para utilizar la función, lo que técnicamente se conoce como “llamada a la
función” o “envío de mensajes a métodos”. Ejemplos de llamadas a las funciones pow, nextInt y
println:
La función public static double pow(double a, double b); recibe dos argumentos o
parámetros.
La función public static void main(String[] args); puede no recibir argumentos o recibir un
array de tipo String. Hasta el momento, main no ha recibido argumentos, pero se pueden
enviar estos en tiempo de ejecución.
La imagen siguiente muestra que desde la línea de comandos, al momento de ejecutar una
aplicación, puede o no enviarse parámetros a la función main. La primera ejecución se
hace sin envío de parámetros y en la segunda ejecución se envían tres cadenas de
caracteres separadas por espacios, las cuales son recibidas por el array args y mostradas
mediante una iteración incluida en la parte falsa de la condición.
Importante: observe el mismo ejemplo de la figura, reescrito para ejemplificar otra forma
de utilizar el ciclo for con arrays o colecciones de datos u objetos:
Las funciones permiten estudiar, observar y entender una aplicación como la unión de una o varias
funciones que interactúan entre sí y que, como ya se dijo, trabajan para alcanzar un objetivo común,
realizando cada función una tarea específica para la consecución de dicho objetivo. Para demostrar esto,
observe de nuevo el ejemplo de la actividad 7, página 22 en donde se planteaba la necesidad de
implementar un programa que, dados los datos: categoría, días trabajados y número de horas extras,
calcule, según la tabla que se presenta más abajo, pago de horas extras, aporte a un fondo de solidaridad,
auxilio de transporte, aportes a EPS y pensión (10%) y salario neto recibido.
En la nueva versión todos los cálculos y la salida resultante, se han implementado en una función que
recibe los parámetros valor de la hora, porcentaje de descuento para el fondo de solidaridad y auxilio de
transporte. Con los datos recibidos como parámetros se realizan los cálculos solicitados y la función se
llama para cada una de las alternativas establecidas por las categorías de los empleados. Veamos:
1 package funciones;
2
3 import java.util.Scanner;
4
5 public class CalculoSueldo {
6
7 static final double EPS_PENSION = 0.10; // OJO se sacó de main para que quede a nivel de clase
8
9 public static void main(String[] args) {
10 Scanner scanner = new Scanner(System.in);
11 int categoria, horasExtras, diasTrabajados;
12
13 System.out.print("Ingrese la categoría: ");
14 categoria = scanner.next().toUpperCase().charAt(0); // OJO
15
16 System.out.print("Ingrese los días trabajados: ");
17 diasTrabajados = scanner.nextInt();
18
19 System.out.print("Ingrese el número de horas extras: ");
20 horasExtras = scanner.nextInt();
21
22 if ((categoria == 'A') || (categoria == 'B')) {
23 CalculoSueldo.calcularPago(diasTrabajados, 1000000, horasExtras, 0.01, 0.085);
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 47/191
24 } else if (categoria == 'C') {
25 calcularPago(diasTrabajados, 1500000, horasExtras, 0.011, 0.075);
26 } else if (categoria == 'D') {
27 calcularPago(diasTrabajados, 2000000, horasExtras, 0.012, 0.065);
28 } else if (categoria == 'E') {
29 calcularPago(diasTrabajados, 2500000, horasExtras, 0.013, 0.55);
30 } else if (categoria == 'F') {
31 calcularPago(diasTrabajados, 3000000, horasExtras, 0.014, 0);
32 } else {
33 calcularPago(diasTrabajados, 3500000, horasExtras, 0.115, 0);
34 }
35 }
36
37 private static void calcularPago(int dias, double salario, int extras,
double porcentajeFondo, double porcentajeTransp) {
38 double vrHora, salarioBase, pagoExtras, salarioNeto, epsPension, fondoSolidaridad, transporte;
39
40 vrHora = salario / 192; // se suponen 48 horas por semana y meses de 4 semanas
41 salarioBase = (salario / 30.0) * dias; // se suponen meses de 30 días
42 pagoExtras = extras * vrHora;
43 salarioNeto = salarioBase + pagoExtras;
44 epsPension = salarioNeto * EPS_PENSION;
45 fondoSolidaridad = salarioBase * porcentajeFondo;
46 transporte = salarioBase * porcentajeTransp;
47
48 salarioNeto = salarioNeto - fondoSolidaridad - epsPension + transporte;
49
50 System.out.println("Salario base : " + String.format("%.2f", salarioBase));
51 System.out.println("Pago por horas extras: " + String.format("%.2f", pagoExtras));
52 System.out.println("Fondo de solidaridad : " + String.format("%.2f", fondoSolidaridad));
53 System.out.println("Auxilio de transporte: " + String.format("%.2f", transporte));
54 System.out.println("Aportes EPS y Pensión: " + String.format("%.2f", epsPension));
55 System.out.println("Salario neto : " + String.format("%.2f", salarioNeto));
56 }
57 }
Por primera vez se incluye en la línea 7, una definición de una constante que queda fuera de la
función main. Con esto se quiere mostrar que es posible definir constantes o variables fuera de
las funciones y dentro del bloque de la clase.
Una característica de las constantes o variables definidas fuera de las funciones y dentro del
bloque de la clase, es que son visibles para todas las funciones de la clase, mientras que las
variables o constantes definidas dentro de una función sólo son visibles dentro de la función donde
fueron definidas.
Clase.funcion([argumentos]);
Lo expuesto, es la razón por la que las funciones de la clase Math siempre son llamadas como se
muestra enseguida:
Math.pow(x, y);
Math.min(x, y);
Math.sqrt(x);
A continuación, se incluye un esquema que muestra los parámetros actuales, los que son enviados
desde, por ejemplo, la línea 25, cuando se hace el llamado a la función calcularPago y cómo son
recibidos por los parámetros formales de la función implementada a partir de la línea 37.
Teniendo en cuenta que la función que se implementa a partir de la línea 37, recibe parámetros
distintos cada vez que es llamada y que dichos parámetros se comportan como variables locales,
deberían ser claras las instrucciones que hay desde la línea 38 hasta la línea 55, dado que la
implementación es muy similar a las que se han hecho hasta ahora para la función main.
Por último, a partir de la línea 50 se utiliza la función String.format("%.2f", datoReal), para dar
formato con dos decimales a la salida de la aplicación.
Actividad complementaria
Esta actividad está pensada para desarrollar destrezas en compresión de lectura, en el uso de funciones y
al mismo tiempo afianzar la lógica algorítmica y la cultura del autoaprendizaje.
1. Retomemos la clase CalculoSueldo que se acaba de explicar, pero incorporando los cambios que
se sugieren a continuación:
1 package funciones;
2
3 import java.util.Scanner;
4
5 public class CalculoSueldoV2 {
6
7 static final double EPS_PENSION = 0.10;
8
9 public static void main(String[] args) {
10 Scanner scanner = new Scanner(System.in);
11 int horasExtras, diasTrabajados;
12 char categoria;
Observe que se pide que las decisiones, que en la versión anterior están entre las líneas 22 y 34
son reemplazadas en esta versión por el llamado a la función decidirPago. Su misión consiste en
implementar dicha función, a partir de la línea 26. Tenga en cuenta las siguientes restricciones:
Los nombres de los parámetros de la función definida en la línea 26, no pueden ser
cambiados.
Los nombres de las variables definidas dentro de la función main no pueden ser
cambiados.
No se permite la definición de nuevas variables.
La funcionalidad de la aplicación no se altera.
2. Se ha tomado como base la aplicación de la página 26 para crear una nueva versión que incorpore
el tema de funciones, por lo tanto, todas las alternativas se determinan ahora en la función
calcular que se utiliza en la línea 22 de la nueva versión:
1 package funciones;
2
3 import java.util.Scanner;
4
5 public class Caso001 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9
10 int a, b;
11 char operador;
12
13 System.out.print("Primer valor : ");
Tal como se indica a partir de la línea 32 del código fuente, termine de implementar el switch sin
incluir la cláusula default, sólo implementando las operaciones que se solicitan. Seguidamente
pruebe el funcionamiento de la nueva versión. Observe lo siguiente:
Para que una función pueda retornar un valor, se cambia el tipo de retorno void, por el
tipo de dato u objeto que se quiera retornar, en este caso y según la línea 25, el tipo de
retorno es double, igual que el tipo del dato retornado en la última instrucción de la
función calcular: return resultado.
Por último observe en la línea 26 cómo se puede inicializar una variable de tipo double
para indicar que no contiene un valor válido.
1 package funciones;
2
3 import java.util.Scanner;
4
5 public class FuncionMCD {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9 int valor1, valor2, mcd;
10
4. Para llevar a cabo lo que se le solicita en este punto, asegúrese de entender primero los conceptos
que se resaltan en la siguiente plantilla de clase:
package nombrePaquete;
Los elementos de clase que se definen aquí (constantes, variables o enumeraciones) son
visibles para todas las funciones o métodos de la clase. Si utiliza el modificador public
serán visibles incluso fuera de la clase.
A una función los argumentos pueden ser pasados “por valor” o “por referencia”.
En el paso "por valor", se crean copias de los argumentos pasados a la función.
En el “paso por referencia” lo que se hace es referenciar la variable que contiene
el dato, no se crea una copia del dato y por lo tanto se permite modificar los
valores originales o referenciados de los arreglos u objetos.
En Java, sólo los arreglos u objetos pueden ser pasados como argumentos por
referencia.
Las constantes o variables que se definen dentro de una función o método, sólo
son visibles a nivel local, es decir a nivel del método y por lo tanto no son
accesibles fuera de la función donde son definidas.
}
}
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 52/191
Con base en lo expuesto complete el punto 4 de la manera que se indica a continuación:
1 package funciones;
2
3 public class Ambito {
4
5 static int a = 100;
6 static int c = 200;
7
8 public static void main(String[] args) {
9 int v[] = {5, 10, 15, 20, 25, 30};
10 int x = 10, y = 20;
11 int z = c;
12
13 System.out.println("Valor de <x> antes de ejecutar f1(): " + x);
14 System.out.println("Valor de <y> antes de ejecutar f1(): " + y);
15 System.out.println("Valor de <z>: " + z);
16 System.out.print("Elementos de v[] antes de ejecutar f1(): ");
17 mostrarVector(v);
18 System.out.println("------------------------------------------");
19 y = fx(x, y, v);
20 System.out.println("Valor de <x> luego de ejecutar f1(): " + x);
21 System.out.println("Valor de <y> despues de ejecutar f1(): " + y);
22 System.out.print("Elementos de v[] después de ejecutar f1(): ");
23 mostrarVector(v);
24 }
25
26 private static int fx(int a, int b, int vector[]) {
27 a = a *= 10;
28 b = a * Ambito.a * c;
29 System.out.println("Valor de z:" + z); // ojo
30
31 for (int i = 0; i < vector.length; i++) {
32 vector[i] = vector[i] *= 5;
33 }
34 return b;
35 }
36
37 private static void mostrarVector(int vector[]) {
38 for (int valor : vector) {
39 System.out.print("\t" + valor);
40 }
41 System.out.println();
42 }
43 }
14
Disponible en https://drive.google.com/drive/folders/0B3Zlyx-DWwvZN3JzWUdHQkJDamc?usp=sharing
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 53/191
b. En la línea 11 se crea la variable “z” y se le asigna el valor 200, sin embargo, al intentar
compilar, el programa reporta en la línea 29: “error: cannot find symbol >>
System.out.println("Valor de z:" + z);”, ¿por qué?
Hecha la prueba y entendido por qué falla, comente (no elimine) la instrucción de la línea
29 y compile. La aplicación original debería ejecutarse ahora sin problemas y obtener los
siguientes resultados:
Valor de <x> antes de ejecutar f1(): 10
Valor de <y> antes de ejecutar f1(): 20
Valor de <z>: 200
Elementos de v[] antes de ejecutar f1(): 5 10 15 20 25 30
------------------------------------------
Valor de <x> luego de ejecutar f1(): 10
Valor de <y> después de ejecutar f1(): 2000000
Elementos de v[] después de ejecutar f1(): 25 50 75 100 125 150
c. Si existe una restricción que no permite duplicar nombres de identificadores, ¿por qué las
definiciones hechas en las líneas 5, 26 y 37 no ocasionan que la aplicación falle, si hay
identificadores duplicados?
d. ¿Por qué el valor de “x” no se muestra alterado luego de ejecutar fx si es pasado como
argumento a dicha función en la línea 19 y el valor de dicho argumento es alterado en la
línea 27?
f. ¿Por qué los valores del vector “v” se muestran alterados luego de ejecutar fx?
g. Si a nivel de clase y de método tengo definidas dos variables con nombre “v1”, al
momento de utilizarlas ¿cómo diferenciar cuál es la de clase y cuál es la de método?
Esta aplicación se utilizará para implementar casos con el propósito de afianzar la lógica
algorítmica y la destreza en la implementación de funciones, pero antes se llama la atención sobre
los siguientes aspectos:
Tenga en cuenta que el parámetro formal args, definido en la línea 7 puede recibir un
array de argumentos enviados desde la línea de comandos. Cuando se envían
argumentos desde la línea de comandos, la condición de la línea 26 se cumple y se evalúa
el caso a que corresponde el primer argumento. Si la condición no se cumple, se ejecutan
las instrucciones a partir de la línea 147.
15
A partir de la línea 48 se usa “\n”, lo cual se conoce como “secuencia de escape de nueva línea”. Cuando esto se incluye en
una cadena hace que se muestre lo dicho, un salto de línea. Al final del documento se incluyen otras secuencias de escape.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 55/191
En las líneas 12, 18 y 24 se definen arrays bidimensionales (matrices) para usarlos
posteriormente en pruebas.
En los siguientes pasos se implementará funcionalidad adicional a la aplicación y con esto podrá
evaluar su capacidad de comprensión de lectura y de lógica algorítmica:
case "3":
Ejemplos.listarVector(v);
System.out.println("Promedio: " + Ejemplos.promedioVector(v));
break;
f. El caso 6 se basa en el punto “a” para mostrar sólo los elementos impares del vector.
g. El caso 7 demuestra que los argumentos de tipo array u objetos no son pasados por valor
sino por referencia, lo que determina que cualquier cambio que sufran dentro de la
función los afecta directamente.
case "7":
Ejemplos.burbuja(v);
Ejemplos.listarVector(v);
break;
i. Para el caso 9, elabore una función que muestre los elementos de una matriz de enteros
y pruebe que dicha función permite mostrar las matrices mA y mB.
j. La diagonal principal de una matriz cuadrada contiene los elementos empezando desde
el de la posición [1, 1], siguiendo con el de la posición [2, 2] hasta la posición [n, n].
Ejemplo:
10 30 25 40
5 -15 4 12
8 11 0 48
16 44 1 76
Para el caso 10 que se incluye enseguida, elabore una función que retorne un vector con
los elementos de la diagonal de la matriz recibida como argumento:
case "10":
System.out.println("Diagonal de mA:");
int diagonal[] = Ejemplos.diagonalMatriz(mA);
Ejemplos.listarVector(diagonal);
System.out.println("Diagonal de mB:");
diagonal = Ejemplos.diagonalMatriz(mB);
Ejemplos.listarVector(diagonal);
break;
l. También la suma de cada una de las columnas de una matriz se obtendrá fácilmente,
reutilizando la función del punto anterior dentro de la función totalesColumnas. Observe
el caso:
case "12":
totalesColumnas(mA);
break;
m. Para el caso 13, proceda como se indica en el punto “k” para dar la oportunidad al usuario
de conocer la suma de determinada fila de la matriz mB.
n. Para el caso 14 proceda como en el punto “l” para mostrar la sumatoria de los elementos
de cada fila de la matriz mB.
10 30 25 40
5 -15 4 12
8 11 0 48
16 44 1 76
Elabore una función que retorne un entero que corresponda a la suma de la diagonal
secundaria y permita probar su funcionamiento mediante la implementación del caso 15.
p. Un productor de leche lleva el registro de lo que produce en litros, pero cuando entrega
la producción de un día le pagan en galones. Escriba una función que ayude al productor
a saber cuánto recibirá por la entrega de la producción de un día (1 galón = 3.785 litros).
r. Para el caso 18, implemente una función que permita determinar, como se muestra en
la siguiente porción de código, cuánto dinero ahorra una persona en un año si cada
semana ahorra un porcentaje determinado y constante durante el año, de su sueldo
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 59/191
mensual. Considere cuatro semanas por mes y también tenga en cuenta que durante el
año el sueldo permanece igual.
System.out.print("Sueldo mensual: ");
double sueldoMensual = in.nextDouble();
System.out.print("Porcentaje ahorro semanal: ");
double porcentajeSemanal = in.nextDouble();
double ahorro = Ejemplos.calculoAhorro(sueldoMensual, porcentajeSemanal);
System.out.println("Ahorro anual $" + ahorro);
s. Para el caso 19, implemente una función que permita determinar el valor real fx,
mediante el uso de la respectiva función e implemente el caso como se muestra
enseguida:
System.out.print("Límite o tope: ");
int limite = in.nextInt();
System.out.println("Fx = " + Ejemplos.fx(limite));
1 1 1 1 1
Fx = 1 + ---- + ---- + ---- + ---- + … + ----
2 4 8 16 2n
t. Para el caso 20, implemente una función que, dado un número natural, n, imprima la lista
de sus divisores, en orden decreciente. Si la función se utiliza como se indica en la
siguiente porción de código, se listarán los divisores del número ingresado por el usuario:
Los dos primeros llamados a la función listar son ejemplos de argumentos variables,
puesto que se envía distinto número de parámetros, en ambos casos, números enteros,
lo cual cumple con la regla: cantidad variable de argumentos del mismo tipo.
Para definir una función o método que reciba argumentos variables se utiliza la forma:
<modificadores> <tipo de retorno> nombreFuncion(tipo... nombreArg) { }
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 60/191
Ejemplo de la función que debe ser implementada para este caso:
Importante: los parámetros variables hacen posible formatear las salidas mediante el
uso de la función printf que recibe un primer argumento de tipo String, con el cual se
indica el formato de la salida de los subsiguientes argumentos que corresponden a los
valores que serán sustituidos en la cadena. Como el tema de especificadores de formato16
trasciende el objetivo de estas prácticas, enseguida se presenta una breve descripción
del uso que se da en la función anterior:
16
Al final de esta guía se anexa un apartado sobre especificadores de formato en Java.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 61/191
El siguiente especificador (%5.2f) indica que el segundo argumento a sustituir
corresponde a un valor real que se debe mostrar en 5 posiciones, dos de las
cuales son decimales.
Los siguientes son los especificadores de formato más usados:
b: boolean
c: carácter Unicode
d: número entero
f: número real
s: String
t: fecha y hora
package funciones;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
while (in.hasNext()) {
cedula = in.next();
apellidos = in.next();
nombres = in.next();
categoria = in.nextInt();
sueldoActual = in.nextDouble();
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 62/191
if (opcion == 0) {
mostrarRegistro(cedula, nombres, apellidos, categoria, sueldoActual);
} else if (opcion == categoria) {
mostrarRegistro(cedula, nombres, apellidos, categoria, sueldoActual);
}
in.nextLine(); // descartar los posibles siguientes datos de la línea
} // fin del while
} // fin del try
mostrarTotales();
}
/**
* Una forma trivial de solicitar una opción al usuario
* @return Un valor entero que corresponde a la opción elegida por el usuario
*/
private static int leerOpcion() {
Scanner kb = new Scanner(System.in);
Incluya aquí las instrucciones para mostrar por pantalla las opciones elegibles, desde la:
0- Mostrar todos los registros, hasta la
4- Mostrar empleados de la categoría 4.
return kb.nextInt();
}
/**
* Muestra los datos de un registro de nómina todos los cálculos
* concernientes. También hace el conteo de empleados, calcula la nomina sin
* incremento y se apoya en otras dos funciones para calcular los
* incrementos y los descuentos.
*/
private static void mostrarRegistro(String cedula, String nombres, String apellidos,
int categoria, double sueldoActual) {
/**
* Calcula y muestra el incremento de un sueldo, con base en una categoría y
* porcentaje dados. También incrementa el total de nómina con incremento,
* según el suedo incrementado.
/**
* Calcula y muestra el descuento, según la categoría, que debe hacerse a un
* sueldo incrementado. También incrementa el total descontado por
* solidaridad pensional, según lo descontado al sueldo.
* @param categoria
* @param sueldo
*/
private static void calcularDescuento(int categoria, double sueldo) {
double porcentajeDesc = 0, descuento;
/**
* Calcula los promedios de nómina, el porcentaje total incrementado y
* muestra información general de nómina
*/
}
}
7. Para este caso se toma como base la aplicación propuesta en el punto 8 de las actividades
complementarias de la práctica 9, página 37 y se retoma la estrategia de implementación del
punto anterior. Recordemos la tabla que define los cálculos:
package funciones;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
while (in.hasNextLine()) {
cedula = in.next();
nombre = in.next();
profesion = in.next().trim(); // quitar posibles espacios al inicio y/o al final del token
horasTrabajadas = in.nextInt();
in.nextLine(); // descartar el resto de linea
mostrarRegistro(cedula, nombre, profesion, horasTrabajadas);
} // fin del while
System.out.println("Total bruto de nómina $" +
String.format("%.0f", totalNominaBruto));
System.out.println("Total neto de nómina $" +
String.format("%.0f", totalNominaNeto));
} // fin del try
} // fin de main
private static void mostrarRegistro(String cedula, String nombre, String profesion, int horas) {
System.out.println("Cedula: " + cedula);
System.out.println("Nombre: " + nombre);
System.out.println("Profesion: " + profesion);
if (profesion.equals("INGENIERA DE ALIMENTOS")
// Complete las condiciones para profesiones afines
|| profesion.equals("INGENIREA DE ALIMENTOS")) {
calcularSueldo(horas, 70000, 10, 0);
} else if (profesion.equals("ZOOTECNISTA")
// Complete de manera similar a la primera condición, teniendo en cuenta que el
// tercer argumento corresponde al porcentaje para el fondo de solidaridad
// pensional y el cuarto argumento corresponde al auxilio de transporte
} else if (profesion.equals("BACTERIOLOGA")
// Complete de acuerdo a lo indicado para las condiciones anteriores
} else {
System.out.println("ERROR: profesion [" + profesion + "] sin condición");
}
System.out.println("-------------------------------");
}
} else {
System.out.println("No reportó horas trabajadas");
}
} // fin de la función calcularSueldo
} // fin de la clase
Cédula: 52.710.695
Nombre: ADRIANA PAOLA CUJAR ALARCON
Profesión: MICROBIOLOGA INDUSTRIAL
Pago base $7600000 (152 horas a $50000 hora)
Se le descuenta el 8.0% de solidaridad pensional equivalente a $608000,00
Se le incrementa el 7.5% de auxilio de trasporte equivalente a $570000,00
El pago neto es $7562000
Cédula: 52.355.290
Nombre: ADRIANA MARCELA SALCEDO SEGURA
Profesión: INGENIERA DE ALIMENTOS
Pago base $9240000 (132 horas a $70000 hora)
Se le descuenta el 10.0% de solidaridad pensional equivalente a $924000,00
No aplica auxilio de transporte
El pago neto es $8316000
-------------------------------
Cédula: 52.755.672
Nombre: ANDREA ARIZA ZAMBRANO
Profesión: INGENIERA DE ALIMENTOS
No reportó horas trabajadas
-------------------------------
El Entorno de Desarrollo Integrado (IDE) Eclipse. Se supone que tiene Java instalado.
Uso de librerías o paquetes.
Clases y Objetos.
En otras palabras, el autor es consciente de la posibilidad de arrastrar y soltar componentes para definir
por ejemplo un formulario de entrada de datos, pero esto dificulta sobre manera, entender de manera
adecuada lo que verdaderamente ocurre a nivel de programación. Empecemos:
1. Descargue la última versión de Eclipse. Se recomienda que la descarga se realice utilizando los
vínculos que se resaltan en la figura siguiente.
2. Terminada la descarga, descomprima el ZIP, abra la carpeta descomprimida, ejecute Eclipse y espere
hasta que se muestre el siguiente cuadro:
17
https://www.eclipse.org/downloads/?
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 68/191
3. En el cuadro mostrado deberá seleccionar el “espacio de trabajo”. Dicho espacio hace referencia a la
carpeta donde quedarán guardados sus proyectos, similar a la carpeta “Fundamentos” que se sugirió
para las anteriores prácticas. En la figura del punto 6 se resalta con rojo la unidad y carpeta que el
autor ha elegido como espacio de trabajo.
Recuerde el nombre seleccionado para evitar inconvenientes a la hora de ubicar sus trabajos.
4. Crear un proyecto Java. Del menú de Eclipse, elija File > New > Other.
5. Del cuadro que aparece seleccione Java Project y pulse Next para ver un cuadro como el que se
muestra enseguida:
6. Proceda a indicar el nombre del proyecto y verifique que las opciones seleccionadas, corresponden a
las que se muestran en la figura anterior, para finalmente pulsar Finish.
Observe que en “Project layout” se especifica que se crearán carpetas separadas para los archivos
fuente y para las clases. Hasta ahora se habían generado los archivos CLASS en la misma carpeta de
los archivos fuente.
7. Agregar clases al proyecto. En el panel que muestra la estructura del proyecto, elija src > New > Class.
Pero, ¿qué es una clase? – digamos que es un arquetipo, un modelo, una representación que define
un conjunto de atributos (datos que determinan estados), y métodos (funciones que determinan el
comportamiento de los atributos). A partir de las clases se pueden crear entidades concretas, objetos
o instancias, pero esto se verá un poco más adelante. Por ahora miremos cómo implementar la
primera clase creada.
package demobase;
import java.util.Scanner;
/**
* Método sumarValores - Ejemplo 2, pág. 12
*/
public static void sumarValores() {
int a;
float b, c;
c = a + b;
}
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 72/191
Con el código anterior se ha realizado lo siguiente:
Se ha importado el paquete Scanner que como ya se sabe, se utiliza para permitir el ingreso
de datos.
Se ha definido a nivel de clase el atributo in, creado a partir de la clase Scanner. Definido de
esta manera, será visible para todos los métodos de la clase Secuencial y por lo tanto será un
error crearlo en cada uno de los métodos que se implementarán.
Se han agregado dos métodos a partir de los ejemplos de la página 12: concatenar y
sumarValores.
Para continuar, es conveniente que revise los ejemplos de la página 12 y que contraste su
implementación con los de esta clase.
10. De manera similar a como se agregaron los métodos concatenar y sumarValores, agregue métodos
para cada una de las aplicaciones solicitadas en la práctica 6, un método por cada aplicación
propuesta. Dé nombres representativos a los métodos y agregue y agregue comentarios a cada uno,
indicando qué hacen.
11. Punto de entrada a la aplicación. En este paso se construirá el punto de entrada a la aplicación y se
incorporarán algunos conceptos nuevos.
En el código de la página siguiente, se importa la clase JOptionPane que forma parte del paquete
swing. Esta clase permite definir los siguientes cuatro tipos de cuadros de diálogo:
package demobase;
import java.util.Scanner;
import javax.swing.JOptionPane;
case "2":
Secuencial.sumarValores();
break;
…
default:
String mensaje = String.format("La opción \"%s\" no está implementada", caso);
JOptionPane.showMessageDialog(null, mensaje, "Tenemos problemas...",
JOptionPane.INFORMATION_MESSAGE);
}
} while (true);
}
}
A continuación, se hace una breve descripción de los aspectos más relevantes de la implementación:
El primer argumento que aquí es null, se refiere al contenedor o ventana sobre el cual se
desplegará el cuadro de diálogo.
El valor entero que retorna este método a la variable opcion se utiliza enseguida para verificar
si la opción es “0”, en cuyo caso se termina la aplicación de manera controlada (exit(0)):
if (opcion == JOptionPane.YES_OPTION) {
System.exit(0); // Terminar la aplicación de manera normal
}
Del código anterior se deduce que la clase JOptionPane, define la constante YES_OPTION y
algunas otras que se dejan para consulta del lector y que permiten verificar la elección hecha
por el usuario.
12. Implementadas las dos clases anteriores, proceda de la manera siguiente para ejecutar la aplicación:
a. Use la opción Window > Appearance > Show Toolbar para desplegar la barra de herramientas
de IDE.
Nota: es importante que consulte atajos18 de Eclipse que le permitan elegir rápidamente
opciones.
En el modelo, las clases están representadas por rectángulos, cada rectángulo tiene tres
compartimentos, el primero con el nombre de la clase, el segundo con los atributos de la clase y
el tercero con los métodos de la clase. Veamos algunos detalles:
Para la clase DemoBase los atributos, por ahora, son dos: in de tipo Scanner y secuencial de
tipo Secuencial.
El signo (-) que precede a la definición de los atributos indica que son private. También se
hubieran podido definir con el signo (#) para indicar protected o con el signo (+) para indicar
public. Es importante que consulte sobre estos modificadores.
18
http://unestudiantedeinformatica.blogspot.com.co/2015/04/mejores-atajos-de-teclado-eclipse.html
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 77/191
La clase DemoBase consta de un solo método público: main, que como sabemos se usa para
iniciar la ejecución de las aplicaciones Java. Dicho método se conoce como el punto de
entrada de la aplicación.
La flecha que asocia las dos clases, especifica tres aspectos importantes: el rombo indica que
la clase DemoBase agrega una instancia de la clase Secuencial cuyo nombre es precisamente
secuencial. Los números 1..1, indican que la asociación entre las clases es de uno a uno, es
decir, que DemoBase sólo crea un objeto de tipo Secuencial.
Con base en el diagrama de clases de la imagen, lleve a cabo las siguientes actividades:
Es muy importante que los métodos queden debidamente parametrizados para que permitan
definir o crear estructuras unidimensionales o bidimensionales de cualquier tamaño.
15. Finalmente tenga en cuenta que cuando se habla de definir una instancia de clase, o de definir un
objeto de un tipo determinado, se está hablando de lo mismo. Los siguientes son ejemplos de
definiciones de instancias o de objetos:
También los términos creación de instancia de clase o creación de objeto, se refieren a lo mismo.
Los siguientes son ejemplos de creación de instancias o de objetos:
Más adelante se profundizará en las múltiples formas que existen para crear objetos, por ahora se han
dado las bases para pasar al próximo tema que corresponde al uso del paquete swing que contiene la
clase JOptionPane y otras muchas clases que se utilizarán para crear aplicaciones con interfaz gráfica.
java.swing
java.awt
java.awt.event
Profundizar sobre esta biblioteca ocuparía un libro completo, por lo que aquí se documentarán las bases
esenciales para cubrir tres objetivos:
3. Gestionar los eventos sobre los componentes que hacen parte de las interfaces gráficas de usuario,
en lo posible, utilizando las expresiones lambda disponibles a partir de la versión 8 de Java.
Como se dijo, no espere encontrar en este capítulo un manual de referencia sobre el uso de GUI en Java,
pero sí, la documentación esencial que le proporcionará las bases para diseñar formularios con la
usabilidad requerida.
En Java existen cuatro grandes grupos de clases: clases básicas, contenedoras de alto nivel, contenedoras
intermedias y componentes atómicos. La imagen que se presenta a continuación da una idea general de
la jerarquía de clases disponibles19 para crear interfaces gráficas:
La clase abstracta java.awt.Component define distintos métodos relacionados con efectos visuales y con
la respuesta a eventos. Para dar sólo un ejemplo, tenga en cuenta que en esta clase están definidos los
métodos para permitir manipular formularios.
La clase abstracta java.awt.Container es un contenedor u objeto que permite agrupar otros objetos de
forma que se puedan tratar como una unidad. Los objetos Container mantienen una lista de los objetos
que contienen y cuentan con métodos para adicionar componentes, retornarlos, removerlos y administrar
la disposición de los mismos.
Contenedores de alto nivel: Son todos aquellos contenedores que se derivan de la clase java.awt.Window
que a su vez es una especialización de la clase Container. La clase Window permite definir ventanas
genéricas, sin bordes ni barras de menús, pero con métodos básicos como pack que permite ajustar el
tamaño de la ventana a un tamaño previamente definido, toFront y toBack para colocarlas delante o
detrás de otras ventanas y dispose para destruirlas junto con todos sus componentes.
Continuando con la descripción de las clases básicas es necesario nombrar una especialización de la clase
java.awt.Container, que sirve de base a todos los componentes de interacción que incorpora Swing,
excepto para los contenedores de alto nivel. Es la clase javax.swing.JComponent que proporciona muchas
de las funcionalidades básicas de contenedores intermedios y componentes simples de Swing, entre las
cuales se destacan el manejo de bordes, opacidad, ayuda contextual, tamaño y alineación, entre otras.
Dado que la clase JComponent se especializa en muchas subclases, la figura anterior no muestra dichas
derivaciones que incluyen paneles que permiten agrupar componentes, controles para la definición de
menús, listas, botones y campos de texto. En la figura siguiente puede observar una detallada jerarquía de
componentes derivados de la clase JComponent20.
20 ibíd.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 81/191
Sin más preámbulo, abra Eclipse y siga los siguientes pasos para empezar esta primera parte de la práctica
que se dedica exclusivamente al diseño de GUIS. En la práctica 14 se mostrará cómo implementar el
manejo de eventos para permitir que los usuarios puedan interactuar con las GUI creadas.
1. Use File > New > Java Project para crear un nuevo proyecto. Se recomienda que lo nombre
DemoSwing, que será el nombre con el que se hará referencia de ahora en adelante.
2. Use File > New > Java Project para agregar una clase de acuerdo a los datos de la figura siguiente:
1 package demoswing;
2
3 import java.awt.Dimension;
4 import javax.swing.JFrame;
5
6 public class DemoJFrame extends JFrame {
7
8 public DemoJFrame() {
9 inicializarComponentes();
10 }
11
12 private void inicializarComponentes() {
13 setTitle("Una simple instancia de JFrame");
14 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
15 setExtendedState(JFrame.NORMAL);
16 setPreferredSize(new Dimension(600, 400));
17 setVisible(true);
18 pack();
19 }
20 }
En la línea 3 se importa la clase Dimension para utilizar una instancia de dicha clase en la
línea 16 con el fin de establecer el tamaño con el que se mostrarán los formularios creados
a partir de la clase DemoJFrame.
En la línea 6 se define la clase DemoJFrame de una manera que hasta ahora no se había
documentado. Observe que se incluye la cláusula extends seguida del nombre de uno de
los componentes de la jerarquía de componentes swing. Esta cláusula indica que la clase
DemoJFrame hereda21 todas las características y funcionalidades de JFrame y de todos sus
ancestros (Frame, Window, Container, Component y Object). Para más claridad ubique la
clase JFrame en la primera figura de esta práctica y observe los ancestros de los que hereda
JFrame.
21
El tema de herencia será tratado detenidamente en una práctica más adelante. Incluirlo por completo ahora sólo
haría más complejo lo que se quiere explicar en esta parte.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 83/191
a) Línea 13: llamado al método setTitle, heredado de JFrame, para asignar un título
al formulario. Observe que en el código fuente de la clase DemoJFrame no se ha
implementado el método setTitle usado aquí. Si no fuera porque este se hereda
de la clase JFrame, ocurriría un error.
e) Línea 17: el argumento true ingresado al método setVisible indica que la ventana
o el formulario se mostrará inmediatamente se cree. En algunos casos los
formularios se crearán y se dejarán invisibles hasta tanto el usuario los haga
visibles mediante alguna acción.
4. Proceda como en el paso 2, para crear una nueva clase con el nombre DemoSwing. Esta vez sí
marque la casilla “public static void main(String[] args)” e implemente la nueva clase de acuerdo
al código que se muestra enseguida:
package demoswing;
import javax.swing.JOptionPane;
public class DemoSwing {
public static void main(String[] args) {
String caso = elegirOpcion();
switch (caso) {
case "0":
new DemoJFrame(); // ojo, de esta manera se crean objetos anónimos
break;
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 84/191
default:
String mensaje = String.format("La opción \"%s\" no está implementada", caso);
JOptionPane.showMessageDialog(null, mensaje, "¡Atención!",
JOptionPane.INFORMATION_MESSAGE);
System.exit(0); // terminar la aplicación
}
}
En el código se resalta la instrucción new DemoJFrame(); esto porque hasta ahora los objetos que
se han creado se han asignado siempre a una variable y aquí vemos que sólo aparece el operador
new seguido de la llamada al constructor. De lo resaltado se deduce que Java permite crear objetos
anónimos. Si se hubiera empleado una instrucción como DemoJFrame miFormulario = new
DemoJFrame(); el objeto creado ya no sería anónimo, sino que se llamaría “miFormulario”.
Los demás conceptos que se utilizan para implementar esta clase, han sido expuestos en prácticas
anteriores, por lo que se estima que no se requiere más explicación sobre la misma.
Los gestores de diseño son objetos encargados de posicionar automáticamente y de la mejor manera
posible los componentes dentro de un contenedor. Cada objeto Container tiene un administrador de
diseño asociado a él y se establece mediante un mensaje a setLayout(LayoutManager gestor) del objeto
Container. Si no se envía el mensaje setLayout, se utiliza el administrador de diseño por defecto.
La ventaja más apreciable de utilizar administradores de diseño, es saber que cada vez que se
redimensiona el contenedor, el administrador de posición intentará mantener la integridad de la
organización de los componentes.
En esta segunda parte de la práctica se analizarán cada uno de los gestores de diseño disponibles.
Empecemos:
FlowLayout: Este gestor coloca los componentes en una línea de izquierda derecha, según el orden en que
sean añadidos. Si el espacio horizontal no alcanza para colocarlos todos, se continúa en la línea siguiente.
Los componentes se dimensionan de acuerdo al tamaño necesario y por defecto se muestran centrados.
En la figura siguiente se muestra como FlowLayout organiza automáticamente la disposición en un
formulario de una etiqueta (JLabel) con el texto “Nombre”, un campo de texto en blanco (JTextField) y dos
botones (JButton). Siga los pasos que se dan a continuación para probar el efecto de este gestor de diseño.
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoFlowLayout y verifique que,
para esta clase, la casilla public static void main(String[] args), esté desactivada. En adelante las
clases que cree en este proyecto no tendrán el método public static void main(String[] args).
1 package demoswing;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 public class DemoFlowLayout extends JFrame {
7
8 private JButton btnAceptar;
9 private JButton btnCancelar;
10 private JLabel lblNombre;
11 private JTextField txtNombre;
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 86/191
12
13 public DemoFlowLayout() {
14 inicializarComponentes();
15 }
16
17 private void inicializarComponentes() {
18 this.setTitle("Gestor de diseño FlowLayout");
19
20 lblNombre = new JLabel("Nombre:");
21 txtNombre = new JTextField(30);
22 btnAceptar = new JButton("Aceptar");
23 btnCancelar = new JButton("Cancelar");
24
25 Container contenedor = getContentPane();
26 contenedor.setLayout(new FlowLayout());
27
28 contenedor.add(lblNombre);
29 contenedor.add(txtNombre);
30 contenedor.add(btnAceptar);
31 contenedor.add(btnCancelar);
32
33 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
34 setExtendedState(JFrame.NORMAL);
35 setPreferredSize(new Dimension(450, 200));
36 pack();
37 setVisible(true);
38 }
39 }
En las líneas 3 y 4 ahora se usa (*) para importar todos los componentes de la biblioteca
awt y swing, lo cual es una práctica no recomendada. Lo ideal es que se importe sólo lo
que se va requiriendo. Aquí para reducir el número de líneas de código se optará por la
práctica no recomendada.
Línea 11: se declara una instancia de JTextField, que como se puede ver en la figura
anterior, corresponde a un campo de texto en el que los usuarios pueden ingresar datos.
Línea 20: se crea la instancia de JLabel, note como el constructor recibe el texto que
muestra la etiqueta.
Línea 21: se crea la instancia de JTextField, note como el constructor recibe el tamaño del
campo de texto.
Líneas 25: como se intenta ilustrar en la figura siguiente, todo JFrame tiene asociado un
objeto de tipo Container que es el que en realidad contiene los elementos como etiquetas,
cajas de texto, botones, listas desplegables, etc.
Por consiguiente, lo que se hace en esta línea de código es asignar a la variable contenedor,
la instancia del Container del JFrame, retornada por el método getContentPane.
Línea 26: mediante el uso del método setLayout, se establece que el gestor de diseño del
contenedor es de tipo FlowLayout.
Para concluir con la explicación, digamos que la clase JTextField es una especialización de la
clase JTextComponent que permite mostrar y editar una única línea de texto. Como verá
enseguida, se utiliza frecuentemente para facilitarle al usuario el ingreso de datos breves en
formato texto.
La clase JLabel corresponde a una etiqueta que puede mostrar varias líneas de texto o
hipertextos con distintas fuentes, iconos o ambos. Por ser un componente de salida, no
permite al usuario seleccionar ni editar el texto establecido, pero es de gran utilidad al
momento de mostrar avisos al usuario.
La clase JButton permite crear botones en los que el usuario hace clic para desencadenar
acciones. Una aplicación de Java puede utilizar varios tipos de botones, incluyendo botones
de comando, casillas de verificación, botones interruptores y botones de opción. Todos los
tipos de botones son subclases de AbstractButton (paquete javax.swing), la cual declara las
características comunes para los botones de Swing.
3. Agregue al switch de DemoSwing un case “1”, impleméntelo como case “0”, sólo que para el
nuevo case se crea una instancia anónima de tipo DemoFlowLayout.
4. Ejecute la aplicación y observe el comportamiento del nuevo formulario con los elementos
dispuestos según FlowLayout.
A continuación, se indican los pasos necesarios para construir el ejemplo de la figura anterior:
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoGridLayout y verifique que,
para esta clase, la casilla public static void main(String[] args), esté desactivada.
1 package demoswing;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 public class DemoGridLayout extends JFrame {
7
8 public DemoGridLayout() {
9 inicializarComponentes();
10 }
11
12 private void inicializarComponentes() {
13 this.setTitle("Gestor de diseño GridLayout");
14
15 Container contenedor = getContentPane();
16 GridLayout grid = new GridLayout(4, 3);
17 grid.setHgap(5);
18 grid.setVgap(5);
19 contenedor.setLayout(grid);
20
21 for (int i = 1; i <= 3; i++) {
22 contenedor.add(new JButton("Botón " + i));
23 }
24 for (int i = 1; i <= 9; i++) {
25 contenedor.add(new JTextField("Campo de texto " + i));
26 }
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 89/191
27
28 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
29 setExtendedState(JFrame.NORMAL);
30 setPreferredSize(new Dimension(600, 200));
31
32 this.pack(); // la ventana se redimensiona con el tamaño y los diseños establecidos
33 setVisible(true);
34 }
35 }
Línea 16: se crea un gestor de contenido grid, de tipo GridLayout indicando que debe
distribuir el espacio de JFrame en 4 filas y 3 columnas.
Línea 17: se indica que el espacio horizontal entre los componentes es de 5 unidades.
Línea 18: se indica que el espacio vertical entre los componentes es de 5 unidades.
Línea 19: se establece que el gestor de diseño del contenedor es el creado en la línea 16.
3. Agregue al switch de DemoSwing un case “2” que le permita probar el comportamiento de esta
nueva clase.
BorderLayout: Este gestor de diseño, divide el contenedor en cinco zonas, una central y las otras cuatro
correspondientes a los puntos cardinales. Si no se ocupan las cinco zonas, el espacio disponible es
distribuido entre el resto de componentes. Observe cómo se vería la distribución de cinco botones
administrados por un BorderLayout:
A continuación, se indican los pasos necesarios para construir el ejemplo de la figura anterior:
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoBorderLayout y verifique que,
para esta clase, la casilla public static void main(String[] args), esté desactivada.
1 package demoswing;
2
3 import javax.swing.*;
4 import java.awt.*;
5
6 public class DemoBorderLayout extends JFrame {
7
8 public DemoBorderLayout() {
9 inicializarComponentes();
10 }
11
12 private void inicializarComponentes() {
13 this.setTitle("Gestor de diseño BorderLayout");
14
15 Container contenedor = getContentPane();
16 contenedor.setLayout(new BorderLayout(5, 5));
17
18 contenedor.add(new JButton("NORTE"), BorderLayout.NORTH);
19 contenedor.add(new JButton("SUR"), BorderLayout.SOUTH);
20 contenedor.add(new JButton("ESTE"), BorderLayout.EAST);
21 contenedor.add(new JButton("OESTE"), BorderLayout.WEST);
22 contenedor.add(new JButton("CENTRO"), BorderLayout.CENTER);
23
24 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
25 setExtendedState(JFrame.NORMAL);
26 setPreferredSize(new Dimension(600, 200));
27 pack();
28 setVisible(true);
29 }
30 }
3. Agregue al switch de DemoSwing un case “3” que le permita probar el comportamiento de esta
nueva clase.
A continuación, se indican los pasos necesarios para construir el ejemplo de la figura anterior:
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoBoxLayout1 y verifique que,
para esta clase, la casilla public static void main(String[] args), esté desactivada.
1 package demoswing;
2
3 import javax.swing.*;
4 import java.awt.*;
5
6 public class DemoBoxLayout1 extends JFrame {
7
8 private JLabel lbMensaje;
9 private JTextArea txtaEditor;
10 private JCheckBox chkSeleccion;
11 private JButton btnAceptar;
12
13 public DemoBoxLayout1() {
14 inicializarComponentes();
15 }
16
17 private void inicializarComponentes() {
18 this.setTitle("Gestor de diseño BoxLayout");
19
20 lbMensaje = new JLabel("Escriba en el \u00e1rea de texto siguiente:");
21 txtaEditor = new JTextArea();
22 chkSeleccion = new JCheckBox("Deshabilite el \u00e1rea de texto");
23 btnAceptar = new JButton("Acepte los cambios");
24
25 Container contenedor = getContentPane();
26 contenedor.setLayout(new BoxLayout(contenedor, BoxLayout.Y_AXIS));
3. Agregue al switch de DemoSwing un case “4” que le permita probar el comportamiento de esta
nueva clase.
4. Se dijo que BoxLayout tiene en cuenta el tamaño máximo, mínimo, preferido y la alineación de los
componentes. Esto se puede hacer mediante los siguientes métodos:
Para comprobar estos métodos se propone crear una nueva versión de la clase DemoBoxLayout1,
para que el formulario tenga la apariencia de la figura siguiente:
contenedor.add(lbMensaje);
contenedor.add(txtaEditor);
contenedor.add(chkSeleccion);
contenedor.add(btnAceptar);
setPreferredSize(new Dimension(600, 300)); // comentar y probar
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(JFrame.NORMAL);
pack();
setVisible(true);
}
6. El espacio que sobra por defecto en la parte inferior de la versión que acaba de probar, puede ser
redistribuido uniformemente si se utiliza el método estático createGlue de la clase Box para lograr
un efecto de distribución como el de la imagen, que permita ocupar toda la altura del formulario:
contenedor.add(Box.createGlue());
contenedor.add(lbMensaje);
contenedor.add(txtaEditor);
contenedor.add(Box.createGlue());
contenedor.add(chkSeleccion);
contenedor.add(Box.createGlue());
contenedor.add(btnAceptar);
contenedor.add(Box.createGlue());
7. Pruebe lo realizado en el punto anterior para determinar qué cambio sucede en la presentación
del formulario.
8. Se dejan para consulta y prueba, cómo usar los siguientes métodos que crean espacios rígidos:
A continuación, se indican los pasos necesarios para construir el ejemplo de la figura anterior en el que se
muestra cómo la etiqueta con el mensaje ocupa las dos primeras columnas de la primera fila, el último
botón las tres columnas de la última fila y los demás elementos sólo una celda cada uno.
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoGridBagLayout y verifique que,
para esta clase, la casilla public static void main(String[] args), esté desactivada.
1 package demoswing;
2
3 import javax.swing.*;
4 import java.awt.*;
5
6 public class DemoGridBagLayout extends JFrame {
7
8 private JLabel lblMensaje;
9 private JCheckBox chkCasilla1;
10 private JCheckBox chkCasilla2;
11 private JRadioButton rbtnOpcion1;
12 private JRadioButton rbtnOpcion2;
13 private JRadioButton rbtnOpcion3;
14 private JButton btnComando;
15
16 public DemoGridBagLayout() {
17 inicializarComponentes();
18 }
19
20 private void inicializarComponentes() {
21 this.setTitle("Gestor de diseño GridBagLayout");
Líneas de la 8 a la 14: Se declaran, en su orden, una etiqueta, dos casillas de selección, tres
botones radio y un botón normal. Las instancias respectivas se crean en las primeras líneas
del método inicializarComponentes.
Líneas de la 34 a la 40: como las instrucciones para colocar debidamente los componentes,
son las mismas, se construye el método agregarComponente para evitar la redundancia
de código.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 97/191
El método agregarComponente que se implementa a partir de la línea 49, define cinco
argumentos:
Línea 50: se crea un objeto de tipo GridBagConstraints que se utiliza para indicar las
restricciones de ubicación y tamaño de cada componente.
Línea 54: se indica que el componente se debe estirar hasta ocupar el ancho que se
estableció. Es por esta razón que el botón de la última fila, ocupa las tres columnas.
GroupLayout: Es un flexible gestor de diseño que dispone los componentes con base a los eje vertical y
horizontal separada y obligatoriamente. Es decir, cada componente debe estar presente tanto en el eje
vertical como en el horizontal.
Este gestor de diseño organiza los componentes o grupos de componentes de forma secuencial y paralela,
según la siguiente convención:
Los objetos SequentialGroup y objetos ParallelGroup permiten determinar un rango de amplitud para cada
componente. Además, permiten dejar espacios desocupados cuyo rango de amplitud también se puede
definir.
A continuación, se incluye la figura de un formulario en el que sus componentes han sido distribuidos
mediante GroupLayout:
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoGroupLayout y verifique que,
para esta clase, la casilla public static void main(String[] args), esté desactivada.
1 package demoswing;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 public class DemoGroupLayout extends JFrame {
7
8 JLabel lblNombre;
9 JLabel lblDireccion;
10 JLabel lblCorreo;
11 JTextField txtNombre;
12 JTextField txtDireccion;
13 JTextField txtCorreo;
14 JCheckBox chkActualizacion;
15 JCheckBox chkComentarios;
16 JCheckBox chkCodigo;
17 JCheckBox chkInfo;
18 JButton btnAceptar;
19 JButton btnCancelar;
20
21 public DemoGroupLayout() {
22 inicializarComponentes();
23 }
24
25 public void inicializarComponentes() {
26
27 lblNombre = new JLabel("Nombre: ");
28 lblDireccion = new JLabel("Dirección: ");
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 99/191
29 lblCorreo = new JLabel("Correo: ");
30 txtNombre = new JTextField(20);
31 txtDireccion = new JTextField(20);
32 txtCorreo = new JTextField(20);
33 chkActualizacion = new JCheckBox("Actualizaciones");
34 chkComentarios = new JCheckBox("Comentarios");
35 chkCodigo = new JCheckBox("Código Fuente");
36 chkInfo = new JCheckBox("Información");
37 btnAceptar = new JButton("Aceptar");
38 btnCancelar = new JButton("Cancelar");
39
40 GroupLayout layout = new GroupLayout(getContentPane());
41 getContentPane().setLayout(layout);
42
43 layout.setAutoCreateGaps(true); // espacio entre componentes
44 layout.setAutoCreateContainerGaps(true); // espacio entre componente contenedor
45
46 layout.setHorizontalGroup(layout.createSequentialGroup()
47 .addGroup(layout.createParallelGroup()
48 .addComponent(lblNombre)
49 .addComponent(lblDireccion)
50 .addComponent(lblCorreo)
51 )
52 .addGroup(layout.createParallelGroup()
53 .addComponent(txtNombre)
54 .addComponent(txtDireccion)
55 .addComponent(txtCorreo)
56 .addGroup(layout.createSequentialGroup()
57 .addGroup(layout.createParallelGroup()
58 .addComponent(chkActualizacion)
59 .addComponent(chkComentarios)
60 )
61 .addGroup(layout.createParallelGroup()
62 .addComponent(chkCodigo)
63 .addComponent(chkInfo)
64 )
65 )
66 )
67 .addGroup(layout.createParallelGroup()
68 .addComponent(btnAceptar)
69 .addComponent(btnCancelar)
70 )
71 );
72 layout.setVerticalGroup(layout.createSequentialGroup()
73 .addGroup(layout.createParallelGroup()
74 .addComponent(lblNombre)
75 .addComponent(txtNombre)
76 .addComponent(btnAceptar)
77 )
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 100/191
78 .addGroup(layout.createParallelGroup()
79 .addComponent(lblDireccion)
80 .addComponent(txtDireccion)
81 .addComponent(btnCancelar)
82 )
83 .addGroup(layout.createParallelGroup()
84 .addComponent(lblCorreo)
85 .addComponent(txtCorreo)
86 )
87 .addGroup(layout.createParallelGroup()
88 .addComponent(chkActualizacion)
89 .addComponent(chkCodigo)
90 )
91 .addGroup(layout.createParallelGroup()
92 .addComponent(chkComentarios)
93 .addComponent(chkInfo)
94 )
95 );
96
97 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
98 setExtendedState(JFrame.NORMAL);
99 setPreferredSize(new Dimension(600, 300));
100
101 this.pack(); // la ventana se redimensiona con el tamaño y los diseños establecidos
102 setVisible(true);
103 }
104 }
Línea 40: se crea el gestor. Observe que el constructor de este gestor, recibe como
argumento el contenedor que se va a gestionar.
Debe tenerse presente que este gestor obliga a que se establezca la distribución horizontal
y vertical.
Como puede ser más fácil de entender el asunto de las distribuciones de manera gráfica, enseguida
se presenta una imagen que representa el código desde la línea 46 hasta la 95:
A continuación, se indican los pasos necesarios para construir un formulario como el de la figura anterior,
mediante el uso de cuatro instancias de JPanel.
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoJPanel. Esta clase no incluye
el método public static void main(String[] args).
1 package demoswing;
2
3 import javax.swing.*;
4 import java.awt.*;
5
6 public class DemoJPanel extends JFrame {
7
8 public DemoJPanel() {
9 initComponents();
10 }
11
12 private void initComponents() {
13 setTitle("Demostración de JPanel");
14 jButtons = new JButton[8];
15 textoBotones = "Nuevo,Editar,Eliminar,Guardar,<< Inicio,< Anterior,Siguiente >,
Último >>".split(","); // esto es parte de la línea anterior
16
17 Container contenedor = getContentPane();
18 contenedor.setLayout(new BorderLayout(10, 10));
19
20 contenedor.add(crearPanelEdicion(), BorderLayout.NORTH);
21 contenedor.add(crearPanelPeticiones(), BorderLayout.WEST);
22 contenedor.add(crearPanelEntradas(), BorderLayout.EAST);
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 103/191
23 contenedor.add(crearPanelMovimiento(), BorderLayout.SOUTH);
24
25 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
26 setExtendedState(JFrame.NORMAL);
27 setPreferredSize(new Dimension(470, 225));
28 this.pack();
29 setVisible(true);
30 }
31
32 private JPanel crearPanelEdicion() {
33 JPanel jPanelEdicion = new JPanel();
34 jPanelEdicion.setBorder(BorderFactory.createEtchedBorder());
35
36 for (int i = 0; i < 4; i++) {
37 jButtons[i] = new JButton(textoBotones[i]);
38 jPanelEdicion.add(jButtons[i]);
39 }
40 return jPanelEdicion;
41 }
42
43 private JPanel crearPanelPeticiones() {
44 lblDocumento = new JLabel("Documento:");
45 lblNombre = new JLabel("Nombre completo:");
46 lblDireccion = new JLabel("Dirección:");
47
48 JPanel jPanelPeticiones = new JPanel();
49 jPanelPeticiones.setLayout(new BoxLayout(jPanelPeticiones, BoxLayout.Y_AXIS));
50
51 jPanelPeticiones.add(lblDocumento);
52 jPanelPeticiones.add(Box.createVerticalGlue());
53
54 jPanelPeticiones.add(lblNombre);
55 jPanelPeticiones.add(Box.createVerticalGlue());
56
57 jPanelPeticiones.add(lblDireccion);
58 return jPanelPeticiones;
59 }
60
61 private JPanel crearPanelEntradas() {
62 txtDocumento = new JTextField(30);
63 txtNombre = new JTextField(30);
64 txtDireccion = new JTextField(30);
65
66 JPanel jPanelEntradas = new JPanel();
67 jPanelEntradas.setLayout(new BoxLayout(jPanelEntradas, BoxLayout.Y_AXIS));
68
69 jPanelEntradas.add(txtDocumento);
70 jPanelEntradas.add(txtNombre);
71 jPanelEntradas.add(txtDireccion);
72 return jPanelEntradas;
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 104/191
73 }
74
75 private JPanel crearPanelMovimiento() {
76 JPanel jPanelMovimiento = new JPanel();
77 jPanelMovimiento.setBorder(BorderFactory.createEtchedBorder());
78
79 for (int i = 0; i < 4; i++) {
80 jButtons[i] = new JButton(textoBotones[i + 4]);
81 jPanelMovimiento.add(jButtons[i]);
82 }
83 return jPanelMovimiento;
84 }
85
86 private JButton jButtons[];
87 String textoBotones[];
88
89 private JLabel lblDireccion;
90 private JLabel lblDocumento;
91 private JLabel lblNombre;
92
93 private JTextField txtDireccion;
94 private JTextField txtDocumento;
95 private JTextField txtNombre;
96 }
4. Línea 18: se establece BorderLayout como gestor de diseño para el contenedor del JFrame.
5. Líneas de la 20 a la 23: se agregan al contenedor del JFrame, cuatro paneles que son retornados
por métodos implementados a partir de la línea 32.
7. Línea 34: al panel creado en la línea 33 se le asigna un tipo de borde para facilitar la visualización
del panel superior en tiempo de ejecución, a la vez que se logra una mejor presentación del
formulario.
8. Líneas de la 36 a la 39: se instancian los primeros 4 botones del formulario. Observe en la línea 37
que al crear cada botón se le asigna uno de los textos referidos en el paso 3. También observe que
en la línea 38 se agregan los botones al panel, antes de ser retornado este último.
9. Líneas de la 43 a la 59: se crea el panel que se muestra en la parte izquierda del formulario, con
las etiquetas que se utilizan para solicitar los datos al usuario. Estas etiquetas se disponen
verticalmente, gracias a las especificaciones del gestor de diseño en la línea 49.
10. Líneas de la 61 a la 73: se crea el panel que contiene los campos de texto que se muestran en la
parte derecha del formulario. Estos campos de texto se disponen verticalmente, gracias a las
especificaciones del gestor de diseño en la línea 67.
11. Líneas de la 75 a la 84: se crea el panel que se muestra en la parte inferior del formulario.
12. Líneas de la 79 a la 84: se crean los últimos 4 botones del array de 8 elementos que se instanció
en la línea 14. Observe que los textos que muestran los botones, corresponden a los últimos 4
elementos del array de Strings asignado en la línea 15.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 106/191
JScrollPane: Representa a un panel con barras de desplazamiento en el que puede incrustarse otro
componente como en este caso que incluye un JList. Este tipo de panel puede mostrar barras de
desplazamiento horizontal y/o vertical lo que los hace muy útiles para contener componentes como JList o
JTextArea que la mayoría de las veces tienen contenidos que no alcanzan a ser visibles en el área asignada.
Es importante tener en cuenta que el componente incluido dentro de un JScrollPane se denomina cliente
(en este caso el JList) y la zona de visualización se denomina puerto de visualización. Observe en la parte
izquierda de la imagen siguiente, una representación del contenedor JScrollPane:
A continuación, se indican los pasos necesarios para construir un formulario como el de la figura anterior,
mediante el uso de cuatro instancias de JPanel.
1. Agregue una nueva clase al proyecto, esta vez con el nombre DemoJScrollPane. Esta clase no
incluye el método public static void main(String[] args).
Las explicaciones sólo hacer referencia a las partes resaltadas del código anterior, teniendo en
cuenta que la mayor parte del código se base en conceptos ya explicados.
5. Línea 58: se crea un objeto de tipo JList. Este tipo de objeto permite desplegar listas de elementos.
6. Líneas 59 y 60: se asigna el objeto de tipo JList, como cliente al puerto de visualización del
JScrollPane. El objeto de tipo JScrollPane se agrega al panel contenedor principal.
7. Líneas de la 63 a la 78: el método retorna una instancia de JPanel configurada con los componentes
que se muestran en la figura siguiente:
8. Líneas de la 80 a la 101: el método retorna una instancia de JPanel configurada con los
componentes que se muestran en la figura siguiente:
Genéricos en Java
Los genéricos permiten que métodos, clases o interfaces22 puedan operar con distintos tipos de objetos
proporcionando seguridad en tiempo de compilación. Esto permite crear código más legible y mucho más
potente. Las definiciones e inicializaciones que usan genéricos se distinguen por el uso del operador
diamante “<>”, con el que se indica que una misma clase o método puede usar cualquier tipo de objeto.
Veamos algunos ejemplos basados en el código de la clase DemoJScrollPane que se acaba de documentar:
JList<String> lstNumeros; declara un objeto para contener una lista de elementos de tipo String.
También se hubiera podido declarar:
JList<Integer> lstNumeros; una lista de elementos de tipo Integer.
JList<Number> lstNumeros; una lista de elementos de tipo Number.
JList<Cliente> lstNumeros; una lista de elementos de tipo Cliente.
Observe que al momento de crear la instancia del JList, no se requiere volver a indicar el
tipo de objeto que almacenará la lista:
lstNumeros = new JList<>();
JComboBox<String> cboInferior; declara una lista desplegable de elementos de tipo String.
También se hubiera podido declarar:
JComboBox<Producto> cboInferior; una lista desplegable de elementos de tipo Producto.
JComboBox<Date> cboInferior; una lista desplegable de elementos de tipo Fecha.
Observe que al momento de crear la instancia del JComboBox, no se requiere volver a
indicar el tipo de objeto que almacenará la lista desplegable:
lstNumeros = new JList<>();
22
Por ahora, digamos que una interfaz define “un contrato” de implementación, es decir que cuando una clase
“implementa” una interfaz, está obligada a construir los métodos que se especifican en la interfaz. En la sección
dedicada al paradigma de orientación a objetos, se profundizará debidamente sobre el tema.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 111/191
Clases para el diseño de menús
Como habrá notado en casi todas las aplicaciones, los menús presentan en posiciones predeterminadas y
de forma sencilla, un conjunto de opciones que mejoran la usabilidad de las aplicaciones. Normalmente
aparecen colocados en una barra de menús o como menús contextuales asociados a un componente.
Swing permite crear menús como el que se muestra en la figura siguiente, a partir de varias clases, algunas
de las cuales se documentarán brevemente.
Como se aprecia en la gráfica anterior, las opciones están separadas por líneas horizontales provistas por
la clase JSeparator. Además de sencilla, esta clase es muy útil para separar grupos de opciones en un menú.
Con esto termina el recorrido por el paquete swing de Java, por supuesto no se trató sobre todos los
componentes, asunto que no forma parte de los objetivos de esta guía, por la amplitud del tema y porque
se cree que con las bases dadas es suficiente para permitir consultar los temas complementarios no
tratados, poder construir GUI acordes con la usabilidad requerida y abordar el tema del manejo de
eventos, sección en la que se explica cómo, los componentes permiten la interacción con el usuario.
Eventualmente más adelante, se incorporará información sobre otros gestores de diseño y componentes
swing.
De acuerdo a lo dicho, aquí se documentarán las bases esenciales para cubrir tres objetivos:
Empecemos diciendo que un evento en Java se gestiona mediante un objeto que contiene información
sobre el contexto en el que ocurrió una acción o evento. No siempre los eventos se generan sobre
componentes de una interfaz de usuario, por ejemplo, se puede generar un evento cuando un cronómetro
termine un conteo, cuando un contador alcance cierto valor, cuando se presente una excepción o error, o
cuando se termine un proceso.
1. Los objetos sobre los que se producen los eventos (event sources) registran los objetos que habrán
de gestionarlos (event listeners). Un ejemplo genérico sería el siguiente:
objeto.addEventoListener(…);
2. Los event listeners habrán de disponer de los métodos adecuados, que serán llamados
automáticamente cuando se produzca el evento. Ejemplo:
actionPerformed(ActionEvent evento)
keyPressed(KeyEvent)
mouseClicked(MouseEvent)
3. Para que los event listeners dispongan de los métodos adecuados para gestionar los eventos, es
necesario implementar una determinada interface Listener que se corresponde con los tipos de
eventos que se pueden producir. Ejemplo:
1. Agregue el paquete demoeventos a la aplicación DemoSwing. De aquí en adelante todas las clases
que se utilicen para realizar demostraciones de eventos se guardarán en este paquete.
import demoeventos.*;
import javax.swing.JOptionPane;
Lógicamente la instrucción de creación del objeto mostrará error, hasta tanto no se implemente
la clase DemoEvento1.
4. En la clase DemoSwing, método elegirOpcion, agregue una nueva opción a la lista que verá el
usuario:
Importante: tenga en cuenta los pasos 3 y 4 de ahora en adelante para probar las demostraciones
de implementación de eventos.
5. De manera similar a como agregó las clases que demuestran el uso de gestores de diseño, agregue
al paquete demoeventos, la clase DemoEvento1 e impleméntela como se muestra enseguida, para
probar que los botones correspondientes a un color determinado, cambian el fondo de la ventana:
1 package demoeventos;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 public class DemoEvento1 extends JFrame implements ActionListener {
8
9 private JButton btnAzul;
10 private JButton btnRojo;
11 private JButton btnVerde;
12 private Container contenedor;
13
Excepto el código resaltado, las instrucciones de esta clase ya deben ser comprensibles. Ahora veamos
cómo se implementó el modelo de eventos:
1. Se decía que “para que los event listeners dispongan de los métodos adecuados para gestionar los
eventos, es necesario implementar una determinada interface Listener que se corresponde con
los tipos de eventos que se pueden producir”. Pues bien, como se indica en la línea 7, la clase
DemoEvento1 implementa la interfaz ActionListener. Esta interfaz es como un contrato con el cual
2. También se dijo que “los objetos sobre los que se producen los eventos (event sources) registran
los objetos que habrán de gestionarlos (event listeners)”. En las líneas de la 28 a la 30 vemos como
los objetos sobre los que se producen los eventos, en este caso los botones, registran a this, el
objeto que habrá de gestionar el evento. Sabemos que this hace referencia a un objeto de tipo
DemoEvento1, pues cuando se usa this nos estamos refiriendo a una instancia de la clase actual.
Observe que el método actionPerformed, recibe como argumento la información del evento que
se desencadena, en este caso un clic.
4. En la línea 44 se referencia al objeto sobre el cual se originó el evento (sobre el cual se dio clic).
Pruebe ahora ejecutar a DemoSwing y observe los hermosos colores de fondo que toma el formulario
cuando se pulsa uno de sus botones.
Cree una nueva clase DemoEvento2 muy similar a la anterior, sólo que esta vez la clase no implementa la
interface ActionListener y por lo tanto no está obligada a tener el método actionPerformed. Observe que
en el mismo archivo se define la clase que se encarga de gestionar los eventos clic sobre los botones.
1 package demoeventos;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 public class DemoEvento2 extends JFrame {
8
9 private JButton btnAzul;
10 private JButton btnRojo;
11 private JButton btnVerde;
12 private Container contenedor;
13
14 public DemoEvento2() {
15 inicializarComponentes();
16 }
17
18 private void inicializarComponentes() {
19 setTitle("Demo Listener");
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 118/191
20
21 btnRojo = new JButton("Rojo");
22 btnVerde = new JButton("Verde");
23 btnAzul = new JButton("Azul");
24
25 contenedor = getContentPane();
26 contenedor.setLayout(new FlowLayout());
27
28 btnRojo.addActionListener(new AccionBoton());
29 btnVerde.addActionListener(new AccionBoton());
30 btnAzul.addActionListener(new AccionBoton());
31
32 contenedor.add(btnRojo);
33 contenedor.add(btnVerde);
34 contenedor.add(btnAzul);
35
36 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
37 setExtendedState(JFrame.NORMAL);
38 setPreferredSize(new Dimension(470, 225));
39 pack();
40 setVisible(true);
41 }
42
43 class AccionBoton implements ActionListener {
44
45 @Override
46 public void actionPerformed(ActionEvent evento) {
47 JButton origen = (JButton) evento.getSource();
48 Color color;
49
50 if (origen == btnRojo) {
51 color = Color.RED;
52 } else if (origen == btnVerde) {
53 color = Color.GREEN;
54 } else {
55 color = Color.BLUE;
56 }
57 contenedor.setBackground(color);
58 }
59 }
60 }
1. En las líneas de la 28 a la 30 de la clase DemoEvento2, los botones, registran al objeto que habrá
de gestionar el evento. Sólo que esta vez el objeto que gestiona los eventos es una instancia de la
clase AccionBoton y no this.
Para el ejemplo implemente la siguiente versión del mismo ejemplo de una clase que permite modificar el
color del formulario en tiempo de ejecución:
1 package demoeventos;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 public class DemoEvento3 extends JFrame {
8
9 private JButton btnAzul;
10 private JButton btnRojo;
11 private JButton btnVerde;
12 private Container contenedor;
13
14 public DemoEvento3() {
15 inicializarComponentes();
16 }
17
18 private void inicializarComponentes() {
19 setTitle("Demo Listener");
20
21 btnRojo = new JButton("Rojo");
22 btnVerde = new JButton("Verde");
23 btnAzul = new JButton("Azul");
24
25 contenedor = getContentPane();
26 contenedor.setLayout(new FlowLayout());
27
28 btnRojo.addActionListener(new ActionListener() {
29 @Override
30 public void actionPerformed(ActionEvent evento) {
31 contenedor.setBackground(Color.RED);
32 }
33 });
34
35 btnVerde.addActionListener(new ActionListener() {
36 @Override
37 public void actionPerformed(ActionEvent evento) {
23
Lógicamente también se habría podido implementar la clase AccionBoton totalmente aparte, pero haciendo uso
de un constructor parametrizado (new AccionBoton(contenedor, Color.XXX)) que haría más confuso el código.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 120/191
38 contenedor.setBackground(Color.GREEN);
39 }
40 });
41
42 btnAzul.addActionListener(new ActionListener() {
43 @Override
44 public void actionPerformed(ActionEvent evento) {
45 contenedor.setBackground(Color.BLUE);
46 }
47 });
48
49 contenedor.add(btnRojo);
50 contenedor.add(btnVerde);
51 contenedor.add(btnAzul);
52
53 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
54 setExtendedState(JFrame.NORMAL);
55 setPreferredSize(new Dimension(470, 225));
56 pack();
57 setVisible(true);
58 }
59 }
Observe en las líneas 28, 35 y 42 que ahora para definir el argumento de los métodos addActionListener,
se crea con new un objeto de una clase anónima que implementa la interface ActionListener.
A primera vista puede parecer una solución óptima pero aún es mejorable porque no es una buena práctica
escribir código directamente dentro del método actionPerformed, sino más bien separar el código
mediante llamados a métodos que se encarguen de llevar a cabo las acciones. Realmente en este ejemplo
no es necesario, pero habrá casos en que la respuesta a un evento no sea un simple cambio de color sino
la ejecución de varias líneas de código. Lo correcto sería entonces algo así como esto:
package demoeventos;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public DemoEvento4() {
inicializarComponentes();
}
contenedor = getContentPane();
contenedor.setLayout(new FlowLayout());
btnRojo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evento) {
colorActionPerformed(evento);
}
});
btnVerde.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evento) {
colorActionPerformed(evento);
}
});
btnAzul.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evento) {
colorActionPerformed(evento);
}
});
contenedor.add(btnRojo);
contenedor.add(btnVerde);
contenedor.add(btnAzul);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setExtendedState(JFrame.NORMAL);
setPreferredSize(new Dimension(470, 225));
pack();
setVisible(true);
}
if (origen == btnRojo) {
color = Color.RED;
} else if (origen == btnVerde) {
color = Color.GREEN;
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 122/191
} else {
color = Color.BLUE;
}
contenedor.setBackground(color);
}
}
Por último, tenga en cuenta que de ahora en adelante no se utilizará ninguna de las versiones anteriores,
dado que este curso busca introducir al estudiante en uno de los nuevos componentes más importantes
de la versión 8 de Java y es el soporte a nivel lenguaje de expresiones lambda (conocidas también como
funciones anónimas o clausuras). Así que de ahora en adelante cualquier evento que se requiera
implementar deberá tener en cuenta el siguiente modelo:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public DemoEvento5() {
inicializarComponentes();
}
contenedor = getContentPane();
contenedor.setLayout(new FlowLayout());
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setExtendedState(JFrame.NORMAL);
setPreferredSize(new Dimension(470, 225));
pack();
setVisible(true);
}
}
Actividad complementaria
Suponga que debe implementar una interfaz de usuario como la que se muestra enseguida, la cual, por
cada botón pulsado, mostrará una demostración de programación en otra ventana.
Si se fueran a definir los botones uno a uno, la cantidad de código similar sería enorme. Para estos casos
es mejor utilizar una estructura cíclica que reduzca drásticamente la cantidad de código necesario. De
hecho, ya se presentó un ejemplo similar, pero en este se incorporará la gestión de eventos para que,
como se dijo, al pulsar cada botón se muestre otra ventana o formulario como la de la figura siguiente,
que se despliega al pulsar el primer botón.
Empecemos entonces creando una estructura de proyecto como el que se muestra en la figura siguiente:
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 public class EstructurasProgramacion extends JFrame {
8
9 public EstructurasProgramacion() {
10 inicializarComponentes();
11 }
12
13 private void inicializarComponentes() {
14 this.setTitle("Ejemplos de Programación");
15
16 Container contenedor = getContentPane();
17
18 GridLayout grid = new GridLayout(10, 10);
19 grid.setHgap(5); // separación a izquierda y derecha
20 grid.setVgap(5); // separación arriba y abajo
21 contenedor.setLayout(grid);
22
23 int k = 1;
24
25 for (int j = 1; j < 11; j++) {
26 for (int i = 1; i < 11; i++) {
27 String texto = "Demo " + k;
28 JButton btnOpciones = new JButton(texto);
29 btnOpciones.addActionListener((ActionEvent evento) -> {
30 elegirOpcion(evento);
31 });
32 contenedor.add(btnOpciones);
33 k++;
34 }
35 }
36
Nota: este código no aporta conceptos nuevos por lo tanto no requiere explicaciones.
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 public class DemoSuma extends JFrame {
8
9 private JLabel lblValor1;
10 private JLabel lblValor2;
11 private JLabel lblResultado;
12 private JTextField txtValor1;
13 private JTextField txtValor2;
14 private JTextField txtResultado;
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 126/191
15 private JButton btnResultado;
16 private Container contenedor;
17
18 public DemoSuma() {
19 inicializarComponentes();
20 }
21
22 private void inicializarComponentes() {
23 this.setTitle("Formulario: suma de dos elementos");
24
25 lblValor1 = new JLabel("Primer valor: ");
26 lblValor2 = new JLabel("Segundo valor: ");
27 lblResultado = new JLabel("Resultado: ");
28
29 txtValor1 = new JTextField(30); // qué sucede si elimina el 30
30 txtValor2 = new JTextField(30);
31 txtResultado = new JTextField(30);
32
33 btnResultado = new JButton("Aceptar");
34 btnResultado.addActionListener((ActionEvent evento) -> {
35 sumarValores();
36 });
37
38 contenedor = getContentPane();
39 contenedor.setLayout(new GridBagLayout());
40
41 agregarComponente(contenedor, lblValor1, 0, 0, 1);
42 agregarComponente(contenedor, txtValor1, 1, 0, 50);
43 agregarComponente(contenedor, lblValor2, 0, 1, 1);
44 agregarComponente(contenedor, txtValor2, 1, 1, 1);
45 agregarComponente(contenedor, lblResultado, 0, 2, 1);
46 agregarComponente(contenedor, txtResultado, 1, 2, 1);
47 agregarComponente(contenedor, btnResultado, 0, 3, 2);
48
49 setPreferredSize(new Dimension(500, 300)); // si reduce estos valores qué sucede
50 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
51 setExtendedState(JFrame.NORMAL);
52 pack();
53 setVisible(true);
54 }
55
56 private void agregarComponente(Container contenedor,
JComponent componente, int x, int y, int ancho) {
57 GridBagConstraints gridBagConstraints = new GridBagConstraints();
58 gridBagConstraints.gridx = x;
59 gridBagConstraints.gridy = y;
60 gridBagConstraints.gridwidth = ancho;
61 gridBagConstraints.ipady = 10;
62 gridBagConstraints.insets = new Insets(10, 0, 0, 0);
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 127/191
63 gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
64 contenedor.add(componente, gridBagConstraints);
65 }
66
67 private void sumarValores() {
68 try {
69 double v1 = Double.parseDouble(txtValor1.getText());
70 double v2 = Double.parseDouble(txtValor2.getText());
71 double total = v1 + v2;
72 txtResultado.setText("" + total);
73 } catch (Exception e) {
74 txtResultado.setText("" + Double.NaN);
75 JOptionPane.showMessageDialog(this, "Al parecer no ingresó valores correctamente",
76 "¡Error!",
77 JOptionPane.INFORMATION_MESSAGE);
78 }
79 }
80 }
6. Ejecute la aplicación y pruebe que sucede al pulsar el primer botón y luego cualquier otro.
8. Diseñe formularios e implemente como se especifica en el punto 5, todas las prácticas y ejercicios
propuestos de estructura secuencial, estructura if y estructura switch, hasta la práctica 7 inclusive.
Por supuesto, puede utilizar los gestores de diseño que considere más apropiados.
Listas seleccionables: A veces es necesario restringirle la entrada de datos a un usuario para que sólo elija
un elemento de una lista, como en el caso planteado en la práctica 7, página 21 donde se permite al usuario
ingresar el número correspondiente a un mes y el sistema debe mostrar el nombre de dicho mes. Lo ideal
aquí es que el usuario pueda elegir el número del mes de una lista desplegable y que cuando se pulse
sobre el botón Aceptar, se muestre el mes en un campo de texto, de forma similar a como se ilustra en la
figura siguiente:
1 package estructurasprogramacion;
2
3 import javax.swing.DefaultListModel;
4
5 public class Listado {
6
7 public static String[] ordinales(int inicio, int fin) {
8 String serie [] = new String[fin – inicio + 1];
9 for (int i = 0; i < serie.length; i++) {
10 serie [i] = "" + (i + inicio); // se forza la conversión a string del contador
11 }
12 return serie;
13 }
14
15 public DefaultListModel listaPares(int inicio, int fin) {
16 DefaultListModel modelo = new DefaultListModel();
17 for (int i = inicio; i <= fin; i++) {
18 if (i % 2 == 0) {
19 modelo.addElement("" + i); // se forza la conversión a string
20 }
21 }
22 return modelo;
23 }
24
25 DefaultListModel listaImpares(int inicio, int fin) {
26 String mensaje = "Funcionalidad no soportada.\n"
27 + "Implemente de manera similar a listaPares()";
28 throw new UnsupportedOperationException(mensaje);
29 }
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 129/191
30
31 DefaultListModel fibonacci(int inicio, int fin) {
32 String mensaje = "Funcionalidad no soportada.\n"
33 + "Implemente de manera similar a listaPares()";
34 throw new UnsupportedOperationException(mensaje);
35 }
36
37 DefaultListModel primos(int inicio, int fin) {
38 String mensaje = "Funcionalidad no soportada.\n"
39 + "Implemente de manera similar a listaPares()";
40 throw new UnsupportedOperationException(mensaje);
41 }
42
43 DefaultListModel serie1(int inicio, int fin) {
44 String mensaje = "Funcionalidad no soportada.\n"
45 + "Implemente de manera similar a listaPares()";
46 throw new UnsupportedOperationException(mensaje);
47 }
48 }
Línea 3: se importa de swing la clase DefaultListModel que más adelante se utilizará para
agregar elementos a un objeto de tipo JList.
Líneas de las 7 a la 13: se implementa un método que devuelve un vector con los ordinales
comprendidos en un intervalo dado, pero observe que en realidad no devuelve un array
de números sino de cadenas de texto. También que dicho método tiene el modificador
static lo que permitirá llamarlo sin necesidad de instanciar la clase.
Líneas de la 15 a la 23: este método retorna también una lista de números, pero esta vez
sólo retorna los pares comprendidos entre un intervalo dado por los valores ingresados
como argumentos. Note que ya no se utiliza un array para retornar los números, sino que
los pares se van agregando al objeto modelo definido de tipo DefaultListModel.
Con esto queda dicho que un objeto de tipo DefaultListModel, permite agregar los
elementos que luego se mostrarán en un JList.
Línea 28: se emplea la instrucción throw que permite generar un error. Observe que para
generar un error se crea una instancia de un tipo de error determinado y que el constructor
recibe como argumento el mensaje de error que se dará.
2. Agregue la clase que creará el formulario en donde se podrá elegir un número de mes y obtener
el nombre correspondiente:
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
Linea 10: se define un componente de tipo JComboBox que permitirá listar los números de los
meses.
Línea 27: se utiliza el método setModel para asignar al combo la lista que mostrará. setModel
recibe como argumento un objeto de tipo DefaultComboBoxModel que aquí se crea a partir
de lo retornado por el método estático ordinales de la clase Listado.
Líneas de la 31 a la 33: cuando se pulse sobre el botón Aceptar se llamará al método que
determina el nombre del mes correspondiente al número de mes seleccionado en el combo.
Línea 66: se utiliza el método getSelectedItem del objeto JComboBox para acceder al elemento
seleccionado. Observe que lo retornado por getSelectedItem se convirtió a tipo String y que
dicho String se convirtió a una int mediante el llamado al método parseInt de la clase Integer.
Botones tipo radio: una alternativa a las listas seleccionables para elegir un elemento entre varios, son los
componentes de tipo JRadioButton. En la siguiente imagen, se muestra cómo utilizar este tipo de
componente para elegir un estado civil:
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 public class FrmEstadosCiviles extends JFrame {
8
9 private JButton btnAceptar;
10 private ButtonGroup btnGrpEstadosCiviles;
11 private JLabel lblEstadoElegido, lblMensaje;
12 private JRadioButton rbtnCasado, rbtnComprometido, rbtnDivorciado, rbtnSoltero, rbtnUnionLibre, rbtnViudo;
13 private JTextField txtEstadoElegido;
14 private Container contenedor;
15
88 } else if (rbtnViudo.isSelected()) {
89 txtEstadoElegido.setText(rbtnViudo.getText());
90 }
91 }
92 }
Línea 10: Se define un objeto de tipo ButtonGroup. Tenga en cuenta que cuando se utilizan
componentes de tipo JRadioButton es porque se quiere que el usuario elija una opción entre
varias, por lo tanto, es necesario agrupar todos los JRadioButton utilizando para ello un objeto de
tipo ButtonGroup; si esto no se hace se permitiría marcar varios botones radio como
seleccionados, lo cual es un error de usabilidad.
Línea 12: se definen los botones que serán agrupados en el objeto btnGrpEstadosCiviles definido
de tipo ButtonGroup.
Líneas de la 40 a la 45: en esta porción de código puede observar cómo se hace para agregar los
botones radio al ButtonGroup.
Líneas de la 77 a la 91: en esta porción de código se muestra cómo determinar cuál botón radio
ha sido seleccionado.
Casillas de selección: Cuando se requiera una selección múltiple, lo ideal es usar componentes de tipo
JCheckBox. En la siguiente imagen, se muestra cómo utilizar este tipo de componente para elegir las
preferencias entre varios lenguajes de programación:
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 public class FrmPreferencias extends JFrame {
8
9 private JButton btnAceptar;
10 private JCheckBox chkC, chkCPlus, chkC_sharp, chkJS, chkJava, chkPHP, chkPerl, chkPython, chkVBNet;
11 private JLabel lblElegidos;
12 private JLabel lblMensaje;
13 private JTextField txtLenguajesElegidos;
14 private Container contenedor;
15
16 public FrmPreferencias() {
17 initComponents();
18 }
19
Cómo dibujar en Java: Java incluye varias librerías para dibujar en 2D y en 3d, cuya densidad daría para
escribir dos libros sobre ellas. Aquí se documenta una elemental forma de dibujar un círculo con colores
aleatorios, cada vez que se pulsa el botón “Probar suerte”. Si por azar el círculo se dibuja de color azul, se
mostrará el mensaje: “¡Felicitaciones!, ganaste la mitad de la compra”:
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.ActionEvent;
5 import java.util.concurrent.ThreadLocalRandom;
6 import javax.swing.*;
7
8 public class FrmColorAleatorio extends JFrame {
9
10 private JButton btnAceptar;
11 private Container contenedor;
12
13 public FrmColorAleatorio() {
14 inicializarComponentes();
15 }
16
Línea 21: observe que al panel contenedor se agrega una instancia anónima de tipo PanelDibujo.
Esta clase interna se define a partir de la línea 33.
Línea 25: se utiliza el método repaint, que como su nombre lo indica, vuelve a “repintar” todo el
panel. Todo objeto que se derive de Component, hereda este método para permitir volver a
mostrar el componente cuando sufra algún cambio.
Línea 33: se define una clase dentro de FrmColorAleatorio, es decir, se crea una clase interna que
hereda todo lo de un objeto de tipo JPanel.
Línea 42: se utiliza el constructor por defecto para establecer mediante setPreferredSize que el
panel tendrá unas dimensiones de 400x400 pixeles.
Línea 46: se implementa el método paintComponent, el cual permite dibujar sobre un panel.
Línea 47: se genera un valor aleatorio entre 0 y 12. Recuerde que se ha definido un array de 13
colores por lo tanto este valor aleatorio puede utilizarse como índice para seleccionar un color.
Línea 48: si el índice aleatorio apunta al color azul se estableCE un tamaño de fuente 16 en negrilla
y se escribe un mensaje de felicitación por haber seleccionado el supuesto color ganador.
Línea 53: se dibuja un óvalo a partir de las coordenadas 20, 20 con 350 pixeles de ancho y altura.
Por supuesto como el ancho y la altura son iguales, lo que se dibuja es un círculo.
Otros tipos de listeners: hasta ahora se han realizado demostraciones de cómo se pueden gestionar
eventos clic sobre objetos de tipo JButton. Pero esto no es suficiente, habrá ocasiones en donde es
necesario determinar si una casilla o un botón de selección está marcado como seleccionado o no, o si se
ha elegido un elemento de una lista. Para documentar estos casos, en los pasos siguientes se utilizará la
clase con la que se demostró el uso de JScrollPane, documentada a partir de la página 107, esta vez
agregando los listeners necesarios y asociando dicha clase a la clase Listado que será la clase encargada de
proporcionar algunas listas necesarias.
1. Cree la clase DemoListas dentro del paquete estructurasprogramacion. Como se indicó el código
de esta clase es muy similar a la clase DemoJScrollPane documentada en la página 107. Por lo
tanto, sólo se explicarán los nuevos conceptos que aparecen en ella.
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 140/191
7 public class DemoListas extends JFrame {
8
9 private JList<String> lstNumeros;
10 private JPanel panelSeleccion;
11 private ButtonGroup btnGrpOpciones;
12 private JRadioButton radioButton;
13 String textoBotones[];
14
15 private JLabel lblInferior;
16 private JLabel lblSuperior;
17 private JComboBox<String> cboInferior;
18 private JComboBox<String> cboSuperior;
19
20 private JTextArea textArea;
21 private String opcionActual;
22
23 public DemoListas() {
24 inicializarComponentes();
25 }
26
27 private void inicializarComponentes() {
28 opcionActual = "Serie no seleccionada";
29 setTitle("Demostración de JScrollPane");
30 Container contenedor = getContentPane();
31 contenedor.setLayout(new GridLayout(1, 3));
32
33 contenedor.add(crearJScrollPane());
34 contenedor.add(crearPanelSeleccion());
35 contenedor.add(crearPanelOpciones());
36
37 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
38 setExtendedState(JFrame.NORMAL);
39 setPreferredSize(new Dimension(600, 240));
40 this.pack();
41 setVisible(true);
42 }
43
44 private void agregarComponente(Container contenedor, JComponent componente,
int fila, int columna, int colsAncho) {
45 GridBagConstraints gridBagConstraints = new GridBagConstraints();
46 gridBagConstraints.gridx = columna;
47 gridBagConstraints.gridy = fila;
48 gridBagConstraints.gridwidth = colsAncho;
49 gridBagConstraints.ipady = 5;
50 gridBagConstraints.insets = new Insets(5, 5, 5, 5);
51 gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
52 contenedor.add(componente, gridBagConstraints);
53 }
54
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 141/191
55 private JScrollPane crearJScrollPane() {
56 JScrollPane scrollNumeros = new JScrollPane();
57 scrollNumeros.setBorder(BorderFactory.createTitledBorder(" Lista: "));
58 lstNumeros = new JList<>();
59 scrollNumeros.setViewportView(lstNumeros);
60 return scrollNumeros;
61 }
62
63 public JPanel crearPanelSeleccion() {
64 panelSeleccion = new JPanel();
65 panelSeleccion.setBorder(BorderFactory.createTitledBorder(" Series disponibles: "));
66 panelSeleccion.setLayout(new BoxLayout(panelSeleccion, BoxLayout.Y_AXIS));
67
68 textoBotones = "Números pares,Números impares,Serie de Fibonacci,
Números primos,Una serie matemática".split(",");
69
70 btnGrpOpciones = new ButtonGroup();
71 for (int i = 0; i < 5; i++) {
72 radioButton = new JRadioButton(textoBotones[i]);
73 radioButton.addActionListener((ActionEvent evento) -> {
74 gestionarEvento(evento);
75 });
76 btnGrpOpciones.add(radioButton);
77 panelSeleccion.add(radioButton);
78 }
79 return panelSeleccion;
80 }
81
82 public JPanel crearPanelOpciones() {
83 JPanel panelOpciones = new JPanel();
84
85 panelOpciones.setBorder(BorderFactory.createTitledBorder(" Opciones: "));
86 panelOpciones.setLayout(new GridBagLayout());
87
88 lblInferior = new JLabel("Intervalo inferior: ");
89 agregarComponente(panelOpciones, lblInferior, 0, 0, 1);
90
91 cboInferior = new JComboBox<>(new DefaultComboBoxModel<>(Listado.ordinales(0, 100)));
92 cboInferior.addItemListener((ItemEvent evento) -> {
93 gestionarEvento(evento);
94 });
95 agregarComponente(panelOpciones, cboInferior, 0, 1, 1);
96
97 lblSuperior = new JLabel("Intervalo superior: ");
98 agregarComponente(panelOpciones, lblSuperior, 1, 0, 1);
99
100 cboSuperior = new JComboBox<>( new DefaultComboBoxModel<>(Listado.ordinales(0, 100)));
101 cboSuperior.addItemListener((ItemEvent evento) -> {
102 gestionarEvento(evento);
103 });
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 142/191
104 agregarComponente(panelOpciones, cboSuperior, 1, 1, 1);
105
106 textArea = new JTextArea(5, 25);
107 textArea.setEditable(true);
108 textArea.setLineWrap(true);
109 textArea.setWrapStyleWord(true);
110 agregarComponente(panelOpciones, textArea, 2, 0, 2);
111 return panelOpciones;
112 }
113
114 private void gestionarEvento(ActionEvent evento) {
115 Object origen = evento.getSource();
116 JRadioButton radioButton = (JRadioButton) origen;
117 opcionActual = radioButton.getText();
118 mostrarEleccion();
119 }
120
121 private void gestionarEvento(ItemEvent evento) {
122 ItemEvent evt = (ItemEvent) evento;
123 if (evt.getStateChange() == ItemEvent.SELECTED) {
124 mostrarEleccion();
125 }
126 }
127
128 private void mostrarEleccion() {
129 Listado lst = new Listado();
130 try {
131 int inicio = Integer.parseInt((String) cboInferior.getSelectedItem());
132 int fin = Integer.parseInt((String) cboSuperior.getSelectedItem());
133 String mensaje = opcionActual + '\n'
134 + "Desde: " + inicio + '\n'
135 + "Hasta: " + fin;
136 textArea.setText(mensaje);
137 switch (opcionActual) {
138 case "Números pares":
139 lstNumeros.setModel(lst.listaPares(inicio, fin));
140 break;
141 case "Números impares":
142 lstNumeros.setModel(lst.listaImpares(inicio, fin));
143 break;
144 case "Serie de Fibonacci":
145 // falta llamar a la función respectiva del objeto lst
146 break;
147 case "Números primos":
148 // falta llamar a la función respectiva del objeto lst
149 break;
150 case "Una Serie matemática":
151 // implemente como en el caso anterior
152 break;
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 143/191
153 }
154 } catch (NumberFormatException e) {
155 textArea.setText("Se requiere una lista seleccionada y los datos del intervalo.");
156 } catch (Exception e) {
157 textArea.setText(e.getMessage());
158 }
159 }
160 }
En esta clase aparecen nuevos conceptos y algunos que es necesario recordar. Veamos:
Líneas 9, 17 y 18: aparece de nuevo el concepto de los genéricos ya explicados en la página 111.
Aquí se está indicando en el operador diamante (<>) que tanto el objeto JList como los objetos
JComboBox almacenarán listas de Strings. También se hubiera podido indicar cualquier otro tipo
de objeto.
Línea 57: como en la línea 9 ya se indicó el tipo de objeto para la lista, aquí, al momento de crear
la instancia, el operador diamante ya no indica que la lista es de tipo String, si se especificara Java
generaría una advertencia de redundancia.
Línea 68: se guardan en el array textoBotones 5 elementos de tipo String que son el resultado de
dividir la cadena mediante el llamado al método split, indicándole mediante el argumento que la
cadena se divide cada vez que encuentre una coma. Aunque la cadena de la línea 68 aparece en
dos líneas debe transcribirse en una sola, teniendo especial cuidado de la forma en que fue escrita.
Líneas de la 72 a la 74: a cada nuevo radioButton creado, se le agrega un oyente de evento de tipo
ActionListener.
Líneas de la 91 a la 94 y de la 100 a 103: a los nuevos JComboBox, se les agregan oyentes de eventos
de tipo ItemListener. Este “auditor” de evento detecta cada vez que se seleccione un elemento de
la lista, por lo tanto, permite “hacer algo” cada vez que se cambie de elemento.
También compare la instrucción de la línea 100 con la forma en que se crean los combos en la
clase DemoJComboBox, en dicha clase se utilizaban instrucciones separadas para crear la instancia
y luego asignar los datos, aquí se crea la instancia y se inicializa en la misma línea 100. Las
siguientes son las dos instrucciones utilizadas en DemoJComboBox.
Líneas 91 y 100: dicho de otra manera lo del punto anterior, los constructores asocian a los
combos, objetos de tipo DefaultComboBoxModel creados a partir del método estático ordinales,
definido en la clase Listado. Por lo tanto, los objetos DefaultComboBoxModel son los encargados
de manejar los elementos que muestran los JComboBox, con lo cual queda claro que para Java
unos son los componentes gráficos que muestran las listas y otros son los componentes que
gestionan los elementos de las listas. A esta técnica se le conoce como “separación de la vista del
Líneas de la 114 a la 119: lo que se hace es determinar sobre qué radioButton se originó el evento
para establecer cuál es la opción de lista que hay que mostrar.
Líneas 131 y 132: se convierten a enteros los elementos inicio y fin, seleccionados en las listas
desplegables.
Líneas 139 y 142: se establecen las listas a mostrar de acuerdo a la elección hecha por el usuario,
utilizando para ello la información proporcionada por el objeto de tipo Listado.
Ejercicios para desarrollar la destreza: hasta el momento se le ha guiado paso a paso en la implementación
de gestores de diseño y en el manejo de eventos, a partir de esta parte sólo se le indicará qué debe
implementar de acuerdo a lo aprendido:
Como puede ver en la parte izquierda se especifican cada uno de los componentes de la clase,
inclusive los nombres que debe utilizar y sus tipos.
Su misión consiste en implementar dicho formulario y hacer que el botón “calcular sueldo” realice
lo especificado en las páginas 22 y 23.
Importante:
para colocar los elementos en los dos paneles de tipo GridBagLayout, use el método
agregarComponente, documentado en varias de las clases anteriores.
panelEntradas.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(), "Entrada de datos: "
));
3. En un supermercado tienen una promoción para los clientes que consiste en descontar el 50% de
lo facturado si al pulsar el botón “probar suerte”, al cliente se le muestra el color azul.
6. Seguidamente, con los pequeños cambios que se aprecian en la figura siguiente, la cual representa
la nueva interfaz de usuario de DemoListas, se puede mostrar la sumatoria de los elementos de la
lista actual. Para ello agregue la etiqueta y el campo de texto que se resaltan en la imagen
siguiente:
7. Ahora observe la pequeña adición que se debe hacer en mostrarEleccion para mostrar la sumatoria
de los pares:
switch (opcionActual) {
case "Números pares":
lstNumeros.setModel(lst.listaPares(inicio, fin));
txtSumatoria.setText("" + Listado.sumatoria(lstNumeros.getModel()));
break;
Como puede ver, se envía como argumento el modelo de datos de la lista al método sumatoria y
el valor devuelto por dicho método se asigna al campo de texto respectivo.
8. Además de la sumatoria de los elementos, muestre también en campos de texto distintos, el total
de elementos, el promedio, el mayor y el menor valor de la lista.
Tablas: En muchas ocasiones será necesario mostrar listados de información en varias columnas, para lo
cual ya no son apropiados los objetos JComboBox y JList, para estos casos, Swing proporciona la clase
JTable que se utiliza también asociada a un modelo de datos y si ésta tiene muchas filas deberá estar
contenida dentro de un objeto de tipo JScrollPane para permitir el desplazamiento por los registros.
Suponga por ejemplo que se quiere crear una instancia de JTable de cuatro columnas, con sólo la cabecera
de la tabla, sin filas adicionales, como la tabla que se muestra en la figura siguiente:
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 147/191
El código necesario para crear la instancia mostrada, sería algo así como esto:
Observe que se utiliza la misma técnica que se usó para crear instancias de JComboBox y de JList. Sólo que
ahora el modelo recibe un array bidimensional de objetos en vez de una lista de elementos.
Con base en lo expuesto y continuando con la filosofía de separar la vista del modelo, vamos ahora a
implementar una clase que se encargue de manipular los datos de las tablas y otra clase que se encargue
de mostrar la GUI de la tabla, con una estructura similar a la que se muestra en la figura siguiente:
package estructurasprogramacion;
import java.util.concurrent.ThreadLocalRandom;
import javax.swing.JTable;
import javax.swing.table.*;
/**
* Retorna un modelo de datos conteniendo enteros aleatorios usable en un objeto JTable.
* Tanto los nombres de las columnas como el número de ellas está dado por el valor indicador
* en el primer argumento.
* @param cabecera Un array de Strings que determina el número de columnas y los nombres
* que tendrán éstas.
* @param filas La cantidad de filas que se llenará.
* @return Un modelo de datos bidimensional de enteros aleatorios.
*/
public static DefaultTableModel getModelo(String cabecera[], int filas) {
int cols = cabecera.length;
Integer datosTabla[][] = new Integer[filas][cols];
/**
* Alinea los valores de todas las columnas de una tabla dada como argumento.
* @param tabla Una referencia al objeto JTable que será modificado.
* @param alineacion El tipo de alineación que se utilizará, puede ser:
* JLabel.CENTER o JLabel.RIGHT
*/
public static void alinearValores(JTable tabla, int alineacion) {
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment(alineacion);
TableColumnModel columnas = tabla.getColumnModel();
3. Cree la clase DemoTabla dentro del paquete estructuras programación e impleméntela como se
muestra a continuación:
1 package estructurasprogramacion;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6 import javax.swing.table.*;
7
8 public class DemoTabla extends JFrame {
9
10 private JButton btnLlenar, btnCalcular;
11 private JScrollPane scrollPane;
12 private JTable tablaValores;
13 private Container contenedor;
14 private JPanel panelOpciones;
15 private String[] colsTabla;
16
17 public DemoTabla() {
18 inicializarComponentes();
19 }
20
4. Documente la clase anterior según las especificaciones de la clase Tabla y de acuerdo a las
explicaciones siguientes.
a. Líneas 24 y 25: se define un vector que representa las columnas que tendrá la tabla.
b. Línea 30: el modelo de datos para el objeto de tipo JTable se crea siempre indicando el
array de datos, en este caso el array de objetos vacío y la cabecera de la tabla con 4
columnas.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 151/191
c. Línea 31: observe que la tabla se “incrusta” dentro de un objeto de tipo JScrollPane
anticipando la posibilidad de que la tabla tenga tantas filas que sea imposible desplegarlas
todas de una vez.
d. Línea 35: cada vez que se pulsa clic en “llenar tabla”, se asigna un modelo de datos con
valores aleatorios, con las mismas columnas con que se creó inicialmente la tabla, pero
esta vez ya no vacío sino con 30 filas de enteros aleatorios, según lo especificado en el
método getModelo, utilizado para crear el modelo de datos.
e. Línea 36: se utiliza el método alinearValores para centrar todos los elementos de la tabla.
f. Líneas 41 y 42: cada vez que se pulsa clic sobre “calcular”, se totalizan correctamente las
filas y las columnas en la última columna y en la última fila.
5. Pruebe como se ha indicado hasta ahora el funcionamiento de esta nueva demostración. Tenga
en cuenta que los datos de la tabla son editables y que por lo tanto puede hacer cambios
manualmente.
6. Realice las modificaciones necesarias para que el usuario pueda ingresar las columnas de la
cabecera y el número de filas que tendrá la tabla. Para el caso tenga en cuenta que un String
soporta el método Split.
De esta manera, la aplicación puede solicitar al usuario el número de filas, los nombres de las
columnas separadas por comas y crear la tabla con las especificaciones dadas por el usuario.
7. Agregue otras 5 opciones a las series disponibles e implemente las funciones respectivas en la
clase Listado:
b. Crea una tabla que permita ingresar 4 notas para cada uno de N estudiantes y muestre las
notas parciales y el promedio obtenido por cada uno. Tenga en cuenta que la entrada de
tablaValores.setModel(new DefaultTableModel(
new Object[numFilas][numCols]{},
new String[]{
"Nota 1", …, "Definitiva"
}
d. Muestre el promedio de cada una de las columnas de la tabla. Esto permitirá conocer
cuánto fue el promedio del grupo en el primer parcial, en el segundo parcial y así
sucesivamente.
e. Adaptar para GUI los ejercicios 8 y 9 de las actividades complementarias de la práctica 10.
En realidad, esto ha sido una breve introducción al manejo de eventos en Java, sin embargo, es suficiente
para entender la técnica de asociar “oyentes de eventos” a los objetos y capturar eventos. Para dar un
idea de la complejidad del asunto, observe en la figura siguiente la jerarquía de eventos que proporciona
awt24.
24
Tomado de ntu.edu.sg/home/ehchua/programming/java/J4a_GUI_2.html
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 153/191
También observe la rica colección de “oyentes de eventos”25 de la que se dispone:
En la siguiente tabla se describen los principales tipos de eventos que se pueden llegar a necesitar y los
oyentes y métodos asociados. Tenga en cuenta que si usa notación Lambda sólo requerirá conocer el tipo
de listener que escucha el evento (primera columna de la tabla) y el tipo de evento a escuchar (parámetros
de los métodos listados en la última columna), para ser usados mediante la siguiente sintaxis:
25
Tomada de slideplayer.com/slide/8528469/
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 154/191
Tipo Listener Descripción del evento Método y Tipo de Evento
ratón, se hace clic con él, o el ratón entra en mouseExited(MouseEvent e)
un componente o sale de él mouseReleased(MouseEvent e)
mousePressed(MouseEvent e)
MouseMotionListener Define dos métodos para reconocer cuándo mouseDragged(MouseEvent e)
se arrastra o se mueve el ratón. mouseMoved(MouseEvent e)
MouseWheelListener Define un método para reconocer cuándo la mouseWheelMoved(MouseWheelEvent e)
rueda del ratón se mueve.
TextListener Define un método para reconocer cuándo textValueChanged(TextEvent e)
cambia un valor de texto.
WindowFocusListener Define dos métodos para reconocer cuándo windowGainedFocus (WindowEvent e)
una ventana gana o pierde foco de entrada. windowLostFocus(WindowEvent e)
WindowListener Define siete métodos para reconocer cuándo windowActivated(WindowEvent e)
una ventana se activa, se cierra, se desactiva, windowDesactivated(WindowEvent e)
se minimiza, se maximiza, se abre o se sale windowOpened(WindowEvent e)
de ella. windowClosed(WindowEvent e)
windowClosing(WindowEvent e)
windowIconified(WindowEvent e)
windowDeiconified(WindowEvent e)
A partir de este capítulo nos ocuparemos del paradigma orientado a objetos que copia de la realidad que
conocemos varios aspectos que, por lo evidentes, la mayoría de las veces los pasamos desapercibidos.
Veamos algunos de ellos:
1. Lo que llamamos “realidad” es en verdad un sistema compuesto por múltiples subsistemas en los
que interactúan entidades. Por ejemplo, la población mundial se agrupa por países, los países se
agrupan por comunidades a las cuales les dan diversos nombres, estas comunidades están
formadas por familias de diversos tipos y las familias están formadas por personas.
Con base en los aspectos descritos, es posible comprender cómo el paradigma de orientación a objetos
(POO) lleva a la realidad de los sistemas de información muchos de los principios que rigen los sistemas
naturales. Veamos:
2. Puesto que los objetos se originan a partir de “abstracciones” denominadas “clases”, se deduce
que un objeto es la concreción de una clase a lo que se denomina comúnmente instancia de clase.
3. Una clase entonces hace posible que los objetos creados a partir de ella, tengan características y
comportamientos o funcionalidad definidos por su tipo o clase y que el comportamiento del
sistema del cual forma parte, sea en realidad la suma del comportamiento de sus objetos.
Empecemos por definir las características esenciales de una clase, para luego enfocarnos en las
características de la programación orientada a objetos (POO).
Clases y objetos
Una clase es la representación abstracta de los atributos y la funcionalidad que hace posible la definición
de objetos.
Por ser abstractas, las clases se quedan en el mundo de las ideas y sólo se pueden concretar cuando a
partir de ellas se definen objetos, también llamados instancias de clases. Los objetos, por ser concretos,
Observe que en el esquema anterior la clase, siempre escrita con mayúscula inicial, representa a cualquier
persona y la instancia representa a una persona concreta con los atributos y métodos propios de su clase.
Atributos: como se ha dicho los atributos definen las características o propiedades de los objetos. En Java,
básicamente estos atributos se definen de la siguiente manera:
Los modificadores de ámbito pueden ser public, private, protected o default. Si no se especifica un
modificador de ámbito, el atributo será visible a nivel de paquete. Los corchetes en la expresión indican
que el modificador de ámbito es opcional.
También se pueden especificar los modificadores final y static, el primero para indicar que el valor del
atributo no podrá ser cambiado y el segundo para señalar que el elemento es un miembro de clase y no
un miembro de instancia de clase.
Recuerde lo que ya se ha indicado: cuando un atributo o un método es static y por lo tanto miembro de
clase se puede utilizar de la forma NombreClase.atributo o Nombre.claseMétodo. Cuando un miembro es
un miembro de instancia requiere que se defina un objeto a partir de la clase para posiblemente poder
acceder a él. Cuando se dice posiblemente, se tiene en cuenta la restricción dada por el ámbito según los
modificadores de acceso. Por ejemplo, será imposible acceder directamente a un atributo privado de una
clase, desde otra.
Métodos: los métodos de una clase definen el comportamiento de la misma y su ámbito de uso también
está condicionado al tipo de modificador con que sean definidos. La forma general de un método es la
siguiente:
[modificadoresDeMétodos] tipoDeResultado nombreMétodo ([tipoP1 p1 [, ...]]) [throws Excepción1 [,...]] {
//cuerpo del método
}
Existen tres tipos básicos de métodos que, según la OO, deberían ir siempre en una clase: los accedentes,
los mutadores y los constructores. Opcionalmente también es posible incluir un método para comparar
las instancias con otros objetos y otro más que proporcione información básica de los atributos de clase.
Veamos:
Constructores: son métodos que en Java tienen el mismo nombre de la clase y se utilizan para
crear las instancias de clase. Ejemplo:
// constructor parametrizado
public Persona(String identificacion, String nombreCompleto, String direccionesDeEntrega, String telefonos) {
this.identificacion = identificacion;
this.nombreCompleto = nombreCompleto;
this.direccionesDeEntrega = direccionesDeEntrega;
this.telefonos = telefonos;
}
// constructor copia. No se requiere en Java, todo objeto en Java cuenta con el método clone
public Persona(Persona p) {
this.identificacion = p.identificacion;
this.nombreCompleto = p.nombreCompleto;
this.telefonos = p.telefonos;
}
a) El primero, un constructor por defecto que no es necesario definirlo en una clase, a menos
que se deba llevar a cabo una inicialización especial o se vayan a definir otros tipos de
constructores. No tiene argumentos y permite crear objetos como se ilustra en el ejemplo:
Persona px = new Persona ("102030”, “Carlos Cuesta I.”, “Calle 66...”, “313...");
c) El constructor copia, como su nombre lo indica, lo que permite es hacer una copia de una
instancia y por eso recibe como argumento un objeto que tiene como tipo la propia clase.
Ejemplo de su uso:
De acuerdo con lo expuesto hasta ahora, la instancia cliente2 tendrá los mismos valores
de atributos que px, pero serán dos instancias diferentes, por lo que más adelante se
pueden cambiar los datos de una sin afectar a la otra. Distinto a que si se hubiera hecho
algo así como esto:
Es de anotar que la instrucción anterior no define un nuevo objeto, sino una nueva
referencia a cliente2, por lo tanto, al utilizar cualquiera de las dos variables estará
afectando al mismo objeto.
Más adelante se podrá clonar un objeto sin necesidad de utilizar el constructor copia.
Accedentes: son métodos que permiten acceder a los atributos de la clase, generalmente se
definen como getNombreAtributo. Ejemplo:
Mutadores: son métodos que permiten asignar los valores de los atributos de la clase,
generalmente se definen como setNombreAtributo y reciben como argumento el dato a ser
asignado. Ejemplo:
package poo;
import java.util.Objects;
Persona() { }
public Persona(Persona p) {
this.identificacion = p.identificacion;
this.nombreCompleto = p.nombreCompleto;
this.telefonos = p.telefonos;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Persona other = (Persona) obj;
if (!Objects.equals(this.identificacion, other.identificacion)) {
return false;
}
if (!Objects.equals(this.nombreCompleto, other.nombreCompleto)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Persona{\n" + " identificacion=" + identificacion +
",\n nombreCompleto=" + nombreCompleto +
",\n direccionesDeEntrega=" + direccionesDeEntrega +
",\n telefonos=" + telefonos + "\n}";
}
}
Resulta que, en Java, toda clase que se escribe se deriva implícitamente de la clase Object y, por lo tanto,
hereda de ella. Como la clase Object tiene ya definidos los métodos equals y toString, por eso aquí se hace
la anotación indicando que están sobrescritos.
package poo;
2. Defina las clases que se indican en la primera columna de la tabla siguiente, teniendo en cuenta
los datos del contexto indicado en la segunda columna:
Con base en lo expuesto sobre clases ya se cuenta con el conocimiento necesario para dar inicio al estudio
de las cinco características básicas de la POO:
Abstracción,
Encapsulación/encapsulamiento,
Modularidad,
Herencia y
Polimorfismo.
Cuando se dice básicas, no es sólo porque sean las fundamentales, sino porque hay más que se derivan de
las básicas, por ejemplo, la genericidad, la reutilización y la ocultación. Incluso dentro de las explicaciones
se irán intercalando cinco principios que deben tenerse en cuenta siempre y que fueron denominados por
Michael Feathers con el acrónimo SOLID (Single Responsibility, Open/Closed, Liskov substitution, Interface
segregation y Dependency inversion). Empecemos:
Abstracción
Es un principio fundamental del modelado y consiste en tener en cuenta las propiedades y el
comportamiento apropiados de un objeto en un contexto concreto y utilizando distintos niveles de
comprensión que normalmente van de lo general a lo particular. Para dar un ejemplo, digamos que una
persona tiene características como: número de identificación, nombre, estatura, estudios realizados, tipo
de sangre, raza, dirección de residencia, hábitos alimenticios, etc. Podríamos llenar libros enteros
intentando listar todas las características, físicas, químicas, biológicas, fisiológicas, comportamentales,
etc., de una persona y sería imposible terminarlas. La abstracción lo que le dice en últimas al analista es
“céntrese en intentar definir ‘todos’ los atributos y en el comportamiento de esa persona, pero teniendo
en cuenta el contexto para el cual está intentando modelar una clase Persona”. Así los atributos que se
requieren se verán enormemente acotados.
Clase Persona
identificación
nombreCompleto
Atributos
direccionesDeEntrega
telefonos
actualizarDatosBasicos
agregarDireccion
actualizarDireccion
Funcionalidad/Comportamiento eliminarDireccion
agregarTelefono
actualizarTelefono
eliminarTelefono
Ahora realice el mismo ejercicio de modelar la clase Persona, pero para una historia clínica. Cuando
termine de hacerlo deberá quedarle claro que, en programación orientada a objetos, la realidad que se
modele es una simplificación de la compleja realidad y que dicha simplificación depende del problema y
de la capacidad de “filtrar” sólo aquellas clases, características y funcionalidades que realmente se
requiere tener en cuenta para el problema en curso.
A este nivel entonces podemos decir que necesitamos llevar a cabo tres tipos de abstracción, en lo posible,
en el orden que se expone a continuación:
Como es imposible modelar correctamente una clase si se desconoce el contexto o el problema donde
será utilizada, hay que tener en cuenta, ante todo el análisis, dado que este pone énfasis en la exploración
del problema y en los requisitos para obtener la solución. Según Craig Larman, “La finalidad del análisis
orientado a objetos es crear una descripción del dominio del problema desde la perspectiva de la
clasificación de objetos”26, o sea desde la perspectiva de las clases que lo conforman.
Entendido el problema se puede pasar al diseño, que “pone énfasis en una solución conceptual que
satisface los requisitos, en vez de ponerlo en la implementación”.
Se sugiere tener en cuenta el siguiente método a la hora de hacer abstracción sobre el problema:
1. Para la abstracción de clases identifique los sustantivos, los nombres comunes, los nombres
propios o pronombres relevantes en la descripción del problema o de los casos de estudio
planteados y considérelos como clases conceptuales o atributos candidatos.
26
Las técnicas descritas en el apartado “Abstracción” son tomadas de “UML y patrones: introducción al análisis y
diseño orientado a objetos”, de Craig Larman. Es un clásico escrito en 1.999 que no pierde vigencia por las
excelentes técnicas que presenta, de las cuales aquí se referencia una mínima parte.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 164/191
2. Utilice la lista de categorías de clases conceptuales confeccionada por Larman27, para identificar
los sustantivos y considérelos también como clases conceptuales o atributos candidatos.
4. Agregue las asociaciones que considere se deban mantener en memoria (ver más adelante
asociaciones de composición y de agregación).
5. Incorpore, en una segunda versión, los atributos necesarios para satisfacer los requisitos de datos
que es necesario recibir, procesar y proporcionar.
También a la hora de definir métodos deben tenerse en cuenta las condiciones que garantizan la
correcta ejecución del método (precondiciones) y el estado de los objetos luego de la ejecución
del método. Es muy probable que al encontrar precondiciones se complementen los métodos o
atributos necesarios.
Con los primeros cuatro pasos, obtendrá una primera versión del modelo, similar al que se muestra
enseguida para un subsistema de asignación de vuelos de aerolíneas28:
En el último paso se llena el segundo compartimento de los rectángulos que representan las clases
conceptuales.
27
Para consulta en el libro citado de dicho autor.
28
Tomado de: http://www.sparxsystems.com.ar/download/ayuda/index.html?domain_model_pattern.htm
En esta etapa no interesa la cardinalidad, ese aspecto representado por números y asteriscos (*) que aparecen en
las líneas que se utilizan para representar la asociación entre las clases.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 165/191
Para cada una de las etapas, Larman recomienda:
Utilizar los nombres existentes en el caso de estudio, problema planteado o contexto analizado.
Por ejemplo, si la línea aérea llama a los aviones, Aviones, defínalo así, no los llame Naves. Si llama
a las personas del equipo de trabajo, empleados, no los llame Personas, o algo por el estilo, sino
Empleados.
No añada cosas que no estén planteadas en el problema. Por ejemplo, si en el minucioso análisis
realizado de este subsistema no aparece el concepto hangar, entonces no lo agregue.
Si en el análisis del problema se encuentra con la duda sobre si algo es una clase conceptual o un
atributo esta duda se aclara fácilmente: si ese algo tiene más de un dato relevante, es una clase
conceptual. Al hecho añada, si dicha clase es necesario modelarla. En caso de duda, asuma que es
una clase conceptual y siga adelante. Por ejemplo, inicialmente pudiera pensar que la aerolínea es
un simple dato de tipo String y que no es una clase, pregúntese entonces si dentro del problema
que se está modelando es necesario conocer más que el nombre de la aerolínea y si esto es así,
entonces es una clase conceptual, si es un simple dato, en la segunda versión del modelo, pasará
a formar parte de la lista de atributos de alguna clase conceptual.
Volviendo al paso 4, ¿cuáles son las asociaciones que merece la pena registrar?, para responder a la
pregunta, tenga en cuenta otra vez lo dicho por Larman:
Evite representar como atributos, conceptos del dominio complejos; mejor utilice asociaciones.
Caso de estudio: se requiere un pequeño módulo de sistema académico que permita a los docentes
de una institución educativa registrar las notas de las asignaturas que imparten a diversos grupos
de estudiantes, teniendo en cuenta que cada asignatura tiene como restricción un número
determinado de notas parciales con unos porcentajes definidos.
3. Elabore una tercera versión del modelo, conservando la segunda, donde se incorporen las
asociaciones entre las clases conceptuales.
4. Elabore una cuarta versión del modelo, conservando la tercera, donde se incorporen los métodos
de las clases, distintos a accesores, mutadores, constructor por defecto, equals y toString.
Modularidad
La modularidad es una propiedad de los sistemas de ser estudiados, observados y analizados como la
interacción de varias partes o módulos que llevan a cabo acciones muy específicas para alcanzar un
objetivo común. Un módulo debe cumplir con las condiciones de caja negra, esto quiere decir que para
acoplarlo al resto del sistema no debe requerir conocer como está construido internamente, sino que debe
proporcionar entradas y salidas debidamente documentadas. El ejemplo más claro de esto son las clases
de objetos swing que ha utilizado hasta ahora y las demás clases del lenguaje Java que ha necesitado. Si
lo piensa ahora, en ningún momento necesitó conocer cómo están implementados los métodos split o
toUpperCase de la clase String para poderlos utilizar dividiendo cadenas o convirtiéndolas a mayúsculas y
tampoco fue necesario conocer como están codificados los JButtons o los JComboBox, simplemente ellos
se comportan como cajas negras, como piezas que encajan en cualquier sistema que requiera una GUI.
Las clases bien diseñadas cumplen con las características denominadas modularidad y ocultamiento de
información porque representa un único concepto del mundo real, ocultan detalles de implementación y
sólo definen como públicos algunos métodos. También los paquetes pueden considerarse módulos y
algunas veces hasta los métodos.
Un detalle interesante es que, si se tiene especial cuidado en el método descrito para abstraer lo esencial
de los sistemas, necesariamente la modularidad se obtendrá por añadidura.
Una técnica que ayuda a obtener la modularidad es intentar la alta cohesión en la funcionalidad de las
clases y el bajo acoplamiento entre éstas. ¿Cómo se logra esto?
La alta cohesión se logra cuando usted consigue diseñar clases que cumplen con responsabilidades
concretas, específicas. Continuando con el ejemplo de la aerolínea, una clase debe encargarse de registrar
la información de vuelos y otra clase debe encargarse de registrar la información de aviones. Sería erróneo
diseñar para que una sola clase encargara de ambas responsabilidades.
El bajo acoplamiento es una consecuencia de la alta cohesión una clase con una única responsabilidad o
unas pocas, se acoplará o asociará a pocas clases y una clase con baja cohesión intentará hacer de todo y
A simple vista y sin conocer mucho de diseño orientado a objetos se puede ver el enorme acoplamiento
que tiene la clase Reserva y el bajo acoplamiento de la clase TipoHabitacion. Por consiguiente, Reserva
tendrá escasa cohesión e intentará hacer de todo, mientras que TipoHabitacion se encargará simplemente
de proporcionar el precio de la habitación según su tipo.
Encapsulación
La encapsulación, también conocida como ocultamiento de información, consiste en ocultar los atributos
y funcionalidades entre instancias de clase, sencillamente porque no deben ser expuestos y en el caso
específico de los atributos porque se quiere evitar el acceso a datos por cualquier otro medio distinto a los
accesores. Por lo tanto, la encapsulación garantiza la integridad de los datos que contiene un objeto y
además proporciona los niveles de acceso ya documentados:
Público (+): se puede acceder sin restricciones a los atributos o métodos de una clase que se
definen con el nivel de acceso público. Cuando en UML se antepone el signo más (+) a un método
o un atributo, se indica con ello que es público.
Protegido (#): el acceso a los atributos o métodos está restringido a las clases que se derivan o que
heredan. Cuando en UML se antepone el signo (#) a un método o un atributo, se indica con ello
que es protegido.
Privado (-): el acceso a los atributos está restringido a la clase en donde éstos han sido definidos.
RUT 21545568878
CONFECCIONES EL TELAR E. U. FACTURA
Calle Real N° 10-45, Pereira Risaralda N° 001-0000765
Subtotal 1975.000
Empacador: 1725 – Julio Martínez IVA (18%) 355.500
CANCELADA SI: _X_ NO: ___ Total 2.330.500
De la figura anterior se puede decir que representa una Factura de Venta emitida a una Clienta; como esta
factura, se generan muchas en distintos contextos de Ventas. Es de resaltar que, según la información, la
empresa de confecciones hace Envíos gratis a los Clientes, Envíos que son responsabilidad de un
Empacador interno y de una Empresa Transportadora externa. También se puede notar que para esta
Factura de Venta sólo se han adicionado tres Líneas de Venta, cada Línea de Venta especifica la cantidad,
el Producto, el precio unitario y el total de dicha línea. Confecciones “El Telar”, desea sistematizar sus
Ventas de tal manera que las Facturas que elabore el sistema, no queden restringidas a 7 Líneas de Venta,
sino que se puedan adicionar tantas Líneas como sean necesarias.
Como se puede ver, tanto la representación de la factura como el caso de estudio que especifica la misma,
es autodescriptiva a la hora de encontrar las clases conceptuales según lo ya dicho: “identifique los
sustantivos, es decir, los nombres comunes, los nombres propios o pronombres en la descripción de los
casos de estudio planteados y considérelos como clases conceptuales o atributos candidatos”. Por lo tanto,
se tiene el siguiente listado de clases conceptuales:
Se destaca que se han privilegiado los sustantivos en singular para aquellos casos en que aparece tanto el
singular como el plural. Pero surge una duda: ¿realmente se requiere para este caso de estudio, la clase
conceptual “Envío”? – Puesto que sólo se necesita conocer el código del empacador, su nombre, la
empresa transportadora y el número de guía, la respuesta es no, dado que estos datos los proporcionan
las clases conceptuales “Empacador” y “Transportadora”. Si el caso de estudio indicara que de los envíos
es necesario conocer otros datos como fecha de envío y fecha de entrega, la respuesta sería “Sí”. Con estas
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 169/191
aclaraciones, veamos un primer acercamiento al modelo conceptual que se refinará hasta convertirse en
un modelo de clases:
Esta primera versión del modelo conceptual sintetiza y aclara enormemente lo que se trató de explicar
textualmente en el caso de estudio. Observe cómo puede leerse:
Para la segunda versión, se tiene en cuenta que hay que “incorporar los atributos para satisfacer los
requisitos de datos que es necesario recibir, procesar y proporcionar”. Así que se requiere volver a mirar
la representación de la factura y encontramos una larga lista: nombre del cliente, RUT del cliente, nombre
de la transportadora y número de guía emitido por ésta, …
Lo que hay que hacer entonces es integrar estos atributos a las clases correspondientes y encontraremos
que aparecerán unos “atributos” que son datos simples y otros que son referencias a otros objetos. Si por
ejemplo decimos que los “atributos” de una línea de venta son la cantidad de un producto determinado y
el producto en sí, entonces la cantidad es en realidad un atributo porque es un dato representado por un
único número entero, pero “producto” no es en realidad un atributo de la clase “línea de venta”. Se dice
entonces que las líneas de venta referencian a instancias de productos o tienen instancias asociadas. Esto
se puede comprobar con las siguientes dos líneas de código, la primera para crear una instancia de
producto y la segunda para crear una línea de venta, en donde se indica una cantidad de 20 jeans
referencia 4517. Como puede ver, el segundo argumento del constructor de líneas de venta, es una
referencia a una instancia de un producto y por lo tanto ya se conoce el precio unitario de cada producto
y se puede deducir el total de la línea de venta:
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 170/191
Producto producto = new Producto("Jean Referencia 4517", 35000);
En conclusión, cuando observe casos como el descrito, en donde surgen atributos escalares o simples y
además aparentes atributos de tipo objeto, éstos son en realidad asociaciones de las instancias de clase
con instancias de otros tipos. Ampliemos el concepto:
Asociaciones: de acuerdo a lo visto hasta aquí, las asociaciones son simplemente, conexiones entre
instancias de clase. Hay tres tipos de asociaciones, la composición, la agregación y la herencia. Por ahora
nos ocuparemos en entender la composición y la agregación y dejaremos para un apartado especial la
herencia:
import java.util.ArrayList;
public class Factura {
private Venta venta;
Agregación: cuando las instancias pueden ser compartidas entre varios objetos y los componentes
del objeto compuesto sobreviven a la destrucción de éste, se dice que la asociación es débil.
Para dar un ejemplo de agregación modifiquemos la clase Factura para que el método
generarVenta, reciba las referencias de las instancias que se deben asociar a la venta:
Ahora modifiquemos a MainVentas, de la forma que se indica en seguida y permitir así que el
método generarVenta reciba como argumentos, las instancias necesarias para crear la venta:
import java.util.ArrayList;
public class MainVentas {
public static void main(String[] args) {
Transportadora transportadora = new Transportadora();
Cliente c1 = new Cliente("122345", "Gloria Meza Artica", "Av. de los Comuneros Manizales");
Producto p1 = new Producto("Camisa casual hombre colección 2017", 45000);
Producto p2 = new Producto("Camisa hombre, tejido oriental", 50000);
Producto p3 = new Producto("Jean Referencia 4517 ", 35000);
En UML la composición se representa con un rombo relleno al lado del objeto compuesto y la agregación
con un rombo sin relleno. Ejemplo:
Tenga en cuenta que la agregación (asociación débil) y la composición (asociación fuerte) son conceptos
que debe dominar y por lo tanto ser capaz de descubrir, no sólo gráficamente sino en código. Más
importante aún es ser capaz de analizar cuando implementar una de las dos.
Ahora supongamos que se quiere probar que haciendo un llamado al método toString sobre un objeto de
tipo Venta, se puede generar por consola, algo así como esto:
Venta{
Confecciones Santana E. U.
Calle Real N° 10-45 Anserma Caldas
RUT 21545568878 - FACTURA N° 001-0000765
Anserma, 23-10-2017
Cliente: Gloria Meza Artica - RUT 122345
Dirección: Av. de los Comuneros Manizales
Transportadora: Servientrega – 87521436
Líneas de venta:
10 Camisa casual hombre colección 2017 45000 450000
20 Camisa hombre, tejido oriental 50000 1000000
15 Jean Referencia 4517 35000 525000
Subtotal $1975000,00
IVA (18%) $ 355500,00
Total $2330500,00
Empacador: 1725 - Julio Martínez
Cancelada=Si
}
Note que el diagrama no se atiborra de información irrelevante, como lo es llenar el tercer compartimento
de las clases con los tipos de constructores, accesores, mutadores y métodos toString; eso es algo que se
supone debe ir en todas las clases, por lo tanto, se omiten quedando sólo por incluir en el diseño, los
métodos que se resaltan con recuadros, los cuales, quien haya llegado hasta aquí, se supone que es capaz
de implementarlos a partir del diseño propuesto.
Herencia
La herencia permite la definición de una clase a partir de la definición de otra ya existente. De esta manera,
la clase ya existente, comparte automáticamente los atributos y métodos protegidos que posee, con la
clase creada a partir de ella.
Se habla entonces de superclases, como aquellas clases que permiten la definición de otras a partir de su
estructura y de subclases como aquellas creadas a partir de las superclases. Necesariamente esto lleva a
dos nuevos conceptos: la generalización y la especialización en donde si una subclase es una
especialización de una superclase, la superclase viene a ser una generalización y las subclases,
especializaciones de la superclase. En estos casos, las instancias de las subclases son también instancias
de las superclases que se benefician de atributos y métodos protegidos de su superclase. Ejemplo:
Note que en las asociaciones entre clases aparece la palabra “es” lo cual es una ayuda al momento de
definir la herencia. Es decir, si se pueden construir frases no forzadas como: un avión es un vehículo aéreo
o un avión es un vehículo, esto quiere decir que en el caso analizado es posible utilizar herencia, cosa que
Por ahora es suficiente con saber que para indicar en Java que una clase hereda de otra, se utiliza la palabra
reservada extends de la manera siguiente:
Clases abstractas: la herencia permite declarar clases en las que exista uno o muchos métodos no
implementados o abstractos; estas clases se consideran clases abstractas y también pueden contener
métodos no abstractos, es decir, implementados. La razón de los métodos abstractos es porque algún
comportamiento debe estar presente en todas las clases, pero se implementa de forma distinta para cada
una, como en el caso de la posibilidad de desplazarse para las clases derivadas de Vehículo.
Como se observa en la imagen anterior y en el código siguiente, la declaración de una clase o un método
como abstracto, utiliza la palabra reservada abstract:
@Override
Cuando una clase tiene al menos un método sin implementar, éste y la clase deben ser declarados
como abstractos.
No se pueden crear instancias a partir de una clase abstracta, aunque las clases abstractas sí
pueden tener constructores. Esto es así porque cuando se crea un objeto de una clase que hereda,
la primera llamada de su constructor hace una llamada al constructor de la clase "padre", lo que
permite que, aunque no se puedan crear instancias, si sea posible utilizar su constructor.
Una clase abstracta no puede ser "final".
Las clases que heredan de una clase abstracta, deberán sobrescribir e implementar todos los
métodos abstractos, de no ser así, dichas subclases también deben definirse como abstractas.
Una clase abstracta puede tener métodos no abstractos.
La combinación estático/abstracto es ilegal porque los métodos estáticos no se pueden redefinir.
Todo lo que se defina como protected en una superclase será heredado por las subclases.
Para hacer referencia a lo que se hereda, se utiliza la palabra reservada super.
Una subclase realiza sobreescritura de métodos de su superclase, cuando define un método con
la misma firma (nombre y argumentos iguales) que el método de la superclase. Las subclases
emplean la sobreescritura de métodos la mayoría de las veces para agregar o modificar la
funcionalidad del método heredado de la clase padre.
Cuando en una subclase se sobreescribe un método de la superclase se debe anteponer a la
signatura del método la anotación: @Override. No debe confundirse con la sobrecarga de
métodos que consiste en definir varios métodos con diferente firma.
Con base en estos tips, proceda a revisar los casos estudiados hasta ahora y defina para ellos la herencia
necesaria.
Polimorfismo
Se refiere a la propiedad por la que es posible enviar mensajes sintácticamente iguales a objetos de tipos
distintos. Veamos un ejemplo:
Se tiene la siguiente definición de objetos, a partir del ejemplo dado de aviación, suponiendo
que cada clase utilizada ha sobrescrito el método toString:
Se tiene un ArrayList de vehículos, al que se han agregado los objetos acabados de definir:
Como puede ver, la lista está compuesta por un conjunto de vehículos de distinto tipo, ya que son
instancias de subclases diferentes, pero tienen en común que todas ellas sobrescriben el método
toString de manera distinta. Cuando como en el caso, se llama a un método con el mismo nombre
para objetos de diferentes tipos, esta diferencia se traduce en comportamientos distintos, excepto
para los casos en que las clases no sobrescriben los métodos.
Con base en los conceptos geométricos descritos, se presenta en la figura de la página siguiente, un
modelo de clases que consta de dos clases abstractas, una interface y otras cuantas subclases. Implemente
el modelo de clases respectivo, teniendo en cuenta que debe haber completa correspondencia entre el
diseño y la implementación.
Recuerde que una interface es un contrato, por tanto, la interface Dibujable, simplemente se codifica de
la manera siguiente:
import java.awt.Graphics;
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
System.out.println("=================================================");
frm.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
// terminar la aplicación cuando se cierre la ventana
System.exit(0);
}
});
También puede ser de utilidad saber que el método dibujar2D para la clase Cuadrado se implementó así:
Si al ejecutar esta clase, no se presentan fallas tiene la garantía de haber implementado correctamente.
Por supuesto, tiene libertad para agregar los métodos que crea convenientes, por ejemplo, observe en la
siguiente figura a las subclases Circulo y Cuadrado, con algunos complementos:
Conversión de Tipos
En ocasiones es necesario convertir un String en un valor o en un dato booleano, por citar sólo dos casos.
Cuando esto se le ocurra, recuerde que Java cuenta con las funciones de conversión que se muestran en
las columnas 2 y 3 de la siguiente tabla y que convierten al tipo primitivo indicado en la columna 1:
La siguiente aplicación demuestra la captura de errores en una aplicación que requiere conversión de
tipos, cuando recibe los argumentos necesarios para realizar las operaciones básicas:
package control_otros;
if (args.length == 0) {
mensaje("\nNo se recibieron argumentos.");
} else if (args.length == 3) {
try {
char operador = args[1].charAt(0);
double v1 = Double.valueOf(args[0]);
double v2 = Double.parseDouble(args[2]);
Excepciones.operacion(v1, v2, operador);
} catch (Exception e) {
mensaje(e.toString());
}
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 183/191
} else {
mensaje("\nSe esperan exactamente 3 argumentos.");
}
}
Control de acceso
Los modificadores de acceso determinan la visibilidad de los atributos y métodos de las clases. Su utilidad
se puede ver en toda su dimensión en la programación orientada a objetos (POO), por ahora puede ser
suficiente con revisar la documentación existente en Internet30.
Secuencias de escape
Una secuencia de escape es un conjunto de caracteres que siempre empieza por barra invertida "\" y que
tiene un significado especial. Por ejemplo:
Secuencia Resultado
\n Nueva Línea
\t Tabulador
\r Retroceso de Carro
\f Comienzo de Página
\b Borrado a la Izquierda
\\ El carácter barra inversa ( \ )
\' El carácter comilla simple ( ' )
\" El carácter comilla doble ( " )
29
https://es.stackoverflow.com/questions/1487/guia-definitiva-de-conversi%C3%B3n-de-tipos-en-java
30
http://ayudasprogramacionweb.blogspot.com.co/2013/02/modificadores-acceso-public-protected-private-java.html
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 184/191
Especificadores de formato
Los especificadores de formato31 empiezan con un signo porcentual (%) y van seguidos de un carácter que
representa el tipo de datos. Entre el signo de porcentaje y el carácter que representa el tipo, pueden
incluirse formatos específicos32. Por ejemplo:
Métodos genéricos
Son aquellos métodos para los cuales el intérprete de Java (¿compilador?) determina los tipos de
parámetros que se pasan al método en tiempo de ejecución. Para dar un ejemplo, observe los diversos
tipos de argumentos que son enviados a la función hacerAlgo:
Sin importar el tipo de objetos que reciba, el siguiente método será capaz de determinar qué tipo de
elementos han sido ingresados:
private static <T> void hacerAlgo(T[] args) {
System.out.println("----- Inicio -----");
for (T obj : args) {
System.out.println("\tParámetro: " + obj);
System.out.println("\tTipo: " + obj.getClass());
}
System.out.println("----- Fin -----");
}
Tipos Enumerados
A partir de Java 5 se permite que a una variable se le asigne un valor restringido a un conjunto de valores
predefinidos, es decir, valores dentro de una lista enumerada.
El asunto es largo de explicar y no forma parte de los objetivos de estos talleres, sin embargo observe un
ejemplo en el que se ha creado el tipo enumerado lenguaje con unas constantes predefinidas que más
adelante permiten definir la variable tipoLenguaje de tipo lenguaje y asignarle como valor, uno de los tipos
predefinidos.
31
https://misapuntesdeprogramacion.wordpress.com/2013/01/30/uso-de-system-out-printf-y-system-out-format/
32
https://docs.oracle.com/javase/tutorial/java/data/numberformat.html
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 185/191
lenguaje tipoLenguaje = lenguaje.JAVA;
En Internet existe abundante documentación sobre el tema, una de ellas es la del blog de Leonardo de
Seta33, que brinda una aproximación avanzada a los mismos.
Las anotaciones son metadatos, información adicional sobre el código fuente. En el blog de Ramón
Invarato34 se proporciona una excelente documentación sobre el tema
Otras recomendaciones
33
https://dosideas.com/noticias/java/958-ime-encantan-los-enum-de-java
34
https://jarroba.com/annotations-anotaciones-en-java/
35
https://docs.google.com/document/d/1g42zjLufNdb5tU7kkBS3g3Q8FjKgOVm8d3HOj5xADkk/edit?usp=sharing
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 186/191
Anexo 1.
Existe un excelente trabajo realizado por los profesores Francisco Javier Pinales Delgado y César Eduardo
Velázquez Amador, titulado “Algoritmos resueltos con Diagramas de Flujo y Pseudocódigo”. El libro
describe didácticamente la manera de resolver problemas de cómputo utilizando diversas herramientas
para apoyar el proceso de análisis y diseño de algoritmos básicos. De la página 28 de dicho libro, se toma
el siguiente enunciado con la idea de mostrar la manera como puede utilizar el libro para entender los
planteamientos propuestos y luego codificar en Java las aplicaciones resultantes:
"Se desea implementar un algoritmo para obtener la suma de dos números cualesquiera. Se debe
partir de que para poder obtener la suma es necesario contar con dos números, pues el proceso
que debemos realizar es precisamente la suma de éstos, la cual se asigna a una variable que se
reporta como resultado del proceso."
Luego del planteamiento, los autores presentan el algoritmo y el diagrama de flujo respectivos:
Todo lo anterior para recomendar traducir a Java los algoritmos resueltos y los planteados en el libro
citado, sólo después de haber leído y comprendido lo expuesto por los autores.