Вы находитесь на странице: 1из 191

FUNDAMENTOS DE PROGRAMACIÓN

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.

Práctica 1 – Instalación del JDK


Esta práctica tiene como fin conocer algunos aspectos esenciales de los entornos de desarrollo, en
particular Java. Se espera que al final de la misma:

 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.

Se sugiere llevar a cabo, de forma secuencial, las siguientes instrucciones:

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:

3. En alguna parte de la instalación se le pide que seleccione características adicionales de instalación


para los elementos “Development Tools”, “Source code” y “Public JRE”. La figura siguiente muestra
resaltado, que para cada una de las características y sub-características, éstas se instalen en el disco
duro.

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.

Práctica 2 – Configuración de las variables de entorno


Las variables de entorno son valores que se pueden cambiar y que se definen en los sistemas operativos
para ser utilizados por distintos procesos o aplicaciones, en Windows, una de ellas es PATH, a la que
pueden ser asignadas varias rutas o carpetas, separadas por punto y coma. Estas rutas, normalmente
señalan dónde encontrar aplicaciones o carpetas de trabajo usadas por programas.

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”.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 3/191


3. Tal como se resalta en la figura siguiente, deberá agregar una nueva entrada para indicar la ruta donde
quedaron instaladas las aplicaciones del JDK.

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:

Abrimos la consola de Windows (cmd) y en ella ingresamos la instrucción javac

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.

Práctica 3 – Manejo básico de datos


Los datos son los componentes esenciales de la información, por ejemplo, si usted requiere información
básica de personas, se pueden solicitar datos como número de identidad, nombre, correo, etc.

Así, un dato tiene tres componentes básicos, el identificador, el tipo y el valor. Veamos un posible ejemplo
de datos de una persona:

Identificador Tipo Valor


credencial Texto 52710695
nombre Texto Carlos Cuesta Iglesias
horasTrabajadas Número entero 20
activo lógico Si

Java plantea las siguientes restricciones a la hora de definir identificadores:

 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;

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 6/191


Cuando a los datos se les va a asignar un valor una única vez, deben definirse como constantes y cuando
los datos pueden ser cambiados durante la ejecución de la aplicación, se dice que son variables. En
conclusión, las definiciones: credencial, nombre, horasTrabajadas y activo pueden tomarse como variables
según la sintaxis utilizada y por lo tanto se puede cambiar su valor. Ejemplo:
credencial = "123456789";
nombre = "Gonzalo González de la Gonzalera";
horasTrabajadas = 25;
activo = false;

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:

final double E = 2.718281828459045;

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:

Operador Uso Significado


+= operando1 += operando2 operando1 = operando1 + operando2
-= operando1 -= operando2 operando1 = operando1 - operando2
*= operando1 *= operando2 operando1 = operando1 * operando2
/= operando1 /= operando2 operando1 = operando1 / operando2
%= operando1 %= operando2 operando1 = operando1 % operando2

También existen los siguientes operadores aritméticos unarios, es decir que se usan con un solo operando:

Operador Significado Ejemplo


+ indica un valor positivo +20
- Indica un valor negativo, o cambia el signo algebraico -20
++ suma 1 al operando, como sufijo o prefijo operando++ ++operando
-- resta 1 al operando, como sufijo o prefijo operando-- --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:

Operador Significado Descripción


&& Conjunción Devuelve true si ambos operandos son true.
|| Disyunción Devuelve true si alguno de los operandos es true.
! Negación Niega el operando que se le pasa.
& Conjunción Devuelve true si ambos operandos son true, evaluándolos ambos.
| Disyunción Devuelve true si uno de los operandos es true, evaluándolos ambos.
?: Implicación Conocido como operador ternario u operador condicional. Se utiliza
mediante la forma r = (condición) ? v1 : v2; donde a la variable r se le
asignará v1 si la condición es true o v2 si la condición es false.

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.

1. De acuerdo a la precedencia de operadores descritos, verifique si los resultados resaltados en las


asignaciones de la izquierda, corresponden a las operaciones que se realizan en la parte derecha
de las expresiones:

14 = 4 + 2 * 5 18.2 = --d + 23.0 * 2 / 5


9.2 = 23.0 * 2 / 5 23 = 3 + 5 * (10 - (2 + 4))
23 = 3 + 5 * (10 - (2 + 4)) 16.09 = ++d + 3.5 + 5.09 - 14.0 / 4
5.09 = 3.5 + 5.09 - 14.0 / 4 72.45 = 2.1 * (1.5 + 3.0 * ++d)
28.98 = 2.1 * (1.5 + 3.0 * 4.1) 9 = --d + 23.0 * (2 / 5)

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++

19.2 = d++ + 23.0 * 2 / 5

-17 = 3 + 5 * (10 - (2 + b--))

15.09 = d++ + 3.5 + 5.09 - 14.0 / 4

66.15 = 2.1 * (1.5 + 3.0 * d++)

-98 es el resultado de la siguiente expresión: d += (a + b - c * d)

3. Observe la evaluación realizada a la siguiente expresión lógica:

De manera similar evalúe el resultado true o false de las siguientes expresiones:


a. ((a >= b) || (a < d)) && ((a >= d) && (c > d))
b. ! (a == c) && (c > b)
c. (a * b) != c
Importante: tenga en cuenta que no se aceptan expresiones como a < b < c, por lo tanto,
deben escribirse de la forma a < b && b < c.
4. Enseguida se presentan algunos ejemplos de cómo convertir expresiones aritméticas en
expresiones algorítmicas. En los casos mostrados se tiene en cuenta que Java no tiene operador
que permita elevar un número a un exponente dado, pero si tiene una biblioteca de funciones
matemáticas, la clase Math, donde está definida la función pow que eleva el valor dado como
primer argumento a la potencia dada como segundo argumento.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 9/191
Expresión aritmética Expresión algorítmica

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 10/191


5. Evalúe las siguientes expresiones e indique el resultado obtenido:

a. (a + b * --c != 154) ? Math.pow(10, 2) : Math.pow(25, 1.0/2);

b. (a + ((a + ((a + b) / (v + d))) / (a + (a / b))) != 15) ? (a * 50 % 4) : (a * 50 / 4). Se recomienda


resolver de la manera que se mostró en el punto 3, es decir, paso a paso.

c. Para m = 10, n = 6, p = 2, resuelva ((m + n) / (p - 3)) < (m + (n / (p - 4))). Se recomienda


resolver de la manera que se mostró en el punto 3, es decir, paso a paso.

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.

Práctica 4 – Configuración del entorno de trabajo y edición de archivos fuente


1. Cree una carpeta para sus prácticas, en lo posible siguiendo las siguientes recomendaciones:
 Preferiblemente en la raíz del disco duro o en la raíz de un dispositivo portable (USB o disco).
 No utilice nombres con espacios.

En el caso de estos ejemplos se va a trabajar en la unidad K, carpeta fundamentos, subcarpeta parte1:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 11/191


Nombre de archivo: Demo001.java

Contenido del archivo:


1 package parte1;
2
3 import java.util.Scanner;
4
5 public class Demo001 {
6
7 public static void main(String[] args) {
8 String nombres, apellidos, nombreCompleto;
9
10 Scanner in = new Scanner(System.in);
11
12 System.out.println("Ingrese nombre: ");
13 nombres = in.nextLine();
14
15 System.out.println("Ingrese apellido: ");
16 apellidos = in.nextLine();
17
18 nombreCompleto = nombres + " " + apellidos;
19
20 System.out.println("---- resultados del proceso -------");
21 System.out.println("Nombre completo: " + nombreCompleto);
22
23 }
24
25 }

Nombre de archivo: Demo002.java

Contenido del archivo:


1 package parte1;
2
3 import java.util.Scanner;
4
5 public class Demo002 {
6
7 public static void main(String[] args) {
8

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 12/191


9 Scanner in = new Scanner(System.in);
10
11 int a;
12 float b, c;
13
14 System.out.println("Ingrese un valor entero: ");
15 a = in.nextInt();
16
17 System.out.println("Ingrese un valor real: ");
18 b = in.nextFloat(); // separador de decimales, coma o punto según configuración
19
20 c = a + b;
21
22 System.out.println("Resultado: " + c);
23
24 }
25 }

Nombre de archivo: Demo003.java

Contenido del archivo:


1 package parte1;
2
3 import java.util.Scanner;
4
5 public class Demo003 {
6
7 public static void main(String[] args) {
8
9 Scanner in = new Scanner(System.in);
10
11 // calculo del área de un círculo
12 int radio;
13 double area;
14
15 System.out.println("Ingrese radio del círculo: ");
16 radio = in.nextInt();
17
18 area = Math.PI * Math.pow(radio, 2);
19
20 System.out.println("El área del círculo es: " + area);
21
22 }
23
24 }

Nombre de archivo: Demo004.java

Contenido del archivo:


1 package parte1;
2
3 import java.util.Scanner;
4
5 public class Demo004 {
6

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 13/191


7 public static void main(String[] args) {
8
9 Scanner in = new Scanner(System.in);
10
11 // calculo del área de potencias y raices
12 int x;
13 double resultado;
14 boolean prueba;
15
16 System.out.println("Ingrese un valor: ");
17 x = in.nextInt();
18
19 resultado = Math.pow(x, 2);
20 System.out.println(resultado + " = " + x + " ^ 2");
21
22 resultado = Math.pow(x, 0.5);
23 System.out.println("Raíz cuadrada de " + x + " es " + resultado);
24
25 resultado = Math.pow(x, 1.0 / 2); // qué pasa si utilizo 1 sin decimales?
26 System.out.println("Raíz cuadrada de " + x + " es " + resultado);
27
28 prueba = !(resultado >= 0);
29 System.out.println("En prueba quedó asignado: " + prueba);
30
31 }
32 }

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:

 CD.. (Se devuelve un nivel en la estructura de carpetas (estructura de directorios)


 CD\ (Se sale de todas las carpetas y regresa a la raíz del dispositivo en uso)
 CD nombreCarpeta (se posiciona dentro de la carpeta indicada)
 CD nombreCarpeta\nombreSubcarpeta (se posiciona dentro de la subcarpeta indicada)
 DIR (muestra el contenido de una carpeta)

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.

Tenga en cuenta estos datos importantes:

 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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 15/191


Práctica 5 – Compilación y ejecución de programas
Siga los pasos de esta práctica para verificar que al compilar código Java, utilizando la instrucción JAVAC
(Java Compile), se crea un nuevo archivo con el mismo nombre del archivo fuente, pero con la extensión
CLASS. En el ejemplo de la figura siguiente:

 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.

Práctica 6 – Estructura de control secuencial


Hasta ahora se ha hecho uso de la estructura más sencilla de programación, la estructura secuencial, para
entender el entorno de desarrollo de Java. Este tipo de estructura se caracteriza por tener instrucciones
como las que muestra la figura siguiente, sin bifurcaciones y sin repeticiones, sólo es un conjunto de
instrucciones que se ejecuta en orden estricto de arriba abajo, desde la primera línea de código hasta la
última.

Inicio { // Inicio del bloque7 de instrucciones

Instrucción 1 Scanner in = new Scanner(System.in);


Instrucción 2
double celsius, kelvin;
.
. System.out.println("Grados celsius: ");
. celsius = in.nextInt();
.
kelvin = celsius + 273.15;
. System.out.println(celsius +
. " grados Celsius equivalen a " +
. kelvin + " Kelvin");
Instrucción N } // Fin del bloque de instrucciones
Fin

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:

Datos de Entrada Cálculos necesarios Datos de salida


int q int diaSemana: o sea…

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.

3. Leer el peso de un hombre en libras y devolver su peso en kilogramos y gramos.

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;

System.out.println("i = " + i + ", j = " + j + ", k = " + k);

System.out.println("i < j => " + (i < j));


System.out.println("(i + j) >= k => " + ((i + j) >= k));
System.out.println("(j + k) > (i + 5) => " + ((j + k) > (i + 5)));
System.out.println("k != 3 => " + (k != 3));
System.out.println("j == 2 => " + (j == 2));

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

f>5 (c != 'p') || ((i + f) <= 100)

(i + f) <= 10 !(f > 5)

c == 119 !(i <= 3)

c != 'p' !(i > (f + 1))

c >= 10 * (i + f) i + f <= 10

(i >= 6) && (c == 'w') i >= 6 && c == 'w'

(i >= 6) || (c == 119) c != 'p' || i + f <= 10

(f < 11) && (i > 100) ++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;

System.out.println("i = " + i + ", j = " + j + ", f = " + f + ", g = " + g);

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.

Práctica 7 – Estructuras de control condicional


Las estructuras condicionales permiten decidir entre alternativas. La más simple de ellas, verifica si una
condición se cumple y si se cumple lleva a cabo las instrucciones correspondientes a la parte verdadera de
la condición.

En la figura siguiente, se muestra el diagrama de flujo y la sintaxis utilizada en Java, para implementar el
tipo de condición descrita.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 18/191


if (condición) {

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.

Categoría Salario Mensual Fondo solidaridad Aux. de transporte


AoB 1000000 1% 8.5%
C 1500000 1.1% 7.5%
D 2000000 1.2% 6.5%
E 2500000 1.3% 5.5%
F 3000000 1.4% No aplica
Otras 3500000 1.5% No aplica

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;

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 22/191


29 fondoSolidaridad = salarioNeto * 0.01;
30 transporte = 1500000 * 0.085;
31 } else if (categoria == 'C') {
32 vrHora = 1500000 / 192;
33 salarioBase = (1500000 / 30.0) * diasTrabajados;
34 pagoExtras = horasExtras * vrHora;
35 salarioNeto = salarioBase + pagoExtras;
36 eps_Pension = salarioNeto * EPS_PENSION;
37 fondoSolidaridad = salarioNeto * 0.011;
38 transporte = 1500000 * 0.075;
39 } else if (categoria == 'D') {
40 vrHora = 2000000 / 192;
41 salarioBase = (2000000 / 30.0) * diasTrabajados;
42 pagoExtras = horasExtras * vrHora;
43 salarioNeto = salarioBase + pagoExtras;
44 eps_Pension = salarioNeto * EPS_PENSION;
45 fondoSolidaridad = salarioNeto * 0.012;
46 transporte = 2000000 * 0.065;
47 } else if (categoria == 'E') {
48 vrHora = 2500000 / 192;
49 salarioBase = (2500000 / 30.0) * diasTrabajados;
50 pagoExtras = horasExtras * vrHora;
51 salarioNeto = salarioBase + pagoExtras;
52 eps_Pension = salarioNeto * EPS_PENSION;
53 fondoSolidaridad = salarioNeto * 0.013;
54 transporte = 2500000 * 0.055;
55 } else if (categoria == 'F') {
56 vrHora = 3000000 / 192;
57 salarioBase = (3000000 / 30.0) * diasTrabajados;
58 pagoExtras = horasExtras * vrHora;
59 salarioNeto = salarioBase + pagoExtras;
60 eps_Pension = salarioNeto * EPS_PENSION;
61 fondoSolidaridad = salarioNeto * 0.014;
62 transporte = 0;
63 } else {
64 vrHora = 3500000 / 192;
65 salarioBase = (3500000 / 30.0) * diasTrabajados;
66 pagoExtras = horasExtras * vrHora;
67 salarioNeto = salarioBase + pagoExtras;
68 eps_Pension = salarioNeto * EPS_PENSION;
69 fondoSolidaridad = salarioNeto * 0.015;
70 transporte = 0;
71 }
72 salarioNeto = salarioNeto - fondoSolidaridad - eps_Pension + transporte;
73
74 System.out.println("Salario base : " + salarioBase);
75 System.out.println("Pago por horas extras: " + pagoExtras);
76 System.out.println("Fondo de solidaridad : " + fondoSolidaridad);
77 System.out.println("Auxilio de transporte: " + transporte);
78 System.out.println("Aportes EPS y Pensión: " + eps_Pension);
79 System.out.println("Salario neto : " + salarioNeto);
80 }
81 }

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 23/191


Uno de los tantos ejemplos que puede darse de estructuras anidadas, es leer cuatro números y hallar el
menor de los cuatro.
1 package condicion;
2
3 import java.util.Scanner;
4
5 public class If001 {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9 // Leer cuatro números y, a continuación, escribir el menor de los cuatro
10 int a, b, c, d, menor;
11 System.out.println("Introduzca un valor para guardarlo en A: ");
12 a = in.nextInt();
13
14 System.out.println("Introduzca un valor para guardarlo en B: ");
15 b = in.nextInt();
16
17 System.out.println("Introduzca un valor para guardarlo en C: ");
18 c = in.nextInt();
19
20 System.out.println("Introduzca un valor para guardarlo en D: ");
21 d = in.nextInt();
22
23 if (a < b) {
24 if (a < c) {
25 if (a < d) {
26 menor = a;
27 } else {
28 menor = d;
29 }
30 } else if (c < d) {
31 menor = c;
32 } else {

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 24/191


33 menor = d;
34 }
35 } else if (b < c) {
36 if (b < d) {
37 menor = b;
38 } else {
39 menor = d;
40 }
41 } else if (c < d) {
42 menor = c;
43 } else {
44 menor = d;
45 }
46 System.out.println("El menor es: " + menor);
47 }
48 }

