PROGRAMACION ORIENTADA A OBJETOS (POO)

Conceptos Básicos de POO
Se puede hablar de Programación Orientada a Objetos cuando se reúnen las características de: abstracción, encapsulación, herencia y polimorfismo; y los conceptos básicos que las forman: objetos, mensajes, clases, instancias y métodos.


Conceptos Básicos:
  • Un objeto es una encapsulación abstracta de información, junto con los métodos o procedimientos para manipularla. Un objeto contiene operaciones que definen su comportamiento y variables que definen su estado entre las llamadas a las operaciones.
  • Una clase equivale a la generalización o abstracción de un tipo específico de objetos.
  • Un mensaje representa una acción a tomar por un determinado objeto.
  • Una instancia es la concreción de una clase.
  • Un método consiste en la implementación en una clase de un protocolo de respuesta a los mensajes dirigidos a los objetos de la misma. La respuesta a tales mensajes puede incluir el envío por el método de mensajes al propio objeto y aun a otros, también como el cambio del estado interno del objeto.

Características:La abstracción: Consiste en la generalización conceptual de un determinado conjunto de objetos y de sus atributos y propiedades, dejando en un segundo término los detalles concretos de cada objeto. ¿Qué se consigue con la abstracción? Bueno, básicamente pasar del plano material (cosas que se tocan) al plano mental (cosas que se piensan).

La encapsulación: Se refiere a la capacidad de agrupar y condensar en un entorno con límites bien-definidos distintos elementos. Cuando hablemos de encapsulación en general siempre nos referiremos, pues, a encapsulación abstracta. De manera informal, primero generalizamos (la abstracción) y luego decimos: la generalización está bien, pero dentro de un cierto orden: hay que poner límites (la encapsulación), y dentro de esos límites vamos a meter, a saco, todo lo relacionado con lo abstraído: no sólo datos, sino también métodos, comportamientos, etc.

Por un lado es una abstracción pues, de acuerdo con la definición establecida anteriormente, es en ésta donde se definen las propiedades y atributos genéricos de determinados objetos con características comunes (recordemos el ejemplo de la sala de cine). La Clase es, por otro lado, una encapsulación porque constituye una cápsula o saco que encierra y amalgama de forma clara tanto los datos de que constan los objetos como los procedimientos que permiten manipularlos. Las Clases se constituyen, así, en abstracciones encapsuladas.

La herencia: Se aplica sobre las clases. O sea, de alguna forma las clases pueden tener descendencia, y ésta heredará algunas características de las clases "padres". Si disponemos las clases con un formato de árbol genealógico, tenderemos lo que se denomina una estructura jerarquizada de clases.

La OOP promueve en gran medida que las relaciones entre objetos se basen en construcciones jerárquicas. Esto es, las clases pueden heredar diferencialmente de otras clases (denominadas "superclases") determinadas características, mientras que, a la vez, pueden definir las suyas propias. Tales clases pasan, así, a denominarse "subclases" de aquéllas.

La herencia se implementa mediante un mecanismo que se denomina derivación de clases: las superclases pasan a llamarse clases base, mientras que las subclases se constituyen en clases derivadas. El mecanismo de herencia está fuertemente entroncado con la reutilización del código en OOP. Una clase derivada posibilita, el fácil uso de código ya creado en cualquiera de las clases base ya existentes.

El concepto de herencia constituye un estrato básico del paradigma de objetos, pero esto no significa que todas las relaciones entre clases en OOP deban ajustarse siempre a este modelo jerárquico. Es necesario establecer si la pretendida relación entre objetos es de pertenencia o de derivación. En una relación típica de pertenencia un objeto contiene al otro

Polimorfismo: Esta propiedad, como su mismo nombre sugiere múltiples formas, se refiere a la posibilidad de acceder a un variado rango de funciones distintas a través del mismo interfaz. O sea, que, en la práctica, un mismo identificador puede tener distintas formas (distintos cuerpos de función, distintos comportamientos) dependiendo, en general, del contexto en el que se halle inserto.