Estructura de control switch

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:

switch (expresión) { switch (expresión) {

case valor1: case valor1:


case valor2:
instrucciones;
case valor3:
break;
instrucciones;
break;
case valor2:
instrucciones; case valor4:
break; instrucciones;
break;
.
.
.
.
. .
default: default:
sentencias; sentencias;
break; break;
}
}

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 25/191


Tenga en cuenta que:

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.

1. Elabore el diagrama de flujo del ejemplo Caso001.

2. Elabore el diagrama de flujo para la siguiente aplicación:


1 package condicion;
2
3 import java.util.Scanner;
4
5 public class If003 {
6
7 public static void main(String[] args) {
8 // Leer dos caracteres y deducir si están en orden alfabético
9 Scanner in = new Scanner(System.in);
10 char c1, c2;
11
12 System.out.println("Ingrese un caracter: ");
13 c1 = in.next().charAt(0);
14
15 System.out.println("Ingrese otro caracter: ");
16 c2 = in.next().charAt(0);
17
18 if (c1 < c2) {
19 System.out.println(c1 + " y " + c2 + " están en orden");
20 } else if (c1 == c2) {
21 System.out.println(c1 + " y " + c2 + " son iguales");
22 } else {
23 System.out.println(c1 + " y " + c2 + "no están en orden");
24 }
25 }
26 }

3. Leer un caracter y deducir si está situado antes o después de "m".

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.

8. Determinar el precio de un tiquete de ida y de vuelta en ferrocarril, conociendo la distancia a


recorrer y sabiendo que si el número de días de estancia es superior a siete y la distancia superior
a 800 kilómetros el tiquete tiene una reducción del 30%. El precio por kilómetro es de 25 pesos.

9. Dados dos números decir si uno es divisible del otro.

10. Informar si un número dado está entre un valor A y un valor B.


Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 27/191
Práctica 8 – Estructuras de control repetitivas
Continuando con nuestro recorrido por las estructuras de control, llegamos ahora a las estructuras que
permiten repetir la ejecución de bloques de código. Java cuenta básicamente con tres estructuras de
repetición o formas de iterar o ciclos. Dos de estas estructuras son condicionadas al comienzo (while y for)
y uno condicionada al final (do...while). Enseguida se analizarán cada una de ellas.

Estructura de control while

La estructura de control while permite ejecutar sentencias o instrucciones mientras la condición de


iteración sea verdadera. Su formato general es el siguiente:

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:

1. Se divide el número mayor entre el menor.

2. Si:

a. La división es exacta, el divisor es el M.C.D.

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.

El algoritmo anterior implementado en Java, mediante while, queda de la siguiente manera:

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 }

Estructura de control do while

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 29/191


do {
instrucción(s);
} while (condicion);

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 }

Estructura de control for

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:

 La primera parte, inicio, especifica el o los valores iniciales.


 La segunda parte indica la condición de finalización para el ciclo, la cual está directamente
relacionada con el o los valores iniciales.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 30/191


 La última parte define cómo serán manipulados los valores de iteración del ciclo.
 Se pueden especificar un conjunto de valores para la parte inicial y para la parte que
controla la iteración.

for (inicio; condición de terminación; incremento/decremento por iteración)

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) {

for (int k = 1, j = 10; k < j; ++k, j--) {


System.out.println(k + " " + j);
}
}

Formas no convencionales de utilizar las estructuras de control de ciclos

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;

while (true) { // ciclo infinito


System.out.println(++k + " " + --j);

if (k >= j) {
break;
}
}

k = 0;
j = 11;

do {
System.out.println(++k + " " + --j);

if (k >= j) {
break;
}
} while (true);

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 32/191


Caso 3: se puede usar la instrucción continue para saltarse uno o varios pasos de un ciclo. En el siguiente
ejemplo se utiliza la instrucción continue para evitar la impresión del paso 5:
int numero = 8;

for (int i = 1; i <= 10; i++) {


if (i == 5) {
continue;
}

System.out.println(numero + " * " + i + " = " + numero * i);

Estructuras de control anidadas

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.

public static void main(String[] args) {

for (int i = 1; i < 10; i++) {


for (int j = 1; j < 10; j++) {
System.out.println(i + " * " + j + " = " + i * j);
}
System.out.println();
}
}

Práctica 9 – Lectura de archivos mediante la clase Scanner


En esta práctica se evitarán detalles técnicos que hacen parte de la programación orientada a objetos, del
manejo de archivos en Java y del manejo de errores, para centrarnos sobre un problema: leer datos de
archivos. Para ello considere la siguiente representación del contenido de un archivo:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 33/191


Hasta ahora ha utilizado la definición Scanner in = new Scanner(System.in); para permitir ingresar datos
por teclado. Resulta que Scanner permite leer el contenido de un archivo, mediante la siguiente variación,
hecha en la línea 10 de la aplicación ejemplo:
try (Scanner sc = new Scanner(new File("carpeta/nombreArchivo"))) {…}

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 35/191


Para recordar

 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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 36/191


8. Se tiene el archivo delimitado por puntos y comas, “profesionales_contratados.csv” y se tiene la
siguiente aplicación que permite conocer los registros de dicho archivo:

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

Según la figura siguiente, al ejecutar la aplicación anterior, se muestra la cédula, el nombre


completo y la profesión de cada una de las personas contenidas en el archivo. Todas estas personas
laboran por horas en el DEAM (Departamento de Estudios Agropecuarios de Macondo).

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 37/191


Su misión consiste en elaborar una única y nueva versión de la aplicación que permita
complementar la funcionalidad, según los siguientes requerimientos:

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.

Valor de Fondo de Auxilio de


PROFESIÓN10
la Hora Solidaridad Transporte
INGENIERÍA DE ALIMENTOS Y AFINES11 70000 10% No aplica
12
MÉDICO VETERINARIO Y AFINES 60000 9% 6.5%
BACTERIOLOGA, MICROBIOLOGO Y AFINES13 50000 8% 7.5%

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 38/191


Práctica 10 – Estructuras unidimensionales y multidimensionales
Las variables escalares son aquellas que representan datos simples o individuales de tamaño fijo como,
por ejemplo, los enteros, los reales y los caracteres y las variables suscritas representan estructuras o
arreglos de datos compuestos. En esta práctica nos ocuparemos del tipo de variables suscritas a las que
también se denomina arreglos de datos compuestos o arrays.

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:

 Declaración utilizando dos instrucciones separadas:

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];

 Declaración utilizando una sola instrucción:

tipo nombreArray[] = new tipo[tamaño];

El mismo ejemplo anterior pero ahora definido en una sola instrucción:

int 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:

 Asignar valores a un elemento del array:

edades[2] = 20;
edades[4] = 25;

20 25

0 1 2 3 4

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 39/191


 Recuperar un valor de un elemento del array:

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 40/191


La definición y creación del array en Java, quedaría así:
double[][] notas = new double[4][3];

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 }

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 41/191


Actividad complementaria
En esta actividad se incorpora la lógica algorítmica desarrollada hasta la actividad 9, a los nuevos conceptos
de la actividad 10 con el fin de afianzar la destreza en la solución de problemas computacionales que hacen
uso de conceptos básicos de vectores y matrices.

1. Complemente DemoArray01 para que permita conocer la menor y la mayor edad guardada en el
vector.

2. Complemente DemoArray02 para que muestre el promedio del grupo.

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.

5. Permita conocer el promedio obtenido por el grupo.

6. El siguiente ejemplo llena un vector con datos de un archivo según se documenta:


package arrays;

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 {

public static void main(String[] args) throws FileNotFoundException {

try (Scanner sc = new Scanner(new File("varios/aleatorios.csv"))) {


sc.useDelimiter(";");
int i = 0; // contador de valores positivos encontrados
int k = 1; // contador de columnas de cada fila del CSV
int valor; // actual valor que se lee del archivo
int vector[] = new int[10];

while (sc.hasNextLine()) {
valor = sc.nextInt();

// si valor es un entero positivo, almacenarlo en el array


if (valor > 0) {
vector[i] = valor;
i++;
// si se alcanza la última posición del vector, se interrumpe la lectura
if (i == vector.length) {
break;
}
} // fin del if que verifica el valor leído

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 42/191


// si se alcanza la última columna de una fila se pasa a la siguiente
k++;
if (k > 30) {
k = 1;
sc.nextLine();
} // fin del if que controla el salto de línea
} // fin del while

// mostrar el contenido del vector


for (i = 0; i < vector.length; i++) {
System.out.println("vector[" + i + "] = " + vector[i]);
}
} // fin de la función principal
}
}

Su misión consiste en:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 43/191


Práctica 11 – Funciones o Métodos
Una función o método es un conjunto de instrucciones que realizan un objetivo en particular y que se
ejecuta al ser llamado desde otra función o método. Una función puede llamarse múltiples veces e incluso
llamarse a sí misma de manera recurrente.

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”.

Forma general de una función

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;

public class NombreClase {

public static void main(String[] args) {

}
}

En otras palabras, la funcionalidad de las aplicaciones se ha implementado dentro de un bloque de


instrucciones llamado main delimitado por llaves “{…}”. A los bloques de código así definidos se les llama
funciones o métodos y cumplen siempre con la siguiente sintaxis Java:
<modificadores> <tipoRetorno> <nombreFunción>(<parámetros>) {
<declaraciones>
<instrucciones>
}

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 44/191


 Los modificadores determinan la accesibilidad o visibilidad de la función y el modo en que la
función puede ser utilizada.

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:

 double cuadrado = Math.pow(x, y);


La función pow fue definida en la clase Math de Java como:
public static double pow(double a, double b)
Se dice entonces que es un miembro de clase y por lo tanto se puede utilizar de la forma:
Clase.funcion(…)

 Scanner kb = new Scanner(System.in);


int valor = kb.nextInt();
La función nextInt fue definida en la clase Scanner como:
public int nextInt()

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 tipo de retorno establece qué puede retornar una función. Ejemplo:

 En la función public static double pow(double a, double b) se estableció que se retorna un


tipo double, de ahí que en el llamado: double cuadrado = Math.pow(x, y); se evidencia que
lo retornado por la función es asignado a una variable de tipo double.

 Cuando como en el caso de la función main, el tipo de retorno es void, la función no


retorna valor alguno.

 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:

 double cuadrado = Math.pow(x, y);

 int valor = kb.nextInt();

 System.out.println("bla bla bla");

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 45/191


 Los parámetros o argumentos son el valor, o el conjunto de valores u objetos que puede recibir
una función. Ejemplos:

 La función public static double pow(double a, double b); recibe dos argumentos o
parámetros.

 La función public void println([parámetro]); puede no recibir argumentos o recibir un


único argumento de tipo objeto o de cualquiera de los tipos de datos soportados por Java.
Por este hecho se dice que la función está sobrecargada.

 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:

public static void main(String[] args) {


if (args.length == 0) {
System.out.println("No se recibieron argumentos");
} else {

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 46/191


System.out.println("Argumentos recibidos:");
for (String arg : args) {
System.out.println(arg);
}
}
}

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.

Categoría Salario Mensual Fondo solidaridad Aux. de transporte


AoB 1000000 1% 8.5%
C 1500000 1.1% 7.5%
D 2000000 1.2% 6.5%
E 2500000 1.3% 5.5%
F 3000000 1.4% No aplica
Otras 3500000 1.5% No aplica

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 }

Del código fuente anterior, se resalta:

 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.

 Desde la línea 22 a la línea 34 se resalta el cambio con respecto a la versión presentada en el


ejemplo de la actividad 7, página 22. En esta versión todos los cálculos que estaban dentro de las
seis alternativas, fueron reemplazados por el llamado a la función calcularPago(…), la cual recibe
los argumentos necesarios para hacer los cálculos solicitados, según cada categoría.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 48/191
 La forma como se hace el llamado de la función en la línea 23 difiere de la forma en la que se hace
en las líneas 25, 27, 29, 31 y 33. Ambas formas son correctas y posibles cuando la función llamada
se encuentra definida en la misma clase de la función que hace el llamado. Cuando la función
estática ha sido definida en otra clase, necesariamente el llamado se hace como se indica en la
línea 23, es decir, utilizando la forma:

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;

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 49/191


13
14 System.out.print("Ingrese la categoría: ");
15 categoria = scanner.next().toLowerCase().charAt(0);
16
17 System.out.print("Ingrese los días trabajados: ");
18 diasTrabajados = scanner.nextInt();
19
20 System.out.print("Ingrese el número de horas extras: ");
21 horasExtras = scanner.nextInt();
22
23 decidirPago(categoria, diasTrabajados, horasExtras);
24 }
25
26 private static void decidirPago(char categoria, int dias, int horas) {
// implemente aquí la función que está siendo utilizada en la línea 23
40 }
41
42 /**
48 * los comentarios continúan igual
49 */
50 private static void calcularPago(int dias, int extras, double porcentajeFondo,
double porcentajeTransp) {
// la implementación de esta función no cambia
68 }
69 }

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 : ");

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 50/191


14 a = in.nextInt();
15
16 System.out.print("Segundo valor : ");
17 b = in.nextInt();
18
19 System.out.println("Operación (+, -, *, /, %): ");
20 operador = in.next().charAt(0);
21
22 System.out.println(a + " " + operador + " " + b + " = " + calcular(a, b, operador));
23 }
24
25 private static double calcular(int x, int y, char operacion) {
26 double resultado = Double.NaN; // se asigna Not As Number (NaN)
27
28 switch (operacion) {
29 case '+':
30 resultado = x + y;
31 break;
32 // implemente de manera similar los casos para '-', '*', '/' y '%'
// …
44 }
45 return resultado;
46 }
47 }

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:

 La función se usó en la línea 22 como si se tratase de un valor concatenado a las


subcadenas precedentes. Cuando una función se usa de esta manera o forma parte de una
expresión de asignación o de comparación, es porque dicha función retorna un valor.

 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.

3. Retomemos el algoritmo de Euclides, descrito en la página 29 para implementarlo mediante


funciones. Igual que en el punto anterior, se crea la función calcularMCD de forma que retorne el
MCD y se pueda utilizar como se muestra en las líneas 18 y 20 del siguiente código:

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 51/191


11 System.out.print("Primer valor : ");
12 valor1 = in.nextInt();
13
14 System.out.print("Segundo valor: ");
15 valor2 = in.nextInt();
16
17 mcd = calcularMCD(valor1, valor2);
18 System.out.println("El máximo común divisor es: " + mcd);
19 // o lo que es lo mismo:
20 System.out.println("El máximo común divisor es: " + calcularMCD(valor1, valor2));
21 }
22
23 private static int calcularMCD(int v1, int v2) {
24 int resto;
25
// …
// agregue aquí las instrucciones que hacen falta para que se retorne el MCD
// …
31 return v2;
32 }
33 }

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;