El polimorfismo se puede establecer mediante la sobrecarga de identificadores y operadores, la ligadura dinámica y las funciones virtuales. El término sobrecarga se refiere al uso del mismo identificador u operador en distintos contextos y con distintos significados.

La sobrecarga de funciones conduce a que un mismo nombre pueda representar distintas funciones con distinto tipo y número de argumentos. En el ámbito de la OOP, la sobrecarga de funciones equivale a que un mismo mensaje puede ser enviado a objetos de diferentes clases de forma que cada objeto respondería al mensaje apropiadamente.

La sobrecarga de operadores permite, por otro lado, el desarrollo de un código más coherente, como especialización de la sobrecarga de funciones, posibilitando la re-definición (para tipos de datos definidos-por-el-usuario) de las operaciones realizadas por éstos (+, -, *, >, etc.). Esto es, ocurre lo mismo que en la sobrecarga de funciones, pero aquí, en vez de identificadores de funciones, tenemos operadores.

Gracias a la ligadura dinámica, pueden invocarse operaciones en objetos obviando el tipo actual del éstos hasta el momento de la ejecución del código.


Otros Conceptos
  • Agregación: Composición de un objeto por otros. Es una relación más débil que la que existe entre el atributo y el objeto al cual pertenece, y más fuerte que una asociación.
  • Concurrencia: Propiedad que distingue un objeto activo de otro inactivo.
  • Persistencia: Es la propiedad de un objeto cuya existencia trasciende el tiempo y/o el espacio (ej. el objeto continua existiendo luego de que su creador deja de existir / la ubicación de un objeto se mueve a un espacio de direcciones diferente de aquella donde fue creada).
  • Visibilidad: capacidad de restringir el acceso a atributos y servicios de un objeto. Particularmente importante en el diseño e implementación. (ej.: público / protegido / privado)
Objetos y Clases

Objetos
  • Un objeto es una cosa tangible, algo a que se puede aprehender intelectualmente o algo hacia lo que se puede dirigir una acción o pensamiento.
  • Un objeto representa un item individual e identificable, o una entidad real o abstracta, con un papel definido en el dominio del problema
  • Un objeto tiene:
    1. Estado
    2. Comportamiento
    3. Identidad
    La estructura y el comportamiento de objetos similares se definen en sus clases comunes. El término objeto y ejemplo (instance) de una clase son intercambiables.

Estado de un objeto El estado de un objeto abarca todas las propiedades del objeto, y los valores actuales de cada una de esas propiedades. Las propiedades de los objetos suelen ser estáticas, mientras los valores que toman estas propiedades cambian con el tiempo.
  • El hecho de que los objetos tengan estado implica que ocupan un espacio, ya en el mundo físico , ya en la memoria del ordenador.
  • El estado de un objeto está influido por la historia del objeto.
  • No deben confundirse los objetos, que existen en el tiempo, son mutables, tienen estado, pueden ser creados, destruidos y compartidos..., con los valores (los asignados a una variable, por ejemplo) que son cantidades con las propiedades de ser atemporales, inmutables.
  • El estado de un objeto representa el efecto acumulado de su comportamiento.

Identidad de un objeto Identidad es la propiedad de un objeto que lo lleva a distinguirse de otros.


Comportamiento de un objeto Comportamiento es como un objeto actua y reacciona, en términos de sus cambios de estado y de los mensajes que intercambia.
El comportamiento de un objeto representa su actividad externamente visible y testable. Son las operaciones que una clase realiza (llamadas también mensajes) las que dan cuenta de como se comporta la clase. Por operación se denota el servicio que una clase ofrece a sus clientes. Un objeto puede realizar cinco tipos de operaciones sobre otro, con el proposito de provocar una reacción:
  1. Modificador: altera el estado de un objeto.
  2. Selector: accede al estado de un objeto, sin alterarlo.
  3. Iterador: permite a todas las partes de un objeto ser accedidas en un orden.
  4. Constructor: crea un objeto y/o inicializa su estado.
  5. Destructor: libera el estado de un objeto y/o destruye el objeto.
C++ soporta, ademas de las operaciones, subprogramas libres. En la terminología de C++ las operaciones que un cliente puede realizar sobre un objeto se declaran como funciones miembro.

Relaciones entre objetos Las relaciones entre objetos abarcan las operaciones, resultados y suposiciones que unos hacen sobre los otros.
  1. Links Son conexiones físicas o conceptuales entre objetos. Denota la asociación específica por la que un objeto (cliente) usa o solicita el servicio de otro objeto (servidor). El paso de mensajes entre objetos los sincroniza.
  2. Agregaciones Denota relaciones todo/parte, con capacidad para governar desde el todo las partes. Es equivalente a la relación "tener un". El todo puede contener a la parte.
Agregación es conveniente en las ocasiones en que el encapsulamiento de las partes es prioritario. Si se requiere que las relaciones entre objetos esten vagamente acopladas, se utilizan links.

Clases Una clase es un conjunto de objetos que comparten una estructura y comportamiento comunes.
  • Clase representa una abstracción, la esencia que comparten los objetos.
  • Un objeto es un ejemplo de una clase.
  • Un objeto no es una clase, y una clase no es un objeto (aunque puede serlo, p.e. en Smalltalk).
  • Las clases actuan como intermediarias entre una abstracción y los clientes que pretenden utilizar la abstracción. De esta forma, la clase muestra:
    1. visión externa de comportamiento (interface), que enfatiza la abstracción escondiendo su estructura y secretos de comportamiento.
    2. visión interna (implementación), que abarca el código que se ofrece en la interface de la clase.

Relaciones entre clases Representan tipos de compartición entre clases, o relaciones semánticas.
  1. Asociación. Indica relaciones de mandato bidireccionales (Punteros ocultos en C++). Conlleva dependencia semántica y no establece una dirección de dependencia. Tienen cardinalidad.
  2. Herencia. Por esta relación una clase (subclase) comparte la estructura y/o comportamiento definidos en una (herencia simple) o más (herencia múltiple) clases, llamadas superclases.
    • Representa una relación del tipo "es un" entre clases.
    • Una subclase aumenta o restringe el comportamiento o estructura de la superclase (o ambas cosas).
    • Una clase de la que no existen ejemplos se denomina {\it abstracta}.
    • C++ declara como virtuales todas aquellas funciones que quiere modificar en sus subclases.
  3. Agregación. Representa una relación del tipo "tener un" entre clases. Cuando la clase contenida no existe independientemente de la clase que la contiene se denomina agregación por valor y además implica contenido físico, mientras que si existe independientemente y se accede a ella indirectamente, es agregación por referencia.
  4. Uso. Es un refinamiento de la asociación donde se especifica cual es el cliente y cual el servidor de ciertos servicios, permitiendo a los clientes acceder sólo a las interfaces públicas de los servidores, ofreciendo mayor encapsulación de la información.
  5. Ejemplificación Se usa en lenguajes que soportan genericidad (declaración de clases parametrizadas y argumentos tipo template). Representa las relaciones entre las clases parametrizadas, que admiten parámetros formales, y las clases obtenidas cuando se concretan estos parámetros formales, ejemplificados o inicializados con un ejemplo.
  6. Metaclases Son clases cuyos ejemplos son a su vez clases. No se admiten en C++.

Relaciones entre clases y objetos
  • Todo objeto es el ejemplo de una clase, y toda clase tiene 0 ó más objetos.
  • Mientras las clases son estáticas, con semántica, relaciones y existencia fijas previamente a la ejecución de un programa, los objetos se crean y destruyen rápidamente durante la actividad de una aplicación.