public class NombreClase {

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.

public|protected|private static void fx([argumentos]) {

 Los parámetros o argumentos de una función se comportan como variables


locales de la función en la que son definidos.

 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.

 Cuando la ejecución de la función termina, los parámetros por valor, las


variables y constantes locales son borrados de la memoria.

 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:

a. Descargue de aquí14 el código fuente del ejemplo (Ambito.java) que se muestra


enseguida y que además servirá para aclarar los puntos resaltados en la plantilla de clase.

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?

e. ¿Por qué el valor de “y” si se muestra alterado luego de ejecutar fx?

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?

5. Ejecute y analice el funcionamiento del prototipo de aplicación que se presenta a continuación.


Enseguida se solicitará que lo complemente, agregando algo de funcionalidad.
1 package funciones;
2
3 import java.util.Scanner;
4
5 public class Ejemplos {
6
7 public static void main(String[] args) {
8 Scanner in = new Scanner(System.in);
9
10 int v[] = {50, 12, 15, -7, 91, 72, 10};
11
12 int mA[][] = {
13 {13, 44, 87},
14 {50, 12, 15},
15 {30, -11, 18}
16 };

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 54/191


18 int mB[][] = {
19 {13, 55, 87},
20 {51, 12, 13},
21 {30, 33, 18}
22 };
23
24 int mS[][];
25
26 if (args.length > 0) { // si se envían argumentos en la llamada
27 switch (args[0]) {
28 case "1":
29 Ejemplos.listarVector(v);
30 break;
31
32 case "2":

140 case "100":
141 System.out.println("Opcion 100 sin implementar");
142 break;
143
144 default:
145 System.out.println("Error en la opción");
146 }
147 } else { // si no se envían argumentos en la llamada, indicar el uso correcto
14815 System.out.println("\nEjecute como se muestra enseguida:\n"
149 + "\tjava funciones.Ejemplos 1\n"
150 + "Así ejecutará la aplicación e ingresará al caso 1\n"
151 + "Puede cambiar el 1 por cualquier otro número de caso.");
152 }
153 }
… private static void listarVector(int v[]) {
… System.out.println("Falta implementar esta función");
… }
… }

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.

 En la línea 10 se define un array unidimensional (vector) para usarlo posteriormente en


pruebas.

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:

a. Reemplace la función listarVector por la siguiente versión y pruebe que efectivamente


lista los elementos del vector recibido como argumento en la línea 9.
private static void listarVector(int v[]) {
for (int i = 0; i < v.length; i++) {
System.out.println(v[i]);
}
}

b. Implemente el caso 2 como se muestra enseguida y compruebe los resultados:


case "2":
Ejemplos.listarVector(v);
double total = Ejemplos.sumaVector(v); // elvalorretornado se usa en la expresiónde asignación
System.out.println("Suma: " + total);
break;
Para que este caso funcione correctamente requiere que agregue la función suma Vector
inmediatamente antes o después de la función listarVector. Impleméntela como se
muestra enseguida, completando el código que falta, donde encuentre puntos
suspensivos:
private static double sumaVector(int vector[]) {
double suma = …
for (int i = 0; i < vector.length; i++) {
suma += …
}
return …
}
c. Implemente el caso 3 como se muestra enseguida y compruebe los resultados:

case "3":
Ejemplos.listarVector(v);
System.out.println("Promedio: " + Ejemplos.promedioVector(v));
break;

Implemente la nueva función como se muestra enseguida:


private static double promedioVector(int v[]) {
return Ejemplos.sumaVector(v) / v.length;
}
Tanto en el caso 2 como en el caso 3 se puede observar que las funciones cuyo tipo de
retorno es distinto de void retornan un dato o un objeto que puede ser utilizado como
parte de una expresión.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 56/191


El caso también muestra la posibilidad de reutilizar funciones y de dividir un problema
en subproblemas: observe que esta función no repite el proceso necesario de sumar los
elementos del vector, sino que la expresión que obtiene el promedio, llama a la función
que suma los elementos y divide por la cantidad de éstos.

d. El caso 4 queda como se muestra enseguida:


case "4":
Ejemplos.listarVector(v);
System.out.println("Mayor: " + Ejemplos.mayorDelVector(v));
break;

La implementación de la función respectiva, requiere que se complemente donde


encuentre puntos suspensivos:

private static int mayorDelVector(int v[]) {


int mayor = v[0]; // se supone que el mayor está en la primera posición
for (int i = 1; i < v.length; i++) {
// si el mayor actual es menor que el elemento de la posición i,
// asignar a la variable mayor, el elemento de la posición i

}
return …
}

e. Implemente el caso 5 como el 4 y permite conocer el menor elemento del vector.

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;

La implementación de la función burbuja es la siguiente:


static void burbuja(int arreglo[]) {
int tmp;
for (int i = 0; i < arreglo.length - 1; i++) {
for (int j = 0; j < arreglo.length - 1; j++) {
if (arreglo[j] < arreglo[j + 1]) {
tmp = arreglo[j + 1];
arreglo[j + 1] = arreglo[j];
arreglo[j] = tmp;
}
}
}
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 57/191


Se sugiere que luego de ver la ejecución del caso 7, elabore la comprobación manual de
lo que sucede con la ejecución de esta función y se documente sobre los distintos
métodos de ordenamiento.

h. Para el caso 8 implemente y pruebe como en “g” la función ordenarDeMenorAMayor.

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;

k. Para el caso 11 se implementa la función totalColumna, que como su nombre lo indica,


retorna la suma de los elementos de una columna, dada como segundo argumento de la
función. El primer argumento corresponde a la matriz de la cual se va a obtener la suma
de la columna. Si procede según lo esperado, el siguiente caso funcionará perfectamente:
case "11":
System.out.print("De qué columna quiere obtener el total (1..3: ");
int j = in.nextInt();
int suma = Ejemplos.totalColumna(mA, j - 1);
System.out.println("Suma de la columna [" + j + "] = " + suma);
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;

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 58/191


Y observe la implementación de la función totalesColumnas:

static void totalesColumnas(int[][] m) {


for (int j = 0; j < m[0].length; j++) {
int total = totalColumna(m, j);
System.out.println("Total columna [" + (j + 1) + "] = " + total);
}
}

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.

o. En la tabla siguiente se resaltan los elementos de la diagonal secundaria de una matriz:

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).

La función que implemente podrá utilizarse en el caso 16 de la forma que se indica


enseguida:
case "16":
System.out.print("Cantidad de litros: ");
int litros = in.nextInt();
System.out.print("Precio por galón: ");
double precio = in.nextDouble();
Ejemplos.calculoPagoLeche(litros, precio);
break;

q. El factorial de n o n factorial se define como el producto de todos los números enteros


positivos desde 1 hasta n. Ejemplo: 5! = 5 x 4 x 3 x 2 x 1. Implemente el caso 17 de acuerdo
al código que se muestra a continuación y la función respectiva, teniendo en cuenta que
ésta recibe como argumento un entero de tipo byte y retorna un long:

System.out.print("Ingrese un número para obtener su factorial: ");


int n = in.nextInt();
System.out.println("Factorial de " + n + " = " + Ejemplos.factorial(n));

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));

El valor retornado por Fx corresponde a la siguiente serie:

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:

System.out.print("Número natural: ");


int numero = in.nextInt();
Ejemplos.listarDivisores(numero);

u. Caso 21: en Java es posible definir argumentos variables o varArgs e implementar


sobrecarga de funciones, lo primero, permite recibir una cantidad variable de
argumentos del mismo tipo y lo segundo permite definir varios métodos con el mismo
nombre, pero con distintos tipos de argumentos. Observe por ejemplo los siguientes
llamados a funciones:
case "21":
Ejemplos.listar(10, 15, 45, 50);
Ejemplos.listar(10, 15, 45, 50, 29, 76);
Ejemplos.listar("\n%d elementos recibidos:", 22.05, 16.15, 34.3, 73.5, 8,12);
break;

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:

static void listar(int... v) {


System.out.printf("\nSe listarán %d elementos:", v.length);
for (int i = 0; i < v.length; i++) {
System.out.printf("\nElemento [%d]: %d", i + 1, v[i]);
}
}
Como puede ver la única diferencia con respecto a lo visto hasta ahora, son los tres
puntos que siguen al tipo de datos o que preceden al nombre del argumento. Este tipo
de argumentos tiene una restricción y es que debe ser el último de la lista. Ejemplo:

static void listar(String msj, double x, int... v) { /* instrucciones */ }

Como se dijo, la sobrecarga de métodos o funciones sobrecargadas, consiste en definir


funciones con el mismo nombre y con distintos argumentos. Ejemplo:

static void listar(String mensaje, double... v) {


System.out.printf(mensaje, v.length);
for (int i = 0; i < v.length; i++) {
System.out.printf("\nElemento [%d]: %5.2f", i + 1, v[i]);
}
}
Observe que a diferencia de la primera función listar, la nueva función que debe agregar
para realizar las pruebas del caso 21, tiene dos argumentos, lo cual indica una
implementación de sobrecarga. En resumen, se da sobrecarga cuando:

a. La cantidad de argumentos es distinta para funciones que se definen con el


mismo nombre.
b. El tipo de argumentos es distinto para funciones que se definen con el mismo
nombre, aunque no siempre la cantidad de argumentos deba ser distinta.

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:

 El especificador de formato (%d) indica que el primer argumento a sustituir en la


cadena corresponde a un valor entero, que en este caso es i + 1.

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

6. Este punto se basa en las actividades complementarias de la 2 a la 7 de la práctica 9. Para el caso


se modifica la aplicación propuesta, con el fin de implementar una nueva versión basada en
funciones. Las instrucciones que se requieren se documentan, paso a paso, en recuadros de color
amarillo. Las demás partes del código no deben ser modificadas o eliminadas. La estructura
general de la aplicación queda así:

package funciones;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Nomina {

static int totalEmpleados = 0; // total de empleados procesados


static double nominaSinInc = 0; // total de nomina sin incremento
static double nominaConInc = 0; // total de nomina con incremento
static double totalSolidaridad = 0; // total descontado x solidaridad pensional

public static void main(String[] args) throws FileNotFoundException {

try (Scanner in = new Scanner(new File("varios/datos_nomina.csv"))) {


in.useDelimiter(";");

String cedula = "", apellidos = "", nombres = "";


int categoria = -1;
double sueldoActual;

int opcion = leerOpcion();

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) {

1. Incremente en uno a totalEmpleados.


2. Agregue a nominaSinInc el sueldo recibido como argumento.
3. Muestre por pantalla los siguientes datos:
a. Cédula
b. Nombre completo
c. Categoría
d. El sueldo actual

double nuevoSueldo = calcularIncremento(categoria, sueldoActual);


calcularDescuento(categoria, nuevoSueldo);
System.out.println("-------------------------------");
}

/**
* 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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 63/191


* @param categoria Determina el porcentaje de incremento a aplicar.
* @param sueldo Lo devengado sin incremento
* @return El sueldo incrementado
*/
private static double calcularIncremento(int categoria, double sueldo) {
double porcentajeInc = 0, incremento;

1. Asigne a porcentajeInc un valor, según sea el caso especificado en el punto 6 de la actividad


complementaria de la práctica 9.
2. Asigne a incremento lo que debe ser incrementado al sueldo recibido como argumento,
teniendo en cuenta el porcentaje definido en el punto 1.
3. Teniendo en cuenta que el argumento sueldo se comporta como una variable local, adicione
al valor actual de dicha variable, el incremento obtenido en el paso anterior.
4. Agregue a nominaConInc el sueldo incrementado.
5. Muestre por pantalla:
a. El porcentaje de incremento indicado en la tabla del paso 1.
b. El incremento realizado.
c. El sueldo con el incremento.
return sueldo;
}

/**
* 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;

1. Asigne a porcentajeDesc un valor, según sea el caso especificado en el punto 7 de la actividad


complementaria de la práctica 9.
2. Asigne a descuento lo que debe ser descontado al sueldo recibido como argumento, teniendo
en cuenta el porcentaje hallado en el punto 1.
3. Teniendo en cuenta que el argumento sueldo se comporta como una variable local, sustraiga
al valor actual de dicha variable, el descuento obtenido en el paso anterior.
4. Agregue a totalSolidaridad el descuento calculado en el paso 2.
5. Muestre por pantalla:
a. El porcentaje de descuento indicado en la tabla del paso 1.
b. El descuento realizado.
c. El sueldo luego de ser afectado por el paso 3. Es decir sustrayendo la solidaridad
pensional.

/**
* Calcula los promedios de nómina, el porcentaje total incrementado y
* muestra información general de nómina
*/

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 64/191


public static void mostrarTotales() {
double promNominaSinInc, promNominaConInc, porcentajeInc;

1. Muestre el total de nómina sin incremento.


2. Asigne a promNominaSinInc, el promedio de los sueldos sin incremento con base en los datos
nominaSinInc y totalEmpleados.
3. Muestre el promedio de sueldos sin incremento.
4. Muestre el total de nómina con incremento.
5. Asigne a nominaConInc, el promedio de los sueldos incrementados.
6. Muestre el promedio de sueldos con incremento.
7. Calcule y muestre el total de aumento en la nómina, sabiendo que se conoce el total de
nómina con incremento y sin incremento.
8. Asigne a porcentajeInc el porcentaje incrementado.
9. Muestre para humanos cuál fue el porcentaje incrementado. Ejemplo de lo que se podría
mostrar: “El aumento en nómina equivale al 7.3%”
10. Muestre el total descontado por solidaridad pensional.

}
}

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:

Valor de Fondo de Auxilio de


PROFESIÓN
la Hora Solidaridad Transporte

INGENIERÍA DE ALIMENTOS Y PROFESIONES AFINES 70000 10% No aplica


MÉDICO VETERINARIO Y PROFESIONES AFINES 60000 9% 6.5%
BACTERIOLOGA, MICROBIOLOGO Y AFINES 50000 8% 7.5%

La siguiente es la nueva versión basada en funciones:

package funciones;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class NominaProfesionales {

private static double totalNominaNeto = 0, totalNominaBruto = 0;

public static void main(String[] args) throws FileNotFoundException {


// evite hacer cambios en el archivo CSV, puede quedar inservible
try (Scanner in = new Scanner(new File("varios/profesionales_contratados.csv"))) {
in.useDelimiter(";");
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 65/191
String cedula = "", nombre = "", profesion = "";
int horasTrabajadas;

in.nextLine(); // omite la primera fila (ver encabezados del archivo)

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("-------------------------------");
}

private static void calcularSueldo(int horas, double valorHora,


double porcSolidaridad, double porcTransporte) {
if (horas > 0) {

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 66/191


1. Cree la variable local auxilioTransporte inicializada en cero.
2. Cree la variable local pagoBase y asigne el cálculo requerido.
3. Agregue a la variable totalNominaBase el pago base obtenido en 2.
4. Muestre el pago base como se indica en los ejemplos de los resultados
de salida que se incluyen al final de este código fuente.
5. Cree la variable local descuento y asigne a ella el descuento que
corresponde al fondo de solidaridad pensional.
6. Muestre cuánto se descuenta en el paso anterior, según el ejemplo
que se incluye al final de este código fuente.
7. Si no aplica el porcentaje de auxilio de transporte muestre el aviso “No
aplica auxilio de trasporte” en caso contrario:
a. Asigne en auxilioTransporte el cálculo necesario.
b. Muestre el incremento según el ejemplo que se incluye al final.
8. Cree la variable local pagoNeto y asigne en ella el cálculo
correspondiente.
9. Agregue a totalNominaNeto el pagoNeto calculado en 8.
10. Muestre el pago neto, según el ejemplo que se incluye al final de este
código.

} else {
System.out.println("No reportó horas trabajadas");
}
} // fin de la función calcularSueldo
} // fin de la clase

A continuación, se incluyen algunas muestras representativas con el formato o presentación que


se quiere para el reporte:

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
-------------------------------

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 67/191


Práctica 12 – Introducción a la programación orientada a objetos
Esta práctica está pensada como una ágil, casi imperceptible, transición a la programación orientada a
objetos, pero asegurando que los conceptos sobre estructuras de control, funciones y estructuras de datos
se fundamenten debidamente.

Los temas a tratar serán:

 El Entorno de Desarrollo Integrado (IDE) Eclipse. Se supone que tiene Java instalado.
 Uso de librerías o paquetes.
 Clases y Objetos.

Aunque no es necesario, el siguiente taller recomienda descargar la última versión de Eclipse17 y no


recomienda trabajar con Netbeans o incorporar a eclipse plugins que amplíen su funcionamiento, esto con
miras a fundamentar debidamente conceptos técnicos que si se abordan de manera muy automatizada,
necesariamente generarán vacíos en el proceso de aprendizaje.

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.

Al terminar tendrá un entorno como el que se muestra en la figura siguiente:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 69/191


Importante: pulse clic sobre el botón que se resalta en la parte izquierda de la imagen para desplegar
el panel que mostrará la estructura de la aplicación y visualizado el panel, despliegue la estructura del
proyecto, pulsando sobre “>”.

7. Agregar clases al proyecto. En el panel que muestra la estructura del proyecto, elija src > New > Class.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 70/191


8. En el cuadro que se despliega y como se muestra en la siguiente imagen, indique el nombre de la
primera nueva clase del proyecto y desmarque la casilla que indica crear un método “public static
void main(…)”. Verifique la información del formulario y pulse Finish.

En este último paso se ha creado una clase como esta:

public class Secuencial {


package demobase;

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 71/191


9. Agregue a la nueva clase el código que se muestra enseguida. Con ello, definirá un atributo de clase
y agregará dos nuevos métodos (funciones) a la clase creada:

package demobase;
import java.util.Scanner;

public class Secuencial {


static Scanner in = new Scanner(System.in); //  atributo de clase
/**
* Método concatenar - Ejemplo 1, pág. 12
*/
public static void concatenar() {
String nombres, apellidos, nombreCompleto;

System.out.print("Ingrese nombre: ");


nombres = in.nextLine();

System.out.print("Ingrese apellido: ");


apellidos = in.nextLine();

nombreCompleto = nombres + " " + apellidos;

System.out.println("---- resultados del proceso -------");


System.out.println("Nombre completo: " + nombreCompleto);
}

/**
* Método sumarValores - Ejemplo 2, pág. 12
*/
public static void sumarValores() {

int a;
float b, c;

System.out.print("Ingrese un valor entero: ");


a = in.nextInt();

System.out.print("Ingrese un valor real: ");


b = in.nextFloat(); // separador de decimales, coma o punto según configuración

c = a + b;

System.out.println("Resultado: " + c);


}

// Y así sucesivamente, agregue como métodos, todos los ejercicios de la práctica 6.

}
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.

Importante: se reitera que ya no se requiere la instrucción static Scanner in = new Scanner(System.in);


dentro de cada método que se defina y que esta clase no contiene el método main, dado que no se
utilizará para iniciar la ejecución de la aplicación.

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:

 ShowConfirmDialog: despliega una pregunta de confirmación.

 ShowInputDialog: solicita un dato.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 73/191


 ShowMessageDialog: informar al usuario sobre algo que ha sucedido.

 ShowOptionDialog: algo así como la unión de la funcionalidad de los anteriores.

De acuerdo a lo explicado, agregue e implemente la clase que servirá de punto de entrada a la


aplicación de la manera que se muestra enseguida:

package demobase;
import java.util.Scanner;
import javax.swing.JOptionPane;

public class DemoBase {

private static final Scanner in = new Scanner(System.in);

private static Secuencial secuencial; //  Definir una instancia de la clase Secuencial

public static void main(String[] args) {


secuencial = new Secuencial(); //  Crear la instancia de tipo Secuencial
do {

String caso = JOptionPane.showInputDialog(null, "Elija una opción (\"0\" para terminar)");


if (caso.equals("0")) {
int opcion = JOptionPane.showConfirmDialog(null,
"¿Esta seguro?", ":-(",
JOptionPane.YES_NO_OPTION);
if (opcion == JOptionPane.YES_OPTION) {
System.exit(0); //  Terminar la aplicación de manera normal
}
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 74/191


switch (caso) {
case "1":
Secuencial.concatenar();
break;

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:

 Se usa el método ShowInputDialog para solicitar el número de opción (caso) que se


seleccionará del switch. Como se puede ver, este método recibe dos argumentos:

String caso = JOptionPane.showInputDialog(null, "Elija una opción (\"0\" para terminar)");

El primer argumento que aquí es null, se refiere al contenedor o ventana sobre el cual se
desplegará el cuadro de diálogo.

El segundo argumento, corresponde al mensaje de solicitud del dato.

El resultado de lo anterior es algo así como esto:

 También se usa ShowConfirmDialog para solicitar que se confirme la salida de la aplicación:

int opcion = JOptionPane.showConfirmDialog(null, "¿Esta seguro?", ":-(",


JOptionPane.YES_NO_OPTION);
Se utilizan los siguientes cuatro argumentos:
El primer argumento que aquí es null, se refiere al contenedor o ventana sobre el cual se
desplegará el cuadro de diálogo.

El segundo argumento, el mensaje de confirmación que se visualizará.

El tercer argumento, el título que aparecerá en el cuadro de diálogo.


Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 75/191
El cuarto argumento define las opciones “Si” y “No” representadas por botones. También es
posible utilizar “Si”, “No” y “Cancelar” (YES_NO_CANCEL_OPTION) o YES_OPTION solamente.

El resultado de la instrucción descrita, es algo así como esto:

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.

 Observe también en el default del switch las siguientes dos instrucciones:

String mensaje = String.format("La opción \"%s\" no está implementada", caso);


JOptionPane.showMessageDialog(null, mensaje, "Tenemos problemas...",
JOptionPane.INFORMATION_MESSAGE);
El método format de la clase String se usa aquí para devolver a la variable mensaje, una
notificación indicando que el caso seleccionado no se encuentra implementado.

Por último, el método ShowMessageDialog de la clase JOptionPane se utiliza aquí para


informar al usuario que ha elegido una opción no implementada. Este método recibe cuatro
argumentos, que con base en las explicaciones anteriores, ya puede deducir su propósito. El
resultado del despliegue, será algo similar a lo que se muestra en la figura siguiente:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 76/191


b. Pulse sobre el icono , para ejecutar la aplicación o pulse Ctrl+F11 o elija la opción Run
del menú.

Nota: es importante que consulte atajos18 de Eclipse que le permitan elegir rápidamente
opciones.

13. Asegúrese de apropiarse debidamente de los siguientes conceptos: el Lenguaje de Modelamiento


Unificado (UML – Unified Modeling Language), es un lenguaje gráfico que se utiliza para visualizar
y especificar los modelos de clases de una aplicación. Sin entrar en detalles, el modelo UML
correspondiente a lo que se ha implementado hasta ahora, corresponde a la figura siguiente:

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.

Importante: cuando un analista – diseñador de software entrega a los encargados de elaborar el


programa un diagrama como el anterior, éstos están obligados a implementar exactamente de
acuerdo a las especificaciones dadas en el diseño. Esto quiere decir que no se permite cambiar
identificadores, modificadores, tipos de retorno, parámetros o cualquier otra especificación
suministrada, a menos que se indique lo contrario. Téngalo muy en cuenta para lo que sigue de
aquí en adelante.

14. Considere el siguiente diagrama de clases:

Con base en el diagrama de clases de la imagen, lleve a cabo las siguientes actividades:

a) Se supone que ya ha completado la implementación de la clase Secuencial con lo propuesto


en el punto 10 de esta práctica, entonces si no lo ha hecho, complete el switch de la clase
DemoBase con los casos necesarios para poder probar la totalidad de los métodos. Esto se
hace de manera similar a como se implementaron los casos 1 y 2.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 78/191


b) Como procedió para la clase Secuencial, construya la clase Ciclos con métodos que
implementen la funcionalidad de las aplicaciones propuestas en la práctica 8, incluyendo las
actividades complementarias. En DemoBase implemente los casos de prueba necesarios.
c) Construya la clase Ciclos con métodos que implementen la funcionalidad de las aplicaciones
propuestas en las prácticas 8 y 9, incluyendo las actividades complementarias. En DemoBase
implemente los casos de prueba necesarios.
d) Construya la clase Vector con métodos que implementen la funcionalidad de las aplicaciones
propuestas en la práctica 10, que demuestren algún caso del uso de vectores (arreglos
unidimensionales), incluyendo las actividades complementarias. En DemoBase implemente
los casos de prueba necesarios.
e) Construya la clase Matriz con métodos que implementen la funcionalidad de las aplicaciones
propuestas en la práctica 10, que demuestren algún caso del uso de matrices (arreglos
bidimensionales), incluyendo las actividades complementarias. En DemoBase implemente los
casos de prueba necesarios.
f) Construya la clase Funciones con métodos que implementen la funcionalidad de las
aplicaciones propuestas en la práctica 11, incluyendo las actividades complementarias. En
DemoBase implemente los casos de prueba necesarios.

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:

private Secuencial secuencial;


private Decision decision;
private Ciclos ciclos;
private Funciones funciones;
private Matriz matriz;
private Vector vector;

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:

matriz = new Matriz();


vector = new Vector();
secuencial = new Secuencial();

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 79/191


Práctica 13 – Interfaces Gráficas de Usuario (GUI) – Una mirada a Swing
Esta práctica está orientada al desarrollo de interfaces gráficas mediante el uso de Swing, la biblioteca de
interfaces gráficas de usuario (GUI) que hace parte del conjunto de clases fundamentales de Java (JFC, Java
Foundation Classes) que se proporcionan en el JDK y que heredan componentes de una librería anterior
denominada Abstract Window Toolkit (AWT). Esta biblioteca consta esencialmente de los siguientes
paquetes:

 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:

1. Conocer la jerarquía de componentes disponibles para construir interfaces gráficas de usuario


(GUI).

2. Construir interfaces de usuario basadas en Swing.

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.

Jerarquía de componentes gráficos

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:

19 La gráfica es tomada de http://www.ntu.edu.sg/home/ehchua/programming/


Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 80/191
Como se muestra en la figura, las clases base de todos los componentes gráficos son las clases Component
y Container que se encuentran en el paquete awt.

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.

Descendiendo en la jerarquía, se encuentra la clase java.awt.JFrame, una derivación de Window que


agrega un marco a la ventana con título, bordes, menús y controles de cambio de tamaño y de cierre. La
apariencia de un objeto de tipo JFrame es como se muestra enseguida:

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 82/191


3. Implemente la nueva clase de acuerdo al código que se muestra a continuación:

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 }

La explicación de la implementación es la siguiente:

 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.

 En la línea 8 se define un método que tiene el mismo nombre de la clase. Cuando un


método tiene el mismo nombre de la clase, se dice que es un constructor, o sea un método
que se utiliza para crear objetos a partir de la clase. Cuando más adelante se utilice la
instrucción new DemoJFrame(), en realidad se estará llamando al constructor para que
cree el formulario.

 En la línea 12 se define el método que es llamado en la línea 9 y que como su nombre lo


indica, inicializa las características del formulario que se crea. Veamos:

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.

b) Línea 14: el método setDefaultCloseOperation, también es heredado de JFrame y


se usa aquí para indicar, por medio del argumento recibido (EXIT_ON_CLOSE), que
el formulario se cerrará cuando se pulse sobre el botón “X”. Las constantes que
este método puede recibir como argumento, son las siguientes:

 DISPOSE_ON_CLOSE: Destruye completamente la ventana liberando la


memoria que ocupa.
 DO_NOTHING_ON_CLOSE: No hace nada.
 EXIT_ON_CLOSE: Termina la aplicación cuando se cierra la ventana.
 HIDE_ON_CLOSE: Oculte la ventana, pero no la destruye.

c) Línea 15: con el método heredado setExtendedState, se indica que el formulario


se muestra del tamaño establecido. También se pudo haber indicado
MAXIMIZED_BOTH para que se mostrase maximizado o ICONIFIED para mostrarlo
minimizado.

d) Línea 16: el llamado a setPreferredSize, recibe como argumento un objeto de tipo


Dimension que permite definir el ancho y la altura del formulario.

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.

f) Hace que la ventana se redimensione según el tamaño y los diseños definidos de


sus subcomponentes.

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
}
}

private static String elegirOpcion() {


String opciones[] = {
"0 - Un simple ventana con gestor de diseño por defecto",
"1 - Gestor de diseño FlowLayout",
"2 - Gestor de diseño GridLayout",
"3 - Gestor de diseño BorderLayout",
"4 - Gestor de diseño BoxLayout 1",
"5 - Gestor de diseño BoxLayout 2",
"6 - Gestor de diseño BoxLayout 3",
"7 - Gestor de diseño GridBagLayout",
"9 - Gestor de diseño DemoGroupLayout",
"10 - Demostración de JPanel",
"11 - Demo DemoJScrollPane",
"12 - Demo MenuBar"
};

String caso = (String) JOptionPane.showInputDialog(null, "Elija una opción",


"Ejemplos de Swing", JOptionPane.QUESTION_MESSAGE, null, // usar icono por defecto
opciones, // array de opciones
opciones[5]); // opción inicial
if(caso == null || ("".equals(caso))) {
System.exit(0); // terminar la aplicación
} else {
caso = caso.substring(0, caso.indexOf(' ')); // subcadena hasta el primer espacio
}
return caso;
}
}

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.

5. Ejecute la aplicación (Ctrl+F11) y observe el comportamiento de la primera opción disponible.


Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 85/191
Gestores de diseño

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).

2. Implemente la nueva clase de acuerdo al código siguiente:

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 }

La explicación de la implementación es la siguiente:

 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íneas de la 8 y 9: se declaran dos instancias de tipo JButton.

 Línea 10: se define la etiqueta que muestra el texto “Nombre”.

 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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 87/191


 Líneas 22 y 23: se crean las instancias de JButton, note como los constructores reciben los
textos que muestran los botones.

 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.

 En las líneas de la 28 a la 31 se puede observar cómo se utiliza el método add del


contenedor para agregar, en su orden, la etiqueta, el campo de texto y los dos botones.

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 88/191


GridLayout: Este administrador de diseño provisto por awt, coloca los componentes en forma de una
matriz que ocupa todo el espacio asignado al contenedor. En la figura siguiente se muestran 12
componentes dispuestos en un GridLayout de 4 x 3:

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.

2. Implemente la nueva clase de acuerdo al código siguiente:

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 }

La explicación de la implementación es la siguiente:

 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.

Importante: observe la línea 26 de la clase DemoFlowLayout, donde se estableció el gestor de


diseño FlowLayout y note la diferencia con la forma en que se establece en la línea 19 de este
ejemplo. En el anterior el argumento que recibe el método setLayout es una instancia anónima y
en este ejemplo el argumento es el objeto grid, previamente creado y ligeramente transformado
en cuanto al espaciado que deben tener los componentes.

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 90/191


2. Implemente la nueva clase de acuerdo al código siguiente:

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 }

La explicación de la implementación es la siguiente:

 Línea 16: Se establece el gestor de diseño BorderLayout, indicando un espacio horizontal


y vertical de 5 unidades entre componentes. Observe que el gestor se declara como una
instancia anónima que se envía como argumento al método setLayout.

 Líneas de la 18 a la 22: se agregan cinco botones al contenedor. Observe cómo al agregar


cada componente, se indica mediante un segundo argumento, la zona en que debe quedar
ubicado cada elemento. Es claro que el segundo argumento que recibe aquí el método
add, corresponde a una constante static definida en la clase BorderLayout.

3. Agregue al switch de DemoSwing un case “3” que le permita probar el comportamiento de esta
nueva clase.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 91/191


BoxLayout: Este gestor de diseño organiza los componentes en una única fila (Y_AXIS) o columna (X_AXIS),
respetando el estado predefinido de los componentes. Observe cómo se verían una etiqueta, un área de
texto, una casilla de selección y un botón administrados por BoxLayout en un eje Y:

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.

2. Implemente la nueva clase de acuerdo al código siguiente:

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));

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 92/191


27 contenedor.add(lbMensaje);
28 contenedor.add(txtaEditor);
29 contenedor.add(chkSeleccion);
30 contenedor.add(btnAceptar);
31
32 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
33 setExtendedState(JFrame.NORMAL);
34 setPreferredSize(new Dimension(600, 200));
35 pack();
36 setVisible(true);
37 }
38
39 }

La explicación de la implementación es la siguiente:

 Líneas 9, 10, 21 y 22: Se incorporan dos nuevos tipos de componentes, correspondientes


a un área de texto y una casilla de selección.

 Línea 26: se establece el gestor de diseño BoxLayout. Observe que el constructor de la


instancia que recibe como argumento el método setLayout, recibe dos argumentos, el
primero hace referencia al contenedor que se va a gestionar y el segundo, la constante
Y_AXIS o X_AXIS que indica si los elementos se colocarán de forma vertical o de forma
horizontal.

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:

 setMaximumSize(Dimension tamaño): máxima dimensión del componente.


 setMinimumSize(Dimension tamaño): mínima dimensión del componente.
 setPreferredSize(Dimension tamaño): dimensión preferida del componente.
 setAlignmentX(float x) y setAlignmentY(float y): alineación en fila o en columna.

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 93/191


La nueva clase se llamará DemoBoxLayout2, será muy similar a DemoBoxLayout1, excepto para
el método inicializarComponentes, que debe quedar así:

private void inicializarComponentes() {


this.setTitle("Gestor de diseño BoxLayout");

lbMensaje = new JLabel("Escriba en el \u00e1rea de texto siguiente:");


lbMensaje.setAlignmentX(Component.RIGHT_ALIGNMENT);

txtaEditor = new JTextArea();


txtaEditor.setPreferredSize(new Dimension(600, 100));

chkSeleccion = new JCheckBox("Deshabilite el \u00e1rea de texto");


chkSeleccion.setAlignmentX(Component.RIGHT_ALIGNMENT);

btnAceptar = new JButton("Acepte los cambios");


btnAceptar.setAlignmentX(Component.RIGHT_ALIGNMENT);

Container contenedor = getContentPane();


contenedor.setLayout(new BoxLayout(contenedor, BoxLayout.Y_AXIS));

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);
}

5. Pruebe lo realizado en el punto anterior, comentando y sin comentar la instrucción


setPreferredSize(new Dimension(600, 300)). Determine qué cambio sucede.

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 94/191