El diseño de clases y objetos es un proceso incremental e iterativo. Debe asegurar la optimización en los parámetros:
  1. Acoplamiento: Grado de acoplamiento entre módulos.
  2. Cohesión: Mide el grado de conectividad entre elementos de un módulo, y entre objetos de una clase.
  3. Suficiencia: Indica que las clases capturan suficientes características de la abstracción para conseguir un comportamiento e interacción eficiente y con sentido.
  4. Completitud: Indica que la interface de la clase captura todo el significado característico de una abstracción, escrito en el mínimo espacio.
  5. Primitividad: Las operaciones deben implementarse si dan acceso a una representación fundamental de la abstracción. Cuales son operaciones primitivas y cuales no (se pueden realizar a partir de otras) es un asunto subjetivo y afecta a la eficiencia en la implementación.


Metodos 
métodos: conjunto de instrucciones a las que se les asocia un nombre de modo que si se desea ejecutarlas, sólo basta o referenciarlas a través de dicho nombre en vez de tener que escribirlas.
Dentro de estas instrucciones es posible acceder con total libertad a la información almacenada en los campos, pertenecientes a la clase dentro de la que el método se ha definido. Por lo que los métodos permiten manipular los datos almacenados en los objetos.
Sintaxis:
()
{
instrucciones;
}
Tipo devuelto: Todo método puede devolver un objeto como resultado de la ejecución de las instrucciones que lo forma, aquí de indica el tipo del dato al que pertenece este objeto.
Si no devuelve nada se indica “void” y si devuelve algo es obligatorio finalizar la ejecución de sus instrucciones con “return ” que indica el objeto a devolverse.
Parámetro: opcionalmente todo método puede recibir en cada llamada una lista de objetos a los que podrá acceder durante la ejecución de sus instrucciones. Aquí se indica cuáles son los tipos de datos de estos objetos y cuál es el nombre con el que harán referencia las instrucciones de método a cada uno de ellos.
Aún que l objeto que puede recibir el método pueden ser diferentes, cada vez que se solicite su ejecución siempre han de ser los mismos tipos y han de seguir el orden establecido en parámetros.
ejemplo:
class persona
{
string nombre;
int edad;
string RFC;
void cumpleaños ()
{
edad ++;
}
}



Parámetros y Argumentos 
Parámetros y argumentos (programación): Un argumento o parámetro es el medio a partir del cual podemos expandir el ámbito de variables locales de funciones, hacia otras funciones y además quienes nos permiten establecer comunicaciones entre funciones. Si nos vemos ante la necesidad de visualizar o modificar el valor de una variable local en otra función que llamaremos, debemos invocar a dicha función haciendo referencia de su nombre, seguido de los parámetros o nombres de variables para las cuales, en teoría ampliaríamos su ámbito.
Las palabras parámetro y argumento, aunque de significado similar, tiene distintas connotaciones semánticas: Se denominan parámetros los tipos declarados en el prototipo (que deben corresponder con los declarados en la definición). Cuando se realiza una llamada a la función, los "valores" pasados se denominan argumentos. A veces se utilizan también las expresiones argumentos formales, para los parámetros y argumentos actuales para los valores pasados.

 Parámetros (en prototipo o definición)   argumentos formales
 Valores pasados (en tiempo de ejecución)   argumentos actuales

Sintaxis

La sintaxis utilizada para la declaración de la lista de parámetros formales es similar a la utilizada en la declaración de cualquier identificador. Ejemplos:
int func(void) {...}                  // sin parámetros
int func() {...}                      // ídem.
int func(T1 t1, T2 t2, T3 t3=1) {...} // tres parámetros simples,
                                     // uno con argumento por  defecto
int func(T1* ptr1, T2& tref) {...}    // los argumentos son un puntero y
                                     // una referencia.
int func(register int i) {...}        // Petición de uso de registro para
                                     // argumento (entero)
int func(char* str,...) {...}         /* Una cadena y cierto número de otros
            
argumentos, o un número fijo de argumentos de tipos  variables */
Los argumentos son siempre objetos. Sus tipos pueden ser: escalares; estructuras; uniones, o enumeraciones; clases definidas por el usuario; punteros o referencias a estructuras y uniones, o punteros a funciones, a clases o a matrices. El tipo void está permitido como único parámetro formal. Significa que la función no recibe ningún argumento. Todos los parámetros de una función tienen ámbito del bloque de la propia función y la misma duración automática que la función.
El único especificador de almacenamiento que se permite es register. En la declaración de parámetros también pueden utilizarse los modificadores volatile y const. Este último se utiliza cuando se pasan argumentos por referencia y queremos garantizar que la función no modificará el valor recibido. Ejemplo:

 int dimension(X x1, const X& x2)      // x2 NO se puede modificar!!

Argumentos por defecto

C++ permite tener valores por defecto para los parámetros. Esto supone que, si no se pasa el parámetro correspondiente, se asume un valor predefinido. La forma de indicarlo es declararlo en el prototipo de la función, como se muestra en el ejemplo (ambas expresiones son equivalentes).
 float mod (float x, float y = 0);
 float mod (float, float = 0);
Un argumento por defecto no puede ser repetido o cambiado en una siguiente declaración dentro del mismo ámbito. Por ejemplo:
void func (int x = 5);
...
void func (int x = 5);    // Error: repetición de argumento por defecto
{                         // nuevo ámbito
   void func (x = 7);    // L.4 Correcto: esta función oculta a la anterior
}                         // el ámbito anterior vuelve a ser visible
void func (x = 7);        // Error: cambiar argumento por defecto

La gramática de C++ exige que los parámetros con valores por defecto deben ser los últimos en la lista de parámetros, y que si en una ocasión falta algún argumento, los que le siguen también deben faltar (adoptar también los valores por defecto). Los argumentos por defecto de métodos (funciones-miembro de clases) no pueden ser otros miembros a no ser que sean estáticos. Los argumentos por defecto no pueden ser otros argumentos:

x = somefunc (int x, int y = x);    // Error!

Los argumentos pasados por referencia solo pueden adoptar valores por defecto, estáticos, globales, o de un subespacio cualificado.

Argumentos: por valor y por referencia

Existen dos formas de pasar argumentos a las funciones: por valor y por referencia. El primero es utilizado por defecto con la declaración usual de parámetros. En el paso "por valor", se crean copias de los argumentos pasados a la función, los cuales, junto a las variables locales (incluyendo el posible valor devuelto), y la dirección de vuelta a la rutina que efectúa la invocación, son pasados a la pila en la secuencia de llamada. Más tarde, cuando termina su ejecución definitivamente, es decir, cuando el control vuelve a la función que la invocó, toda esta información es sacada de la pila mediante la secuencia de retorno (y se pierde). Estos procesos suponen un consumo de tiempo y espacio (memoria), a veces considerable.

Paso por valor

Hemos visto que el paso de parámetros por valor significa que existen copias de los argumentos formales (estas copias son variables locales de la función llamada), y que una función no puede alterar ninguna variable de la función que la invocó.
  • La única excepción es el caso de las matrices. Cuando se utiliza una matriz como argumento en la llamada a una función, el valor pasado es un puntero a la dirección de memoria del principio de la matriz.
Cuando los argumentos pasan por valor pero no hay concordancia entre el tipo de los argumentos actuales y los argumentos formales utilizados en la declaración de la función, entonces se produce un modelado de tipo antes de la asignación.

Pasar un puntero

En C clásico, cuando se desea que la función llamada pueda alterar el valor de variables de la función que la invoca, o ahorrar el espacio que supone la copia local de los argumentos (que pueden ser estructuras de datos muy grandes), la solución consistía en utilizar punteros a las variables respectivas como argumentos para la función (en vez de pasar las variables en sí mismas). A su vez, la función llamada debía declarar el parámetro como puntero, y acceder a la variable indirectamente a través de él. En otras palabras: cuando en C se desea que un valor X pase a una función F y que esta pueda alterar el valor de X en la función que la invocó, el argumento utilizado es &X (la dirección de X). De esta forma, aunque F recibe una copia de &X, puede alterar el valor original a través de esta dirección. Esta técnica puede tener sus ventajas. Por ejemplo, si X es una estructura muy grande, pero puede tener efectos colaterales peligrosísimos y ser una fuente de errores difíciles de detectar.