Con base en los cambios que se muestran a continuación, cree una nueva versión
DemoBoxLayout3, para que el formulario tenga la apariencia mostrada en la figura anterior.

private void inicializarComponentes() {


this.setTitle("Gestor de diseño BoxLayout");

lbMensaje = new JLabel("Escriba en el \u00e1rea de texto siguiente:");


lbMensaje.setAlignmentX(Component.CENTER_ALIGNMENT);

txtaEditor = new JTextArea();


txtaEditor.setPreferredSize(new Dimension(1160, 100));
txtaEditor.setMaximumSize(new Dimension(1160, 100));

chkSeleccion = new JCheckBox("Deshabilite el \u00e1rea de texto");


chkSeleccion.setAlignmentX(Component.CENTER_ALIGNMENT);

btnAceptar = new JButton("Acepte los cambios");


btnAceptar.setAlignmentX(Component.CENTER_ALIGNMENT);

Container contenedor = getContentPane();


contenedor.setLayout(new BoxLayout(contenedor, BoxLayout.Y_AXIS));

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());

setPreferredSize(new Dimension(600, 300));


setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(JFrame.NORMAL);
pack();
setVisible(true);
}

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:

 contenedor.add(Box.createRigidArea(new Dimension(ancho, alto)));


 contenedor.add(Box.createHorizontalStrut(ancho));
 contenedor.add(Box.createVerticalStrut(altura));

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 95/191


GridBagLayout: Es un gestor de diseño muy flexible y funcional, por la misma razón su manejo es complejo.
Con él podrá organizar horizontal y verticalmente los componentes, gracias a que los distribuye en celdas
de una matriz. Adicionalmente cada componente puede ocupar varias celdas con lo que se logra establecer
distintos tamaños para los mismos. Observe la figura de un formulario en el que sus componentes han
sido distribuidos mediante GridBagLayout:

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.

2. Implemente la nueva clase de acuerdo al código siguiente:

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");

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 96/191


22
23 lblMensaje = new JLabel("Algunos componentes swing: ");
24 chkCasilla1 = new JCheckBox("Casilla de selecci\u00f3n 1");
25 chkCasilla2 = new JCheckBox("Casilla de selecci\u00f3n 2");
26 rbtnOpcion1 = new JRadioButton("Bot\u00f3n de selecci\u00f3n 1");
27 rbtnOpcion2 = new JRadioButton("Bot\u00f3n de selecci\u00f3n 2");
28 rbtnOpcion3 = new JRadioButton("Bot\u00f3n de selecci\u00f3n 3");
29 btnComando = new JButton("Bot\u00f3n de Comando");
30
31 Container contenedor = getContentPane();
32 contenedor.setLayout(new GridBagLayout());
33
34 agregarComponente(contenedor, lblMensaje, 0, 0, 2);
35 agregarComponente(contenedor, chkCasilla1, 0, 1, 1);
36 agregarComponente(contenedor, chkCasilla2, 0, 2, 1);
37 agregarComponente(contenedor, rbtnOpcion1, 2, 0, 1);
38 agregarComponente(contenedor, rbtnOpcion2, 2, 1, 1);
39 agregarComponente(contenedor, rbtnOpcion3, 2, 2, 1);
40 agregarComponente(contenedor, btnComando, 0, 3, 3);
41
42 setPreferredSize(new Dimension(400, 200));
43 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
44 setExtendedState(JFrame.NORMAL);
45 pack();
46 setVisible(true);
47 }
48
49 private void agregarComponente(Container contenedor, JComponent componente,
int x, int y, int ancho) {
50 GridBagConstraints gridBagConstraints = new GridBagConstraints();
51 gridBagConstraints.gridx = x; // columna del grid que ocupa
52 gridBagConstraints.gridy = y; // fila del grid en que se agrega
53 gridBagConstraints.gridwidth = ancho; // número de celdas que ocupa a partir de x
54 gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; // estirar el componente
55 contenedor.add(componente, gridBagConstraints);
56 }
57 }

La explicación de la implementación es la siguiente:

 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ínea 32: se registra el administrador de diseño para el contenedor del JFrame.

 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:

a. El primer argumento formal es de tipo Container y referencia al contenedor por


defecto del JFrame.

b. El segundo argumento formal es de tipo JComponent, al definirlo de este tipo,


garantiza que reciba como argumento actual, cualquier tipo de los que se derivan
de esta clase. Por esta razón recibe sin problemas la etiqueta, las casillas de
selección y los botones. Se recomienda que le dé una mirada a dicha jerarquía de
clases, la cual se incluyó en la página 82.

c. El tercero y cuarto argumentos, indican la fila y la columna en que se ubicará cada


elemento.

d. Y el quinto argumento el número de columnas que ocupa.

 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íneas de la 51 a la 53: se establecen las restricciones de ubicación y tamaño. Tamaño


determinado en número de celdas que ocupa a partir de la posición X.

 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:

 Para método setHorizontalGroup, los componentes y grupos ordenados paralelamente tienen la


misma posición en el eje X. Mientras que, en una secuencia, la posición más a la derecha le
corresponde al último componente o grupo en ser agregado.

 Para el método setVerticalGroup, los componentes y grupos ordenados paralelamente tienen la


misma posición en el eje Y. Mientras que, en una secuencia, la posición más abajo le corresponde
al último componente o grupo en ser agregado.

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 98/191


Seguidamente se indican los pasos necesarios para construir un formulario como el de la figura anterior,
mediante el uso de 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.

2. Implemente la nueva clase de acuerdo al código siguiente:

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 }

Enseguida se explica el funcionamiento básico del gestor de diseño utilizado:

 Línea 40: se crea el gestor. Observe que el constructor de este gestor, recibe como
argumento el contenedor que se va a gestionar.

 Línea 41: se asigna el gestor creado al contenedor del formulario.

 Líneas 43 y 44: se fija el espaciado automático entre componentes mediante


setAutoCreateGaps(true) y también se establece el espaciado automático con respecto al
contenedor setAutoCreateContainerGaps(true).

 Líneas de la 46 a la 71: se establece la distribución horizontal de los componentes y grupos


de componentes del formulario.

 Líneas de la 72 a la 95: se establece la distribución vertical de los componentes y grupos


de componentes del formulario.

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 101/191


Clases contenedoras intermedias

Antes de continuar explicando los restantes gestores de diseño, detengámonos un


momento en el tema de una jerarquía que se deriva de JComponent conocida como
contenedores intermedios, los cuales permiten agrupar otros componentes que
pueden ser tratados en conjunto. De estos contenedores existe una gran variedad
en swing que va desde el más sencillo como lo es el JPanel, hasta otros muy
sofisticados como JTabbedPane, que permiten mostrar varias fichas sobrepuestas
en el formulario. Como característica común, todos ellos ofrecen la posibilidad de
mejorar y flexibilizar el diseño de las interfaces gráficas de usuario, puesto que
dentro de un contenedor de alto nivel o de uno intermedio, se pueden incluir otros
intermedios. Empecemos por ver el funcionamiento básico de JPanel.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 102/191


JPanel: Este contenedor representa una sección rectangular a la cual se le puede aplicar un diseño
específico, mediante un administrador de diseño distinto a su gestor por defecto FlowLayout. Inicialmente
son invisibles, pero se les puede aplicar un color de fondo que permita diferenciarlos o incluso crearles
diferentes tipos de bordes. Observe en la gráfica siguientes, el diseño de un formulario en el que se
utilizaron cuatro contenedores intermedios de tipo JPanel invisibles, pero resaltados en azul:

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).

2. Implemente la nueva clase de acuerdo al código siguiente:

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 }

En la exposición que sigue de la implementación, se omiten explicaciones de temas de arrays y de


estructuras de control que a estas alturas deben estar debidamente fundamentadas:

3. Línea 15: Se asigna a la variable textoBotones, un array de 8 elementos, resultante de dividir la


cadena en todos los elementos separados por comas, mediante el uso del método split. Observe
que los textos separados por comas, corresponden a los textos mostrados por los botones de la
figura anterior.

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 105/191


6. Líneas 32 y 40: según la cabecera y la instrucción return, este método retorna un objeto de tipo
JPanel, que corresponde al panel ubicado en la parte superior del formulario.

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.

La figura de la izquierda representa un JFrame al que se le agregó en la


parte izquierda un JScrollPane que a su vez contiene un objeto JList.

En la parte central (panelSeleccion) y en la derecha (panelOpciones) los


contenedores agregados son de tipo JPanel. El de la parte central
contendrá los tipos de series elegibles para mostrar en el objeto JList y
el de la parte derecha (panelOpciones), permitirá elegir el rango de
valores a mostrar.

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).

2. Implemente la nueva clase de acuerdo al código siguiente:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 107/191


1 package demoswing;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 public class DemoJScrollPane extends JFrame {
7
8 private JScrollPane scrollNumeros;
9 private JList<String> lstNumeros;
10
11 private JPanel panelSeleccion;
12 private ButtonGroup btnGrpOpciones;
13 private JRadioButton[] jrButtons;
14 String textoBotones[];
15
16 private JPanel panelOpciones;
17 private JLabel lblInferior;
18 private JLabel lblSuperior;
19 private JComboBox<String> cboInferior;
20 private JComboBox<String> cboSuperior;
21
22 private JButton btnAceptar;
23
24 public DemoJScrollPane() {
25 inicializarComponentes();
26 }
27
28 private void inicializarComponentes() {
29 setTitle("Demostración de JScrollPane");
30 Container contenedor = getContentPane();
31 contenedor.setLayout(new GridLayout(1, 3));
32
33 crearJScrollPane(contenedor);
34 contenedor.add(crearPanelSeleccion());
35 crearPanelOpciones();
36 contenedor.add(panelOpciones);
37
38 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
39 setExtendedState(JFrame.NORMAL);
40 setPreferredSize(new Dimension(600, 225));
41 pack();
42 setVisible(true);
43 }
44
45 private void agregarComponente(Container contenedor, JComponent componente,
int x, int y, int ancho) {
46 GridBagConstraints gridBagConstraints = new GridBagConstraints();
47 gridBagConstraints.gridx = x;
48 gridBagConstraints.gridy = y;
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 108/191
49 gridBagConstraints.gridwidth = ancho;
50 gridBagConstraints.insets = new Insets(5, 0, 5, 0);
51 gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
52 contenedor.add(componente, gridBagConstraints);
53 }
54
55 private void crearJScrollPane(Container contenedor) {
56 scrollNumeros = new JScrollPane();
57 scrollNumeros.setBorder(BorderFactory.createTitledBorder(" Lista: "));
58 lstNumeros = new JList<>();
59 scrollNumeros.setViewportView(lstNumeros);
60 contenedor. add(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 jrButtons = new JRadioButton[5];
69 textoBotones = "Números pares,Números impares,Serie de Fibonacci,Números
primos,Una serie matemática".split(","); //  es parte de la línea anterior
70
71 btnGrpOpciones = new ButtonGroup();
72 for (int i = 0; i < jrButtons.length; i++) {
73 jrButtons[i] = new JRadioButton(textoBotones[i]);
74 btnGrpOpciones.add(jrButtons[i]);
75 panelSeleccion.add(jrButtons[i]);
76 }
77 return panelSeleccion;
78 }
79
80 public JPanel crearPanelOpciones() {
81 panelOpciones = new JPanel();
82
83 panelOpciones.setBorder(BorderFactory.createTitledBorder(" Opciones: "));
84 panelOpciones.setLayout(new GridBagLayout());
85
86 lblInferior = new JLabel("Intervalo inferior: ");
87 panelOpciones.add(lblInferior, new GridBagConstraints());
88
89 cboInferior = new JComboBox<>();
90 panelOpciones.add(cboInferior, new GridBagConstraints());
91
92 lblSuperior = new JLabel("Intervalo superior: ");
93 agregarComponente(panelOpciones, lblSuperior, 0, 1, 1);
94
95 cboSuperior = new JComboBox<>();
96 agregarComponente(panelOpciones, cboSuperior, 1, 1, 1);
97
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 109/191
98 btnAceptar = new JButton("Aceptar");
99 agregarComponente(panelOpciones, btnAceptar, 0, 2, 2);
100 return panelOpciones;
101 }
102 }

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.

1. Línea 8: se define un objeto de tipo JScrollPane


que contendrá un objeto de tipo JList, declarado
en la línea siguiente.

2. Línea 33: se agrega al JFrame la instancia del


JScrollPane, sin embargo no espere ver aún una
lista de números como la de la figura.

3. Línea 56: se crea la instancia de JScrollPane.

4. Línea 57: se le asigna un borde con título.

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 110/191


9. Líneas 9, 19, 20, 58, 89 y 95: estas líneas tienen en común que introducen el tema de los genéricos
que aparecieron por primera vez en la versión 5 de Java, lanzada en el año 2004. En la siguiente
sección se da una breve introducción a este tema, tomando como base el uso que se le da en el
ejemplo anterior.

10. Hasta aquí se ha dado una muy breve


introducción a los contenedores
intermedios de Java, en la que sólo se han
analizado las características mínimas de
la clase JPanel y la clase JScrollPane.
Como puede ver, hay más…, y por lo
tanto se recomienda consultar el
funcionamiento de los restantes.

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ú.

La clase JPopupMenu permite definir y crear los menús contextuales o


emergentes, como cualquier otra instancia de clase creada hasta ahora.

Tanto a instancias de la clase JMenuBar como a instancias de tipo


JMenuPopup, se pueden agregar opciones de tipo JRadioButtonMenultem que
se comportan de manera similar a los JRadioButton incluidos en la aplicación
anterior.

También se pueden agregar opciones de tipo JMenuttem como las que se


representan en el ejemplo y definir opciones que muestran casillas de
selección, a partir de la clase JCheckBoxMenultem.

La estructura de la izquierda, corresponde a la manera como


se implementó el menú principal del ejemplo mostrado. Se
observa que a la barra se agregan cuatro menús y será a estos
menús que se anexan las demás opciones y submenús.

Se considera que la implementación es tan sencilla que no


requiere explicaciones adicionales, por lo tanto, veamos el
código completo de la aplicación.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 112/191


1 package demoswing;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 public class DemoMenuBar extends JFrame {
7
8 private final String RUTAIMAGENES = "recursos/blueberry/png/32/";
9
10 private JMenuBar barraMenu;
11 private JMenu menuArchivo;
12 private JMenu menuNuevo;
13 private JMenuItem itemActores;
14 private JMenuItem itemPeliculas;
15 private JPopupMenu.Separator separa1;
16 private JMenuItem itemPropiedades;
17 private JPopupMenu.Separator separa2;
18 private JMenuItem itemSalir;
19 private JMenu menuEdicion;
20 private JMenuItem itemEdicionActores;
21 private JMenuItem itemEdicionGeneros;
22 private JMenuItem itemEdicionPeliculas;
23 private JMenuItem itemEdicionPrestamos;
24 private JMenuItem itemSocios;
25 private JMenu menuConsultas;
26 private JMenu menuAyuda;
27 private JMenuItem itemAcercaDe;
28
29 public DemoMenuBar() {
30 initComponents();
31 }
32
33 private void initComponents() {
34 ImageIcon iconNuevo = new ImageIcon(getClass().getClassLoader().getResource(RUTAIMAGENES +
"document_file.png"));
35
36 menuArchivo = new JMenu("Archivo");
37 menuNuevo = new JMenu("Nuevo");
38 menuNuevo.setIcon(iconNuevo);
39 itemActores = new JMenuItem("Actores");
40 itemPeliculas = new JMenuItem("Peliculas");
41 separador1 = new JPopupMenu.Separator();
42 itemPropiedades = new JMenuItem("Propiedades");
43 separador2 = new JPopupMenu.Separator();
44 itemSalir = new JMenuItem("Salir");
45
46 menuEdicion = new JMenu("Edición");
47 itemEdicionActores = new JMenuItem("Actores");
48 itemEdicionGeneros = new JMenuItem("Géneros");
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 113/191
49 itemEdicionPeliculas = new JMenuItem("Películas");
50 itemEdicionPrestamos = new JMenuItem("Préstamos");
51 itemSocios = new JMenuItem("Socios");
52
53 menuConsultas = new JMenu("Consultas");
54
55 menuAyuda = new JMenu("Ayuda");
56 itemAcercaDe = new JMenuItem("Acerca de");
57
58 menuArchivo.add(menuNuevo);
59 menuNuevo.add(itemActores);
60 menuNuevo.add(itemPeliculas);
61 menuArchivo.add(separador1);
62 menuArchivo.add(itemPropiedades);
63 menuArchivo.add(separador2);
64 menuArchivo.add(itemSalir);
65
66 menuEdicion.add(itemEdicionActores);
67 menuEdicion.add(itemEdicionGeneros);
68 menuEdicion.add(itemEdicionPeliculas);
69 menuEdicion.add(itemEdicionPrestamos);
70 menuEdicion.add(itemSocios);
71
72 menuAyuda.add(itemAcercaDe);
73
74 barraMenu = new JMenuBar();
75 barraMenu.add(menuArchivo);
76 barraMenu.add(menuEdicion);
77 barraMenu.add(menuConsultas);
78 barraMenu.add(menuAyuda);
79 setJMenuBar(barraMenu);
80
81 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
82 setExtendedState(JFrame.NORMAL);
83 setPreferredSize(new Dimension(600, 225));
84 pack();
85 setVisible(true);
86 }
87 }

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 114/191


Práctica 14 – Eventos
Para el desarrollo de esta práctica, se supone que ha realizado la práctica 13 y por lo tanto no se incluirán
detalles de cómo implementar las GUI que se utilizan para estudiar el modelo de interacción propuesto
por Java a partir de Swing y la gestión de eventos que permite a los usuarios interactuar con componentes
de las aplicaciones y que dichos componentes respondan de acuerdo a la forma como fueron
programados.

De acuerdo a lo dicho, aquí se documentarán las bases esenciales para cubrir tres objetivos:

1. Entender el funcionamiento de los listeners u oyentes de eventos.

2. Mostrar las formas de programar eventos.

3. Desarrollar destrezas en lo que respecta a la programación orientada a eventos.

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.

Resumiendo a lo esencial, el modelo de eventos consiste en lo siguiente:

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:

public class PrimerDemo extends JFrame implements ActionListener {…}

Enseguida se implementarán variantes de un sencillo ejemplo sobre el proyecto DemoSwing para


demostrar los tres puntos anteriores.

Variante 1: La clase que representa al formulario implementa la interface Listener

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.

2. En la clase demoswing, agregue la instrucción de importación que se resalta en el código siguiente,


para indicar que se importará todo lo del paquete demoeventos.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 115/191


package demoswing;

import demoeventos.*;
import javax.swing.JOptionPane;

public class DemoSwing {

public static void main(String[] args) {



3. Agregue al switch del método main en la clase DemoSwing, un nuevo caso que más adelante
permitirá probar cómo implementar eventos de manera básica:

case "13": // puede ser cualquier número de opción


new DemoEvento1();
break;

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:

private static String elegirOpcion() {


String opciones[] = {
"0 - Un simple ventana sin gestor de diseño",
"1 - Gestor de diseño FlowLayout",

"13 - Demo Eventos 1" //  OJO
};

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 116/191


14 public DemoEvento1() {
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(this);
29 btnVerde.addActionListener(this);
30 btnAzul.addActionListener(this);
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 @Override
44 public void actionPerformed(ActionEvent evento) {
45 Object origen = evento.getSource();
46 Color color;
47
48 if (origen == btnRojo) {
49 color = Color.RED;
50 } else if (origen == btnVerde) {
51 color = Color.GREEN;
52 } else {
53 color = Color.BLUE;
54 }
55 contenedor.setBackground(color);
56 }
57 }

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 117/191


se obliga a la clase DemoEvento1 a implementar el método actionPerformed, definido en la
interfaz. Por esta razón, la clase marcará error hasta tanto dicho método no se implemente.

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.

3. A partir de la línea 43 se implementa el método actionPerformed, con lo cual se da cumplimiento


al contrato del que se habló en el punto 1.

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).

5. En la línea 46 se define un objeto que permite manipular colores en Java.

6. A partir de la línea 48 se decide establecer un color de acuerdo al origen del evento.

7. En la línea 55 se establece como color de fondo del formulario, el correspondiente al botón


pulsado.

Pruebe ahora ejecutar a DemoSwing y observe los hermosos colores de fondo que toma el formulario
cuando se pulsa uno de sus botones.

Variante 2: Una clase interna distinta al formulario implementa la interface Listener

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 }

La explicación del nuevo código de estas clases es la siguiente:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 119/191


2. En la línea 43 de la clase interna23 AccionBoton se observa que ésta “se compromete” a
implementar la interfaz ActionListener, con lo cual se obliga a codificar el método actionPerformed
que aparece codificado a partir de la línea 46 de la clase.

Variante 3: Un objeto de una clase interna anónima implementa la interface Listener

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 class DemoEvento4 extends JFrame {

private JButton btnAzul;


private JButton btnRojo;
private JButton btnVerde;
private Container contenedor;

public DemoEvento4() {
inicializarComponentes();
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 121/191


private void inicializarComponentes() {
setTitle("Demo Listener");

btnRojo = new JButton("Rojo");


btnVerde = new JButton("Verde");
btnAzul = new JButton("Azul");

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);
}

public void colorActionPerformed(ActionEvent evento) {


JButton origen = (JButton) evento.getSource();
Color color;

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 class DemoEvento5 extends JFrame {

private JButton btnAzul;


private JButton btnRojo;
private JButton btnVerde;
private Container contenedor;

public DemoEvento5() {
inicializarComponentes();
}

private void inicializarComponentes() {


setTitle("Demo Listener");

btnRojo = new JButton("Rojo");


btnVerde = new JButton("Verde");
btnAzul = new JButton("Azul");

contenedor = getContentPane();
contenedor.setLayout(new FlowLayout());

btnRojo.addActionListener((ActionEvent evento) -> {


contenedor.setBackground(Color.RED); // más de una instrucción en un método aparte
});

btnVerde.addActionListener((ActionEvent evento) -> {


contenedor.setBackground(Color.GREEN); // más de una instrucción en un método aparte
});
btnAzul.addActionListener((ActionEvent evento) -> {
contenedor.setBackground(Color.BLUE); // más de una instrucción en un método aparte
});

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 123/191


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);
}
}

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 124/191


1. Use Eclipse para crear un nuevo proyecto de Java
con el nombre EstructurasProgramacion.

2. En el nuevo proyecto, cree un paquete denominado


estructurasprogramacion.

3. Agregue la clase EstructurasProgramacion al


paquete creado en el punto 2.

4. Agregue e implemente la clase EstructurasProgramacion como se muestra enseguida, teniendo


en cuenta que la línea 51 mostrará un error:

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 125/191


37 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
38 setExtendedState(JFrame.NORMAL);
39 setPreferredSize(new Dimension(1280, 720));
40
41 this.pack();
42 setVisible(true);
43 }
44
45 private void elegirOpcion(ActionEvent evento) {
46 JButton origen = (JButton) evento.getSource();
47 String opcion = origen.getText();
48
49 switch (opcion) {
50 case "Demo 1":
51 new DemoSuma();
52 break;
53 // continúe implementando otros casos
54 // ...
55 default:
56 String mensaje = String.format("La opción \"%s\" no está implementada", opcion);
57 JOptionPane.showMessageDialog(null, mensaje, "¡Atención!",
58 JOptionPane.INFORMATION_MESSAGE);
59 System.exit(0); // terminar la aplicación
60 }
61 }
62
63 public static void main(String[] args) {
64 new EstructurasProgramacion().setVisible(true);
65 }
66 }

Nota: este código no aporta conceptos nuevos por lo tanto no requiere explicaciones.

5. Agregue la clase DemoSuma al paquete estructurasprogramacion e impleméntela como se


muestra enseguida:

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.

7. Con base en lo anterior responda el siguiente cuestionario:

a. Cuál es la diferencia entre double y Double.


b. Para qué sirve el método parseDouble de la clase Double.
c. El método getText está implementado en la clase JTextField. (F/V)
d. El método getText es un mutador. (F/V)
e. El método setText es un mutador. (F/V)
f. Consulte en la Internet para qué sirve la instrucción try {…} catch (…) {…}
g. Pruebe qué sucede si no ingresa valores en los campos de texto e intenta obtener un
resultado. Explique porqué se obtiene lo que se obtiene.
h. ¿Los resultados obtenidos siempre son precisos? – Si no es así consulte por qué.

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 128/191


Proceda como se indica enseguida para construir dicha aplicación tomando como base el gestor de diseño
GridBagLayout e incorporando una lista de selección.

1. Agregue al paquete estructurasprogramacion, la clase Listado e impleméntela como se muestra


enseguida:

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 }

A continuación, se presentan algunos detalles importantes de esta clase:

 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.*;

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 130/191


6
7 public class DemoJComboBox extends JFrame {
8
9 private JLabel lblMensaje, lblNumeroMes, lblNombreMes;
10 private JComboBox cboMeses;
11 private JTextField txtNombreMes;
12 private JButton btnAceptar;
13 private Container contenedor;
14
15 public DemoJComboBox() {
16 inicializarComponentes();
17 }
18
19 private void inicializarComponentes() {
20 this.setTitle("Formulario: suma de dos elementos");
21
22 lblMensaje = new JLabel("Dado un número de mes mostrar su nombre");
23 lblNumeroMes = new JLabel("Número del mes: ");
24 lblNombreMes = new JLabel("Nombre del mes: ");
25
26 cboMeses = new JComboBox();
27 cboMeses.setModel(new DefaultComboBoxModel<>(Listado.ordinales(1, 12)));
28 txtNombreMes = new JTextField(30);
29
30 btnAceptar = new JButton("Aceptar");
31 btnAceptar.addActionListener((ActionEvent evento) -> {
32 determinarMes();
33 });
34
35 contenedor = getContentPane();
36 contenedor.setLayout(new GridBagLayout());
37
38 agregarComponente(contenedor, lblMensaje, 0, 0, 2);
39 agregarComponente(contenedor, lblNumeroMes, 1, 0, 1);
40 agregarComponente(contenedor, cboMeses, 1, 1, 1);
41 agregarComponente(contenedor, lblNombreMes, 2, 0, 1);
42 agregarComponente(contenedor, txtNombreMes, 2, 1, 1);
43 agregarComponente(contenedor, btnAceptar, 3, 0, 2);
44
45 setPreferredSize(new Dimension(300, 250));
46 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // OJO
47 setExtendedState(JFrame.NORMAL);
48 pack();
49 setVisible(true);
50 }
51
52 private void agregarComponente(Container contenedor, JComponent componente,
int fila, int columna, int colsAncho) { //  nueva versión
53 GridBagConstraints gridBagConstraints = new GridBagConstraints();
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 131/191
54 gridBagConstraints.gridx = columna;
55 gridBagConstraints.gridy = fila;
56 gridBagConstraints.gridwidth = colsAncho;
57 gridBagConstraints.ipady = 5;
58 gridBagConstraints.insets = new Insets(10, 0, 0, 0);
59 gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
60 contenedor.add(componente, gridBagConstraints);
61 }
62
63 private void determinarMes() {
64 int mes;
65 try {
66 mes = Integer.parseInt(cboMeses.getSelectedItem().toString());
67 if (mes == 1) {
68 txtNombreMes.setText("Enero");
69 } else if (mes == 2) {
70 txtNombreMes.setText("Febrero");
71 // completar de Marzo a Noviembre
72 } else if (mes == 12) {
73 txtNombreMes.setText("Diciembre");
74 } else {
75 txtNombreMes.setText("Número de mes erróneo");
76 }
77 } catch (NumberFormatException e) {
78 txtNombreMes.setText("Número erróneo");
79 }
80 }
81 }

La explicación de la implementación de esta clase es la siguiente:

 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íneas de la 52 a la 61: se ha incorporado una nueva versión del método agregarComponente


básicamente para cambiar el orden de los argumentos fila y columna. Este será el método que
se utilizará de ahora en adelante cada vez que se requiera utilizar el gestor GridBagLayout.

 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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 132/191


3. Implemente un nuevo caso en el método elegirOpcion de la clase EstructurasProgramacion, para
probar el comportamiento de una instancia anónima creada a partir de la clase DemoJComboBox.

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:

Veamos cómo implementar este ejemplo:

1. Agregue al paquete estructurasprogramacion, la clase FrmEstadosCiviles e impleméntela como se


muestra enseguida:

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 133/191


16 public FrmEstadosCiviles() {
17 inicializarComponentes();
18 }
19
20 private void inicializarComponentes() {
21
22 btnGrpEstadosCiviles = new ButtonGroup();
23 lblMensaje = new JLabel("Seleccione un estado civil y pulse clic en \"Aceptar\"");
24 rbtnSoltero = new JRadioButton("Soltero");
25 rbtnComprometido = new JRadioButton("Comprometido");
26 rbtnCasado = new JRadioButton("Casado");
27 rbtnDivorciado = new JRadioButton("Divorciado");
28 rbtnViudo = new JRadioButton("Viudo");
29 rbtnUnionLibre = new JRadioButton("Unión libre");
30 lblEstadoElegido = new JLabel("Estado civil elegido: ");
31 txtEstadoElegido = new JTextField(12);
32 btnAceptar = new JButton("Aceptar");
33 btnAceptar.addActionListener((ActionEvent evento) -> {
34 determinarEstadoCivil();
35 });
36
37 contenedor = getContentPane();
38 contenedor.setLayout(new GridBagLayout());
39
40 btnGrpEstadosCiviles.add(rbtnSoltero);
41 btnGrpEstadosCiviles.add(rbtnComprometido);
42 btnGrpEstadosCiviles.add(rbtnCasado);
43 btnGrpEstadosCiviles.add(rbtnDivorciado);
44 btnGrpEstadosCiviles.add(rbtnViudo);
45 btnGrpEstadosCiviles.add(rbtnUnionLibre);
46
47 agregarComponente(contenedor, lblMensaje, 0, 0, 2);
48 agregarComponente(contenedor, rbtnSoltero, 1, 0, 2);
49 agregarComponente(contenedor, rbtnComprometido, 2, 0, 2);
50 agregarComponente(contenedor, rbtnCasado, 3, 0, 2);
51 agregarComponente(contenedor, rbtnDivorciado, 4, 0, 2);
52 agregarComponente(contenedor, rbtnViudo, 5, 0, 2);
53 agregarComponente(contenedor, rbtnUnionLibre, 6, 0, 2);
54 agregarComponente(contenedor, lblEstadoElegido, 7, 0, 1);
55
56 txtEstadoElegido.setEditable(false);
57 txtEstadoElegido.setHorizontalAlignment(JTextField.LEFT);
58 agregarComponente(contenedor, txtEstadoElegido, 7, 1, 1);
59 agregarComponente(contenedor, btnAceptar, 9, 0, 2);
60
61 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
62 pack();
63 setVisible(true);
64 }
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 134/191
65
66 private void agregarComponente(Container contenedor, JComponent componente,
int fila, int columna, int colsAncho) {
// implemente como en DemoJComboBox
75 }
76
77 private void determinarEstadoCivil() {
78 if (rbtnCasado.isSelected()) {
79 txtEstadoElegido.setText(rbtnCasado.getText());

// complete con las demás alternativas…

88 } else if (rbtnViudo.isSelected()) {
89 txtEstadoElegido.setText(rbtnViudo.getText());
90 }
91 }
92 }

2. Implemente un nuevo caso en el método elegirOpcion de la clase EstructurasProgramacion, para


probar el comportamiento de una instancia anónima creada a partir de la clase FrmEstadosCiviles.

La explicación de la implementación es la siguiente:

 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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 135/191


Veamos cómo implementar este sencillo ejemplo que no requiere explicaciones adicionales:

1. Agregue a estructurasprogramacion, la clase FrmPreferencias e impleméntela según el código y


las indicaciones que se dan. Luego proceda como se ha indicado para ver su funcionalidad:

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 136/191


20 private void initComponents() {
21 lblMensaje = new JLabel("Seleccione los lenguajes preferidos y pulse clic en \"Aceptar\"");
22 lblElegidos = new JLabel("Lenguajes elegidos: ");
23 txtLenguajesElegidos = new JTextField(40);
24 btnAceptar = new JButton("Aceptar");
25 btnAceptar.addActionListener((ActionEvent evento) -> {
26 determinarElegidos();
27 });
28
29 chkJava = new JCheckBox("Java");
30 chkC = new JCheckBox("C");
31 chkCPlus = new JCheckBox("C++");
32 chkC_sharp = new JCheckBox("C#");
33 chkPython = new JCheckBox("Python");
34 chkVBNet = new JCheckBox("Visual Basic .NET");
35 chkJS = new JCheckBox("JavaScript");
36 chkPHP = new JCheckBox("PHP");
37 chkPerl = new JCheckBox("Perl");
38
39 contenedor = getContentPane();
40 contenedor.setLayout(new GridBagLayout());
41
42 agregarComponente(contenedor, lblMensaje, 0, 0, 2);
43 agregarComponente(contenedor, chkJava, 1, 0, 2);
// …
// como se agregó a chkJava, agregue los demás JCheckBox definidos
// …
52 agregarComponente(contenedor, lblElegidos, 10, 0, 1);
53 agregarComponente(contenedor, txtLenguajesElegidos, 10, 1, 1);
54 agregarComponente(contenedor, btnAceptar, 11, 0, 2);
55
56 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
57 pack();
58 setVisible(true);
59 }
60
61 private void agregarComponente(…) {
// implemente como en DemoJComboBox
70 }
71
72 private void determinarElegidos() { // por qué no se uso else if c
73 String seleccionados = "";
74 if (chkJava.isSelected()) {
75 seleccionados += (", " + chkJava.getText());
76 }
77 if (chkC.isSelected()) {
78 seleccionados += (", " + chkC.getText());
79 }
// Y así sucesivamente para los demás JCheckBox
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 137/191
92 seleccionados = seleccionados.substring(1);
93 txtLenguajesElegidos.setText(seleccionados);
94 }
95 }

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”:

Veamos cómo implementar este ejemplo:

1. Agregue al paquete estructurasprogramacion, la clase FrmColorAleatorio e impleméntela según el


código y las indicaciones que se dan en forma de comentarios:

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 138/191


17 private void inicializarComponentes() {
18 btnAceptar = new JButton("Probar suerte");
19 contenedor = getContentPane();
20 contenedor.setLayout(new GridBagLayout());
21 agregarComponente(contenedor, new PanelDibujo(), 0, 0, 1);
22 agregarComponente(contenedor, btnAceptar, 1, 0, 1);
23
24 btnAceptar.addActionListener((ActionEvent evento) -> {
25 repaint();
26 });
27
28 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
29 pack();
30 setVisible(true);
31 }
32
33 class PanelDibujo extends JPanel {
34
35 private Color colores[] = {
36 Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY,
37 Color.GRAY, Color.GREEN, Color.LIGHT_GRAY,
38 Color.MAGENTA, Color.ORANGE, Color.PINK,
39 Color.RED, Color.WHITE, Color.YELLOW
40 };
41
42 public PanelDibujo() {
43 this.setPreferredSize(new Dimension(400, 400));
44 }
45
46 public void paintComponent(Graphics g) {
47 int i = ThreadLocalRandom.current().nextInt(0, 13);
48 if (this.colores[i] == Color.BLUE) { // si saca el color azul gana
49 g.setFont(new Font("default", Font.BOLD, 16));
50 g.drawString("¡Felicitaciones! ganaste la mitad de la compra", 30, 395);
51 }
52 g.setColor(this.colores[i]);
53 g.fillOval(20, 20, 350, 350);
54 }
55
56 }
57
58 private void agregarComponente(…) { // versión 2
// …
// implemente como en DemoJComboBox
// …
67 }
68
69 }

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 139/191


2. Implemente un nuevo caso en el método elegirOpcion de la clase EstructurasProgramacion, para
probar el comportamiento de una instancia anónima creada a partir de la clase FrmColorAleatorio.

Las explicaciones de las novedades en esta clase son las siguientes:

 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íneas de la 35 a la 40: se crea un array de colores básicos.

 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 52: se establece el color indicado por el índice i.

 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 }

2. Implemente un nuevo caso en el método elegirOpcion de la clase EstructurasProgramacion, para


probar el comportamiento de una instancia anónima creada a partir de la clase DemoListas.

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.

cboMeses = new JComboBox();


cboMeses.setModel(new DefaultComboBoxModel<>(Listado.ordinales(1, 12)));

 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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 144/191


modelo” y como su nombre lo indica consiste en aislar la implementación de la interfaz de usuario
de la lógica de la aplicación, comúnmente llamada “modelo”.

 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:

1. Termine de implementar la clase Listado y el método mostrarEleccion de la clase DemoListas, de


tal manera que al elegir cualquiera de las 5 series, se muestre correctamente el listado de
elementos respectivos.

2. Observe la siguiente imagen basada en el ejercicio propuesto en las páginas 22 y 23:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 145/191


Observe además que el gestor del JFrame es de tipo BorderLayout y a éste se agregan tres paneles,
el de entradas de datos en el oeste, el de resultados en el este y el de acciones en el sur.

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.

 La siguiente instrucción muestra cómo agregar un borde con título a un panel:

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.

Implemente el panel de entrada de datos de la clase FrmPromocion, de acuerdo a lo especificado


en la parte izquierda de la figura y el panelAzar de acuerdo a lo explicado a partir de la página 138,
en el apartado “cómo dibujar figuras”.

4. Implemente con interfaz gráfica los siguientes ejercicios:

a. De la práctica 7, los ejercicios 5, 6, 8, 9 y 10 y

b. De la práctica 8 elabore con interfaz gráfica el algoritmo del MCD.

5. Lleve a cabo los siguientes cambios en la clase Listado:

a. Importe la clase javax.swing.ListModel y tenga en cuenta que no puede crear instancias a


partir de esta clase, por una razón que será explicada en el siguiente capítulo.

b. Agregue el siguiente método a la clase:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 146/191


public static double sumatoria(ListModel<String> modelo) {
double suma = 0;
for (int i = 0; i < modelo.getSize(); i++) {
suma += Double.parseDouble(modelo.getElementAt(i));
}
return suma;
}

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:

JTable tablaValores = new JTable();


tablaValores.setModel(new DefaultTableModel(
new Object[][]{}, //  un array bidimensional de objetos, vacío (una tabla vacía)
new String[]{ //  un vector de Strings que representa la cabecera de la tabla
"Col. 1", "Col. 2", "Col. 3", "Col. 4"
}
));

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:

1. Cree la clase Tabla dentro del paquete estructurasprogramación e impleméntela exactamente


como se muestra a continuación:

package estructurasprogramacion;

import java.util.concurrent.ThreadLocalRandom;
import javax.swing.JTable;
import javax.swing.table.*;

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 148/191


/**
* Esta clase proporciona demostraciones de manipulación de matrices que se pueden visualizar
* en componentes de tipo JTable.
* @author Carlos Cuesta Iglesias
* @see <a href="https://drive.google.com/open?id=0B3Zlyx-DWwvZN3JzWUdHQkJDamc">
* Documentación del autor</a>
* @version 0.9 del 14 de octubre de 2017
*/
public class Tabla {

/**
* 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];

for (int i = 0; i < filas - 1; i++) {


for (int j = 0; j < cols - 1; j++) {
datosTabla[i][j] = ThreadLocalRandom.current().nextInt(0, 13);
}
}
return (new DefaultTableModel(datosTabla, cabecera));
}

/**
* 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();

for (int j = 0; j < tabla.getColumnCount(); j++) {


columnas.getColumn(j).setCellRenderer(centerRenderer);
}
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 149/191


/**
* Totaliza en la última columna de un objeto JTable, las columnas precedentes de cada fila.
* @param table Una referencia al objeto JTable sobre el cual se realizará el cálculo.
*/
public static void totalizarFilas(JTable table) {
DefaultTableModel modelo = (DefaultTableModel) table.getModel();
int filas = modelo.getRowCount();
int cols = modelo.getColumnCount();
int j;

for (int i = 0; i < filas - 1; i++) {


int suma = 0;
for (j = 0; j < cols - 1; j++) {
int v = Integer.parseInt(modelo.getValueAt(i, j).toString());
suma += v;
}
modelo.setValueAt(suma, i, j);
}
}
}

2. Agregue a la clase anterior el método totalizarColumnas con base en lo especificado para el


método totalizarFilas, incluyendo el mismo estilo de documentación.

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 150/191


21 private void inicializarComponentes() {
22 contenedor = getContentPane();
23 contenedor.setLayout(new GridBagLayout());
24 colsTabla = new String[]{
25 "Col. 1", "Col. 2", "Col. 3", "Col. 4"
26 };
27
28 scrollPane = new JScrollPane();
29 tablaValores = new JTable();
30 tablaValores.setModel(new DefaultTableModel(new Object[][]{}, colsTabla));
31 scrollPane.setViewportView(tablaValores);
32
33 btnLlenar = new JButton("Llenar tabla");
34 btnLlenar.addActionListener((ActionEvent evento) -> {
35 tablaValores.setModel(Tabla.getModelo(colsTabla, 30));
36 Tabla.alinearValores(tablaValores, JLabel.CENTER);
37 });
38
39 btnCalcular = new JButton("Totalizar filas");
40 btnCalcular.addActionListener((ActionEvent evento) -> {
41 Tabla.totalizarFilas(tablaValores);
42 Tabla.totalizarColumnas(tablaValores);
43 });
44
45 panelOpciones = new JPanel(); // Si no se especifica gestor de diseño, se asigna FlowLayout
46 panelOpciones.add(btnLlenar);
47 panelOpciones.add(btnCalcular);
48 agregarComponente(contenedor, scrollPane, 0, 0, 1);
49 agregarComponente(contenedor, panelOpciones, 1, 0, 1);
50
51 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
52 setExtendedState(JFrame.NORMAL);
53 this.pack();
54 setVisible(true);
55 }
56
57 private void agregarComponente(…) {
// …
66 }
67 }

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:

a. Genere la lista de números 0, -1, 2, -3, 4, -5, 6, -7, 8, -9, …

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 152/191


datos la hace el usuario sobre celdas previamente creadas vacías, para lo cual lo único que
hay que hacer es algo así como esto:

tablaValores.setModel(new DefaultTableModel(
new Object[numFilas][numCols]{},
new String[]{
"Nota 1", …, "Definitiva"
}

c. Sobre el ejercicio b, implemente mostrar el promedio del grupo.

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.

Notas finales al manejo de eventos

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:

objeto.addTipoListener((ActionEvent evento) -> { … });

Tipo Listener Descripción del evento Método y Tipo de Evento


ActionListener Define un método para recibir eventos de actionPerformed(ActionEvent e)
acción.
AdjustmentListener Define un método para recibir eventos de adjustmentValueChanged
ajuste. (AdjustmentEvent e)
ComponentListener Define cuatro métodos para reconocer componentHidden(ComponentEvent e)
cuándo se oculta, se mueve, se cambia de componentMoved(ComponentEvent e)
tamaño o se muestra un componente. componentResized(ComponentEvent e)
componentShown(ComponentEvent e)
ContainerListener Define dos métodos para reconocer cuándo componentAdded(ContainerEvent e)
se añade o se elimina un componente de un componentRemoved(ContainerEvent e)
contenedor.
FocusListener Define dos métodos para reconocer cuándo focusGained(FocusEvent e)
un componente gana o pierde el foco del focusLost(FocusEvent e)
teclado.
ItemListener Define un método para reconocer cuándo itemStateChanged(ItemEvent e)
cambia de estado un elemento.
KeyListener Define tres métodos para reconocer cuándo keyPressed(KeyEvent e)
se presiona, se libera o se golpea una tecla. keyReleased(KeyEvent e)
keyTyped(KeyEvent e)
MouseListener Define cinco métodos para reconocer mouseClicked(MouseEvent e)
cuándo se presiona o libera un botón del mouseEntered(MouseEvent e)

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)

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 155/191


Práctica 15 – Sobre el Paradigma de la Programación Orientada a Objetos
Un paradigma de programación define un conjunto de estrategias y principios que son usadas mediante
la implementación de unas reglas en los lenguajes. Durante el corto tiempo de vida de la ingeniería de
software, han surgido varios paradigmas de programación, como son la programación estructurada o
imperativa, la programación funcional, la programación lógica, la orientada a aspectos y la orientada a
objetos.

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.

2. A una entidad u objeto perceptible de un sistema normalmente se le puede clasificar y darle un


nombre. Por ejemplo, a toda la población mundial se le conoce como Personas, Individuos o
Ciudadanos de la comunidad mundial.

3. De las entidades concretas, los objetos o de un ciudadano X o Y, normalmente se pueden conocer


cuatro particularidades básicas: se le puede clasificar, se identifica con un nombre, tiene unas
características, propiedades o atributos específicos y se comporta de una manera determinada.
Aun lo que aparenta estar inanimado tiene un comportamiento a nivel atómico o subatómico que
lo diferencia de otros objetos inanimados.

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:

1. Un sistema de información orientado a objetos normalmente está compuesto por subsistemas,


módulos o paquetes de librerías y clases que originan objetos.

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,

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 156/191


proporcionan valores a los atributos de las clases. Veamos un esquema de lo dicho, a la izquierda
representando una clase y a la derecha un objeto:

Representación de una clases y sus atributos Representación de una instancia de clase


Clase Persona destinatario:Persona
identificacion Identificacion = “10203040”
nombreCompleto nombreCompleto = “Carlos Cuesta Iglesias”
Atributos
direccionesDeEntrega direccionesDeEntrega = “Calle 66, #66-66” …”
telefonos telefonos = “313 666 6666”
boolean equals(Object obj) boolean equals(Object obj)
Métodos
String toString() String toString()

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:

[modificadores] tipo nombreAtributo;

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.

En la siguiente porción de código se

public class Persona {


private String identificacion;
private static String nombreCompleto;
private String direccionesDeEntrega;
private String telefonos;
protected final boolean EDITABLE = true;
...
}

En la siguiente tabla se resume el comportamiento que definen los modificadores de acceso:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 157/191


Modificador La misma Otra clase del Subclase de otro Otra clase de otro
clase mismo paquete paquete paquete
public X X X X
protected X X X
default X X
private X

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 por defecto


public Persona() {
// sólo definir si van otros tipos de constructores o requiere un tratamiento especial
}

// 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;
}

El fragmento de código anterior muestra que existen tres tipos de constructores:

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 cliente = new Persona();


JPanel panel = new JPanel();
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 158/191
b) El constructor parametrizado que recibe como argumentos, uno o varios valores con los
cuales inicializa, uno o varios atributos de la clase. Note que en la implementación de este
constructor se utiliza la palabra this para hacer referencia a los miembros de la propia
clase. Ejemplo de su uso:

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:

Persona cliente2 = new Persona(px);

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:

Persona cliente3 = cliente2;

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:

public String getIdentificacion() {


return identificacion;
}

public String getNombreCompleto() {


return nombreCompleto;
}

 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:

public void setNombreCompleto(String nombreCompleto) {


this.nombreCompleto = nombreCompleto;
}