Paso por referencia

C++ permite utilizar la técnica del C clásico descrita arriba, pero también utilizar el paso de argumentos por referencia (en realidad es una variante semántica del proceso anteriormente descrito). Para ello se utiliza el declarador de referencia &. Las referencias presentan las ventajas de los punteros, en el sentido que permiten modificar los valores de los objetos pasados como argumento, y de que permiten ahorrar espacio si hay que pasar objetos muy grandes, pero no presentan los peligros potenciales de aquellos. En caso necesario las referencias pueden declararse constantes, indicando así que la función invocada no modificará estos valores. En estos casos, la utilización de referencias obedece casi exclusivamente a razones de eficacia en el mecanismo de llamada.

Comparativa

A continuación se muestran tres implementaciones de una misma función; cada una con una forma distinta para paso del argumento.
Implementación-1: Sistema clásico, paso "por valor"
int pru1(int n) {   // n entero; pasa "por valor"
  return 3 * n;
}
...
int x, i = 4;
x = pru1(i);        // ahora: x = 12, i = 4
int& ry = i;
x = pru (ry);       // ahora: x = 12, i = 4

La última sentencia no es un paso por referencia, sino por valor (a pesar de que el argumento actual sea una referencia).
Implementación-2: Sistema clásico, paso de "punteros por valor" (seudo-referencia)

void pru2(int* np) {  // np puntero-a-entero; pasa "por valor"
  *np = (*np) * 3;
}
 . . .
int x = 4;
pru2(&x);             // ahora x = 12
En este caso, pasar el valor &x (dirección de x) como argumento, es equivalente a pasar un puntero a dicha variable (que es lo exigido en la definición de pru2). Es decir, la última línea se puede sustituir por las siguientes:
int* ptr = &x         // define puntero-a-x
pru2(ptr);            // pasa el puntero como argumento
Implementación-3: Sistema C++, paso "por referencia"

void pru3(int& n) { // n tipo "referencia-a-int"; pasa "por  referencia"
  n = 3 * n;
}
 . . .
int x = 4;
pru3(x);            // ahora x = 12

En este último caso, la declaración int& n como parámetro de la función pru3, establece que este n sea declarado como "referencia-a-entero", de forma que cuando se pasa el argumento x, la función crea un valor n que es una especie de alias o espejo de x, de forma que la expresión n = 3*n tiene el mismo efecto que x = 3*x. 
En la declaración de una referencia, cuando el iniciador es una constante, o un objeto de tipo diferente que el referenciado, se crea un objeto temporal para el que la referencia actúa como un alias. Esta creación de objetos temporales es lo que permite la conversión de tipos referencia-a-tipoX cuando se utilizan como parámetros de funciones y no hay concordancia entre el valor recibido y el esperado (suponiendo que exista posibilidad de conversión).


                           Retorno de valores

Métodos con valor de retorno
Los métodos con valor de retorno son módulos de programa que pueden recibir datos de entrada por medio de variables locales (parámetros) y posteriormente retorna un resultado al punto donde es llamado. Este tipo de métodos se utiliza para operar cualquier tipo de proceso que produzca un resultado.

Los métodos con valor de retorno se clasifican en dos tipos:

  • Métodos con valor de retorno sin parámetros.
  • Métodos con valor de retorno con parámetros.
1. Métodos con valor de retorno sin parámetros
Este tipo de métodos no reciben datos de entrada; pero de igual forma retornan un resultado al punto donde son llamados.



Su definición es de la siguiente manera:
tipo nombreMetodo(){
          Declaracion de variables locales
          Cuerpo del método
          return valor;
}

Donde:
  • valor: Es el valor que es retornado por el método.
  • tipo: Es el tipo del valor de retorno.
Invocación (llamado):
variable = nombreMetodo();
Donde:
  • variable: Es la variable que recibe el valor retornado por el método.