public String getDireccionesDeEntrega() {


return direccionesDeEntrega;
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 159/191


Los demás métodos que se agreguen a una clase, formarán parte de la funcionalidad específica que se
desee dar, por ejemplo, para este caso se quiere permitir comparar la igualdad de objetos de tipo persona,
por lo tanto, se implementará el método equals y también se quiere implementar un método que
proporcione por consola, información básica de la clase Persona. Con estas adiciones la clase completa
que se quiere definir quedaría así:

package poo;

import java.util.Objects;

public class Persona {

private String identificacion;


private String nombreCompleto;
private String direccionesDeEntrega;
private String telefonos;

Persona() { }

public Persona(Persona p) {
this.identificacion = p.identificacion;
this.nombreCompleto = p.nombreCompleto;
this.telefonos = p.telefonos;
}

public Persona(String identificacion, String nombreCompleto, String direccionesDeEntrega, String telefonos) {


this.identificacion = identificacion;
this.nombreCompleto = nombreCompleto;
this.direccionesDeEntrega = direccionesDeEntrega;
this.telefonos = telefonos;
}

public String getIdentificacion() {


return identificacion;
}

public void setIdentificacion(String identificacion) {


this.identificacion = identificacion;
}

public String getNombreCompleto() {


return nombreCompleto;
}

public void setNombreCompleto(String nombreCompleto) {


this.nombreCompleto = nombreCompleto;
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 160/191


public String getDireccionesDeEntrega() {
return direccionesDeEntrega;
}

public void setDireccionesDeEntrega(String direccionesDeEntrega) {


this.direccionesDeEntrega = direccionesDeEntrega;
}

public String getTelefonos() {


return telefonos;
}

public void setTelefonos(String telefonos) {


this.telefonos = 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}";
}
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 161/191


De resaltar que antes del método equals aparece un signo de arroba seguido de la palabra Override. En
general cuando se utiliza el signo arroba (@) seguido de una palabra, se está haciendo una anotación, en
este caso la anotación indica que el método equals se va a sobrescribir. Veamos en qué consiste esto:

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.

Actividad complementaria (parte 1)


1. Si algo de lo expuesto no ha quedado completamente claro, cree una aplicación, ejecute la clase
siguiente y analice minuciosamente el código y los resultados que se obtienen de la ejecución para
deducir el porqué de los resultados:

package poo;

public class Pruebas {

public static void main(String[] args) {


// uso del constructor por defecto:
Persona pj = new Persona();
System.out.println("Datos iniciales de pj > " + pj);
// uso del constructor parametrizado para crear dos instancias con los mismos datos:
Persona pk = new Persona("102030", "Carlos Cuesta I.", "Calle 66 #66-66", "313 555 5555");
Persona pq = new Persona("102030", "Carlos Cuesta I.", "Calle 66 #66-66", "313 555 5555");
// uso de accesores
System.out.println("Accediendo al nombre de pk: " + pk.getNombreCompleto());
// uso implícito del método toString del objeto pk para mostrar sus datos:
System.out.println("Datos de pk > " + pk);
// uso del constructor copia: los datos de pk y pm serán iguales pero independientes
Persona pm = new Persona(pk);
System.out.println("Datos de pm recién creado como copia de pk > " + pm);
// uso de mutadores
pm.setNombreCompleto("Rabindranath Tagore");
System.out.println("Datos de pk y pm luego de haber modificado a la copia pm:");
System.out.println("Datos de pk > " + pk);
System.out.println("Datos de pm > " + pm);
// pn referencia al mismo objeto que pm
Persona pn = pm;
pj = pm;
System.out.println("pj, pm y pn referencian al mismo objeto:");
System.out.println("pm > " + pm);
System.out.println("pn > " + pn);
// Afectar a pj, pm o pn equivale a afectar al mismo objeto:
pm.setDireccionesDeEntrega("Calcuta, India");
pn.setTelefonos("22 1825 5555");
System.out.println("Afectar a pj, pm o pn equivale a afectar al mismo objeto:");
System.out.println("pj > " + pj);
System.out.println("pm > " + pm);
System.out.println("pn > " + pn);
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 162/191
// comparación de las instancias de Persona
System.out.println("¿Son iguales pj y pn? > " + pj.equals(pn));
System.out.println("¿Son iguales pk y pm? > " + pk.equals(pm));
// ¡Cuidado con las comparaciones! ni pk, ni pq han sufrido cambios:
System.out.println("\n¿Son iguales pk y pq? > " + pk.equals(pq));
System.out.println("¿Son iguales pk y pq? > " + (pk == pq));
}
}

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:

Tabla requerida Contexto de uso


 Auto  Concesionario
 Auto  Taller
 Medicamento  Droguería
 Medicamento  Facultad de medicina*
* Ver https://medlineplus.gov/spanish/druginfo/meds/a681004-es.html

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 163/191


Supongamos que se requiere listar los atributos y la funcionalidad requeridos de una Persona para un
sistema de entrega de encomiendas. El resultado, sin pensarlo mucho, sería algo así como esto:

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:

1. Abstracción de las clases o los tipos,


2. Abstracción de los atributos o las propiedades de las clases y
3. Abstracción de la funcionalidad.

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.

3. Represente las clases conceptuales mediante rectángulos en un modelo del dominio.

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.

6. En una tercera versión, complemente el modelo agregando el comportamiento de la clase. Como


ya se ha dicho, el comportamiento de las clases está dado por sus métodos. Para definir estos
debería tenerse en cuenta cuál es la clase más apropiada para asignarle una responsabilidad de
hacer algo y esta respuesta depende casi siempre de la clase que más datos conozca al respecto,
de manera directa o por las asociaciones dadas.

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.

 Excluir las características irrelevantes. Para la aerolínea y concretamente en el subsistema que se


está modelando, poco importa la estatura del empleado, entonces obvie detalles innecesarios
como ese.

 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:

 Céntrese en aquellas asociaciones para las que se necesita conservar el conocimiento de la


relación durante algún tiempo, así sea por milisegundos.

 Es más importante identificar clases conceptuales que identificar asociaciones.

 Demasiadas asociaciones tienden a confundir un modelo del dominio en lugar de aclararlo.

 Evite mostrar asociaciones redundantes o derivadas.

 Evite representar como atributos, conceptos del dominio complejos; mejor utilice asociaciones.

Actividad complementaria (parte 2)


1. Elabore una primera versión del modelo conceptual, incluyendo sólo los nombres de las clases a
partir del siguiente caso de estudio:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 166/191


2. Elabore una segunda versión del modelo, conservando la primera, donde se incorporen los
atributos del sistema.

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.

De lo dicho se deduce que la modularidad necesariamente lleva al ocultamiento de información, al


ocultamiento de detalles de implementación, lo cual genera los siguientes beneficios:

1. El ocultamiento de información, en lo que se refiere a la implementación, facilita la comprensión


general de los sistemas.

2. El cambio en la implementación de un módulo, normalmente no afecta al resto del sistema.

3. Los módulos pueden reutilizarse en distintas aplicaciones.

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 167/191


para ello necesariamente se tendrá que acoplar o asociar a muchas clases. La figura siguiente ilustra estos
dos detalles:

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.

Actividad complementaria (parte 3)


Revise su modelo de clases conceptuales para ver si cumple con alta cohesión y bajo acoplamiento. Si no,
intente, sólo intente, aumentar la cohesión y bajar el acoplamiento. Es importante aclarar que no siempre
será posible mantener el bajo acoplamiento de una clase.

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.

A nivel de uso, la encapsulación es una forma de abstracción, ya que se simplifica la representación de un


objeto con relación a los objetos externos.
Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 168/191
Para dar un ejemplo resumido de lo tratado hasta aquí, observe la figura siguiente que da lugar a un caso
de estudio sobre análisis y diseño orientado a objetos:

RUT 21545568878
CONFECCIONES EL TELAR E. U. FACTURA
Calle Real N° 10-45, Pereira Risaralda N° 001-0000765

Pereira, 15 de octubre de 2017


Cliente: Gloria Meza Artica – RUT: 1234156
Dirección: Av. de los Comuneros Manizales Transportadora: ENVÍA A17-45891247

CANTIDAD DESCRIPCIÓN PRODUCTO PRECIO PRECIO TOTAL


UNITARIO
10 Camisa casual hombre colección 2017 45.000 450.000
20 Camisa hombre, tejido oriental 50.000 1.000.000
15 Jean Referencia 4517 35.000 525.000

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:

Factura Envío Linea de Venta


Cliente Empacador Producto
Venta Transportadora

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:

 Una venta se realiza a un cliente.


 Una venta tiene líneas de venta.
 Una línea de venta está compuesta de productos.
 Etc…

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);

LineaDeVenta lineaVenta = new LineaDeVenta(20, producto);

Según lo explicado, el modelo de clases conceptuales en su segunda versión queda así:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 171/191


Se ha dicho que una línea de venta tiene asociada una instancia de producto y se demostró con código
Java, cómo hacer dicha asociación al referenciar una instancia existente de producto al momento de crear
la instancia de línea de venta. Observe en la página anterior, en el diagrama de clases generado con
EasyUML, cómo se indica con la línea que asocia a las clases LineaDeVenta y Producto, que la asociación
está dada por una referencia “producto”.

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:

 Composición: cuando los objetos asociados no pueden compartirse y la destrucción de la instancia


compuesta conlleva la destrucción de las instancias referenciadas, se dice que la asociación es
fuerte o que es una composición. Veamos un ejemplo de composición:

Suponga que tiene la clase Factura con su método generarVenta:

import java.util.ArrayList;
public class Factura {
private Venta venta;

public void generarVenta() {

Transportadora transportadora = new Transportadora();


transportadora.setEmpresa("Servientrega");
transportadora.setGuia("87521436");
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);
// …
venta = new Venta("23-10-2017", c1, transportadora, lineasDeVenta, empacador, true);
}
}
Suponga también que tiene la clase MainVentas con su método main implementado de la
siguiente manera:

public class MainVentas {

public static void main(String[] args) {


Factura f = new Factura();
f.generarVenta();
}
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 172/191


Recuerde que cuando un método termina su ejecución, inmediatamente todas las variables locales
al método son eliminadas de memoria, gracias a un sistema de Java denominado Garbage
Collector, por tanto, cuando la instrucción f.generarVenta() termina de ejecutarse, el objeto venta
asociado a la factura deja de existir y con él todos los objetos creados para definir la venta. Esto es
pues, composición.

 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:

public class Factura {

public void generarVenta(Cliente c1, Transportadora transportadora,


ArrayList<LineaDeVenta> lineasDeVenta, Empacador empacador) {
Venta venta = new Venta("23-10-2017", c1, transportadora, lineasDeVenta, empacador, true);
System.out.println(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);

ArrayList<LineaDeVenta> lineasDeVenta = new ArrayList<>();


transportadora.setEmpresa("Servientrega");
transportadora.setGuia("87521436");
LineaDeVenta lv1 = new LineaDeVenta(10, p1);
lineasDeVenta.add(lv1);
lineasDeVenta.add(new LineaDeVenta(20, p2));
lineasDeVenta.add(new LineaDeVenta(15, p3));
Empacador empacador = new Empacador("1725", "Julio Martínez");

Factura f = new Factura();


f.generarVenta(c1, transportadora, lineasDeVenta, empacador);
f = null;
System.out.println(c1);
}
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 173/191


Es lógico pensar que luego de eliminar la instancia de factura (f = null); se puede tener acceso a las
instancias a las que ésta hacía referencia, siendo un claro ejemplo de agregación porque los objetos
asociados sobrevivieron a la destrucción de la instancia f.

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
}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 174/191


Para lograr una salida por consola como la mostrada, el modelo de clases completo sería el siguiente:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 175/191


Resta estudiar un tipo de asociación, aquella dada por la herencia, que como sabemos es una de las cinco
características principales de la programación orientada objetos.

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

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 176/191


no se puede decir en el ejemplo de facturación, entre la asociación entre una venta y una factura. No es
correcto decir, por ejemplo “una factura es una venta”, pero si es correcto decir “el cliente y el empacador
son personas.

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:

public class VehiculoAereo extends Vehiculo { ... }

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:

public abstract class Vehiculo {

public abstract void desplazarse();

@Override

public String toString() {


return " > Vehiculo > " + "identificador: " + identificador
+ "\nmodelo: " + modelo
+ "\ntipo de combustible: " + tipoCombustible
+ "\ncaballos de fuerza: " + caballoDeFuerza;
}
}

El uso de clases abstractas debe cumplir con las siguientes reglas:

 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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 177/191


También tenga en cuenta que:

 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:

VehiculoAereo vA1 = new VehiculoAereo(…);


Avion av = new Avion("Por alas", 4, "HK543", "AH-1 Super Cobra.", "Gasolina JET A-2", 500);
Helicoptero hv = new Helicoptero(…);
VehiculoTerreste vT1 = new VehiculoTerreste(…);
Motocicleta mt = new Motocicleta(…);

 Se tiene un ArrayList de vehículos, al que se han agregado los objetos acabados de definir:

ArrayList<Vehiculo> vehiculos = new ArrayList<>();


vehiculos.add(vA1);
vehiculos.add(av);
vehiculos.add(hv);
vehiculos.add(mt);
 Y por último, se recorre la lista de vehículos de una de las dos maneras siguientes y equivalentes:

for (Vehiculo v : vehiculos) { for (Vehiculo v : vehiculos) {


System.out.println(v); System.out.println(v.toString());
} }

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 178/191


Para el siguiente taller tome como base los siguientes conceptos geométricos:

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;

public interface Dibujable {

public void setCoordenadas(int x, int y);

public void dibujar2D(Graphics g);


}

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 179/191


Inicialmente la única clase que debe implementar la interface Dibujable, es la clase Cuadrado, pero
pasadas todas las pruebas que se incluyen enseguida, cualquier figura 2D debe implementar dicha
interface.

import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;

public class MainFigura {

public static void main(String[] args) {

Cuadrado cuadrado = new Cuadrado(new int[]{15});


cuadrado.setCoordenadas(10, 10);

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 180/191


Circulo circulo = new Circulo(new int[]{3});
System.out.println(circulo);
System.out.println("La longitud del cículo es: " + circulo.calcularLongitud());
System.out.println("-------------------------------------------------");
PoligonoRegular poligonoRegular = new PoligonoRegular(new int[]{8, 5});
System.out.println(poligonoRegular);
System.out.println("El perímetro del polígono regular es: " +
poligonoRegular.calcularPerimetro());

Figura2D rectangulo = new Rectangulo(new int[]{10, 15});


Figura2D paralelogramo = new Paralelogramo(new int[]{15, 10});
Figura2D trapecio = new Trapecio(new int[]{15, 12, 7});
Figura2D triangulo = new Triangulo(new int[]{10, 5});
Figura2D rombo = new Rombo(new int[]{10, 5});

ArrayList<Figura2D> listaFiguras2D = new ArrayList<>();


listaFiguras2D.add(cuadrado);
listaFiguras2D.add(circulo);
listaFiguras2D.add(rectangulo);
listaFiguras2D.add(paralelogramo);
listaFiguras2D.add(trapecio);
listaFiguras2D.add(triangulo);
listaFiguras2D.add(rombo);
listaFiguras2D.add(poligonoRegular);

System.out.println("=================================================");

for (Figura2D figura : listaFiguras2D) {


System.out.println(figura);
System.out.printf("El área es %10.2f\n", figura.calcularArea());
}

JFrame frm = new JFrame();


frm.add(new JPanel() { // observe que no es necesario referenciar al getContentPane
public void paintComponent(Graphics g) {
cuadrado.dibujar2D(g);
// agregar más dibujos de figuras cuando se haya probado con Cuadrado
}
});

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);
}
});

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 181/191


frm.setPreferredSize(new Dimension(600, 400));
frm.setVisible(true);
frm.pack();
}

También puede ser de utilidad saber que el método dibujar2D para la clase Cuadrado se implementó así:

public void dibujar2D(Graphics g) {


g.drawRect(this.x, this.y, this.longitudLados * ESCALA, this.longitudLados * ESCALA);
}

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:

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 182/191


Práctica 16 – Actividades y Documentación Trasversales
La idea con estas actividades es que a partir de las destrezas adquiridas con la práctica 4, complete su
proceso de aprendizaje con el material complementario que aquí se recomienda. Sin duda alguna este
material demandará una gran disponibilidad de tiempo, pero los beneficios serán mucho mayores que si
se limita a estudiar los temas básicos de las actividades anteriores.

Manejo básico de Excepciones

Java implementa un sistema de gestión de excepciones, también llamado sistema de tratamiento de


errores. La sintaxis básica para capturar excepciones es la siguiente:
try {
// el bloque de instrucciones en el que se monitorean errores
} catch (Exception e) {
// Instrucciones a ejecutar cuando se produzca un error
} finally {
//instrucciones que se ejecutarán independientemente de que ocurra un error o no
}

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:

Tipo primitivo Función Función


boolean boolean Boolean.parseBoolean(String) boolean Boolean.valueOf(String)
int int Integer.parseInt(String) int Integer. valueOf (String)
long long Long.parseLong(String) long Long. valueOf (String)
float float Float.parseFloat(String) float Float. valueOf (String)
double double Double.parseDouble(String) double Double. valueOf (String)

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;

public class Excepciones {

public static void main(String[] args) {

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.");
}
}

static void operacion(double v1, double v2, char operador) {


switch (operador) {
case '+':
System.out.printf("%5.2f %s %5.2f = %5.2f", v1, operador, v2, v1 + v2);
break;
case '-':
System.out.printf("%5.2f %s %5.2f = %5.2f", v1, operador, v2, v1 - v2);
break;

}
}

static void mensaje(String msj) {


System.out.println(msj
+ "\nEjecute como se muestra enseguida:\n\n"
+ "\tjava funciones.Excepciones v1 op v2\n\n"
+ "Siendo op un operador binario válido (+, -, *, /, %)\n");
}
}

Para mayor documentación, consulte la “guía definitiva de conversión de tipos en Java”29

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:

 Especificador de formato para una cadena: %s


 Especificador de formato para un valor entero: %d
 Especificador de formato para un real: %f

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:

String[] nombres = {"Juana", "La Loca"};


hacerAlgo(nombres);
Integer[] valores = {10, 20, 50, 75};
hacerAlgo(valores);
Object[] objetos = {"Hola", 10, 20, 10.3, true};
hacerAlgo(objetos);

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.

public enum lenguaje {


JAVA, JAVASCRIPT, PHP, MATLAB, RUBY
}

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.

Anotaciones en Java (@)

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

En este vínculo35, periódicamente se actualizará información que se considere importante para


complementar el curso de fundamentos de programación.

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:

Ahora observe lo sencillo que resulta traducir a Java el algoritmo planteado:

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.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 187/191


JComboBox a partir de ArrayList. Esto para cuando el componente no se crea mediante código sino
mediante NetBeans.

Fundamentos de Programación en Java – carlos.cuesta@ucaldas.edu.co 188/191

Вам также может понравиться