2. Métodos con valor de retorno con parámetros
Este tipo de métodos reciben datos de entrada por medio de parámetros y retornan un resultado al pundo de su llamado.


Su definición es de la siguiente manera:

tipo nombreMetodo(tipo1 p, tipo2 q, tipo3 r, ...){
          Declaración de variables locales
          Cuerpo del método
          return valor;
}

Donde:
tipo: Es el tipo de valor de retorno.
p, q, r, ... : son los nombres de los parámetros.
tipo1, tipo2, tipo3, ... : son los tipos de datos de los parámetros.
valor: es el valor de retorno.

Invocación (llamado):
variable = nombreMetodo(v1, v2, v3, ...);

Donde:
variable: Es el nombre del método llamado.
v1, v2, v3, ... : Son los valores dados a los parámetros.

Ejemplo (métodos con valor de retorno con parámetros): convertir cantidad dada en segundos en HH:MM:SS

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class HHMMSS extends JApplet implements ActionListener{

          JButton btnCal, btnRes;
          JLabel lblSeg;
          JTextField txtSeg;
          JTextArea txtA;
          JScrollPane scpScroll;

          public void init(){
                    getContentPane().setLayout(null);
                    getContentPane().setBackground(Color.darkGray);

                    lblSeg = new JLabel("SEGUNDOS:");
                    lblSeg.setBounds(20,20,90,23);
                    lblSeg.setForeground(Color.white);
                    lblSeg.setFont(new Font("arial",1,14));
                    getContentPane().add(lblSeg);

                    txtSeg = new JTextField();
                    txtSeg.setBounds(120,20,100,23);
                    txtSeg.setBackground(new Color(255,200,0));
                    txtSeg.setFont(new Font("arial",1,14));
                    getContentPane().add(txtSeg);

                    btnCal = new JButton("CALCULAR");
                    btnCal.setBounds(20,53,100,23);
                    btnCal.addActionListener(this);
                    getContentPane().add(btnCal);

                    btnRes = new JButton("RESET");
                    btnRes.setBounds(120,53,100,23);
                    btnRes.addActionListener(this);
                    getContentPane().add(btnRes);

                    txtA = new JTextArea();
                    txtA.setFont(new Font("arial",1,16));
                    txtA.setBackground(Color.darkGray);
                    txtA.setForeground(Color.green);
                    txtA.setEditable(false);

                    scpScroll = new JScrollPane(txtA);
                    scpScroll.setBounds(20,86,200,80);
                    getContentPane().add(scpScroll);
          }

          public void actionPerformed(ActionEvent e){
                    if(e.getSource()==btnCal)
                              hms();
                    if(e.getSource()==btnRes)
                              reset();
          }

          void hms(){
                    txtA.setText("");
                    int cantSeg = getSegundos(),
                    hor = horas(cantSeg),
                    min = minutos(cantSeg),
                    seg = segundos(cantSeg);
                    imprimir("Resultado:");
                    imprimir("----------------\n");
                    txtA.append("HH:MM:SS >> "+hor+":"+min+":"+seg);
          }

          void reset(){
                    txtA.setText("");
                    txtSeg.setText("");
                    txtSeg.requestFocus();
          }

          //Métodos con valor de retorno con parámetros
          int horas(int seg){
                    int h = seg/3600;
                    return h;
          }

          int minutos(int seg){
                    int m = (seg%3600)/60;
                    return m;
          }

          int segundos(int seg){
                    int s = (seg%3600)%60;
                    return s;
          }

          //Método que retorna el valor numérico entero de la caja de texto
          int getSegundos(){
                    int cs;
                    //donde cs: cantidad de segundos.
                    //Se realiza la validación de datos empleando TRY - CATCH
                    try{ cs = Integer.parseInt(txtSeg.getText());}
                    catch(Exception e){ cs = 0;}
                    return segundos;
          }

          void imprimir(String cad){
                    txtA.append(cad+"\n");
          }
}



Método constructor
















Comentarios