Programación Orientada a Objetos en Java

260  Descargar (0)

Texto completo

(1)

Luis Fernando

García

Llinás

ientada

a objetos en Java

¨

de la

para la codificación

(especialmente usando el lenguaje C),

y que, además, deseen aprender acerca

del desarrollo de aplicacione

s orientadas

a objetos en Java

®

, sin neces

idad de leer

la abundante y extensa literatura

que,

por lo general, contienen

los manuales

y guías de usuarios. Precisamente, la

síntesis y la precisión de la información,

es uno de los atractivos de este texto

que

compila en 260 páginas los contenidos

básicos para un curso de programación

orientada a objetos en Java

®

.

Programaci—

n orientada a objetos en Java

¨

Luis Fernando

García

Llinás

Luis F

ernando

García

Llinás

Aplicar el programa orientado

a objetos

Codificar interfaces y gráficas

de usuario sencillas y

atractivas

Diseñar a partir de teorías

básicas

Ejemplos y casos prácticos

Ingeniero de Sistemas, Universidad del Norte (Barranquilla). Magíster

en Ingeniería de Sistemas y Computación con énfasis en Ingeniería de

Información, Universidad de los Andes (Bogotá). Desde el 2005 está

vinculado a la Universidad del Norte como docente del Departamento de

Ingeniería de Sistemas y Computación, y actualmente hace parte del grupo de

investigación “Redes de Computadores e Ingeniería de Software - GReCIS”

(2)
(3)
(4)
(5)

a objetos en Java®

LUIS FERNANDO GARCÍA LLINÁS

(6)

© Ediciones Uninorte, 2010 © Ediciones de la U, 2010

© Luis Fernando García Llinás, 2010

Coordinación editorial Zoila Sotomayor O. Diseño y diagramación Nilson Ordoñez Diseño de portada Álvaro Bernal Corrección de textos Mercedes Castilla 258 p. ; 16 x 24 cm. ISBN 978-958-741-062-4

1. Java (Lenguaje de programación de computadores). 2. Programación orientada a objetos (Computadores). I. Tít.

(005.117 G216 Ed. 22) (CO-BrUNB)

www.uninorte.edu.co

Km 5 vía a Puerto Colombia, A.A. 1569, Barranquilla (Colombia)

http://edicionesdelau.com/ Calle 24A n.° 43-22 Bogotá (Colombia)

Impreso y hecho en Colombia X-press Proceso

Bogotá

(7)

1. TÓPICOS BÁSICOS ...1

1.1. Sobre el paradigma de programación estructurada o procedimental ... 1

1.2. Objeto ... 5

1.3. Clase ... 6

1.4. Atributo ... 7

1.5. Instanciación ... 12

1.6. Método ... 22

Método constructor, 29

1.7. Encapsulamiento ... 39

1.8. Atributos finales ... 52

1.9. Atributos y métodos estáticos ... 54

1.10. Herencia ... 59

1.11. Métodos y clases abstractas ... 96

1.12. Casting ... 105

1.13. Polimorfismo ... 107

1.14. Métodos y clases finales ... 114

1.15. Herencia simple y múltiple ... 123

(8)

2. TÓPICOS AVANZADOS ...135

2.1. Colecciones ... 136

Listas, 144. Conjuntos, 154. Mapas, 157. Genéricos, 159.

2.2. Manejo de excepciones ... 171

Generación y lanzamiento de excepciones, 174. Captura de excepciones, 177. Definición de excepciones personales, 179.

3. CREACIÓN DE INTERFACES GRÁFICAS DE USUARIO ...199

3.1. Componentes gráficos ... 201

3.2. Layouts ... 208

FlowLayout, 209. GridLayout, 211. BorderLayout, 213.

3.3. Bordes ... 221

3.4. Manejo de eventos ... 226

(9)

El aprendizaje del paradigma de la programación orientada a objetos presenta considerables

problemas a quienes están acostumbrados a trabajar bajo el paradigma estructurado, sobre

todo cuando estos tienen varios años de experiencia. Quizás el cambio de mentalidad que se

requiere o la gran cantidad de nociones que surgen acentúan esta situación.

Inicialmente la programación orientada a objetos puede llegar a verse como un paradigma

complejo o complicado, aun cuando en realidad lo que busca es organizar de mejor manera

el código de una aplicación desarrollada con el enfoque procedimental. Esto con el fin de

facilitar su entendimiento y, por ende, si es necesario, su modificación.

La metodología que se emplea en este libro para introducir los tópicos consiste en plantear

un problema sumamente sencillo, luego entrar a resolverlo empleando la programación

estructurada y después de forma progresiva ir desarrollando la aplicación empleando la

programación orientada a objetos. Durante este proceso se van introduciendo cada una de

las nociones más importantes para adicionarlas al desarrollo de la solución (en algunos

casos se presentan más ejemplos para lograr un mejor entendimiento de cada uno de los

tópicos). Es realmente importante analizar cómo se va configurando la solución orientada a

objetos y compararla con la solución estructurada.

O

bjetivOs

Ser conciso. Uno de los principales objetivos de este libro era escribirlo de manera

sumamente concisa, es decir que no excediera las 250 páginas. Por eso únicamente

se tocan los temas básicos de la codificación de aplicaciones orientadas a objetos

empleando a Java como lenguaje de programación. Por consiguiente, se excluyen

temas como el trabajo con redes, la interacción con bases de datos, el desarrollo de

aplicaciones para la web, etc.

Servir como punto de partida. En ningún momento este libro pretende reemplazar

textos más robustos y completos que tratan estos y muchos otros tópicos. Más bien se

presenta como un punto de partida para los programadores y un eficaz complemento

de otros textos, pues en la medida en que se comprenda la totalidad de esta obra será

(10)

¿A

quiénvAdirigidOestelibrO

?

Este libro fue ideado como texto guía para un curso de programación orientada a objetos

donde llegan estudiantes con nociones básicas de programación y conocimiento de la

teoría de algunas estructuras de datos. Por consiguiente, la obra se dirige especialmente a

programadores que emplean el paradigma procedimental como principal aproximación a la

codificación de soluciones (sobre todo empleando C como lenguaje de programación), y que

desean aprender las nociones del desarrollo de aplicaciones orientadas a objetos empleando

Java.

¿q

uéserequiereAntesdeleerlO

?

Descargar e instalar la máquina virtual de Java que puede ser obtenida de forma

gratuita de la web oficial de Sun (http://java.sun.com/javase/downloads/index.

jsp)

Leer del Tutorial oficial de Java (http://java.sun.com/tutorial) los apartados que

llevan por títulos “About the Java Technology” (http://java.sun.com/docs/books/

tutorial/getStarted/intro/definition.htm) y “Hello World! For Microsoft Windows”

(http://java.sun.com/docs/books/tutorial/getStarted/cupojava/win32.html).

Descargar e instalar un entorno de desarrollo (IDE) para Java. Esto facilitará en gran

medida la codificación de los ejemplos. Existen muchos entornos gratuitos entre

los que sobresalen: Netbeans (http://www.netbeans.org/), JDeveloper (http://

www.oracle.com/technology/products/jdev/index.html), y Eclipse (http://www.

eclipse.org/).

O

rgAnizAción

El libro está organizado en tres capítulos.

En el primer capítulo se presentan los tópicos básicos de la programación orientada a

objetos. También se analizan las nociones necesarias para la creación de aplicaciones

orientadas a objetos sumamente básicas.

En el segundo capítulo se presentan unos tópicos un poco más avanzados de la

teoría de objetos. Aquí las nociones analizadas posibilitan la creación de aplicaciones

mas robustas y completas orientadas a objetos.

En el tercer capítulo se presentan las teorías básicas para diseñar y codificar interfaces

gráficas de usuario sencillas y moderadamente atractivas.

Adicionalmente, en todos estos capítulos se incluye un conjunto de apartados donde se

presentan explicaciones más amplias, aclaraciones pertinentes o simplemente ejemplos más

completos de los tópicos que se abordan.

r

etrOAlimentAción

Cualquier comentario, observación, sugerencia o recomendación que se desee efectuar

sobre la presente obra será bien recibida en las siguientes direcciones de correo electrónico:

(11)

1.

TÓPICOS BÁSICOS

1.1. s

Obre

el

pArAdigmA

de

prOgrAmAción

estructurAdA

O

prOcedimentAl

Dentro del mundo del desarrollo de aplicaciones bajo el paradigma estructurado (también

conocido como programación procedimental o tradicional) la idea general consiste en

especificar el conjunto de instrucciones que brindan solución a un problema específico; este

conjunto de instrucciones se definen al interior de las marcas de inicio y fin del bloque

de codificación principal del algoritmo. Durante el aprendizaje de este paradigma de

programación las recomendaciones iniciales son: entender el problema, definir las variables

globales que harán parte de la solución, identificar aquellas secciones de código que

conviene incluirlas dentro de funciones o subrutinas para futura reutilización, definir datos

de entrada y de salida, entre otras.

Suponga que ha sido encargado del desarrollo de la aplicación de software a una compañía

que la desea para efectuar el cálculo mensual de su nómina. Esta compañía contrata

empleados a quienes les paga dependiendo del número de horas trabajadas y del valor por

hora convenido previamente con cada uno. Como información básica de cada empleado

debe registrarse el número de la cédula, su nombre y su apellido.

Aclaraciones:

Tanto el valor del número de horas trabajadas por cada empleado como el valor de

(12)

Para efectos de mantener la simplicidad del ejemplo no se contemplan acciones para

manejar la persistencia

1

de los datos.

A continuación una posible solución al problema planteado empleando el paradigma

estructurado.

Inicio

Entero: numeroEmpleados, i

Caracteres: cedulas[50], apellidos[50], nombres[50] Real: horasTrabajadas[50], sueldoXHora[50]

Caracteres: cedula, apellido, nombre Real: horas, sueldo

Real: total <- 0

Esc ‘Digite número de empleados: ‘ Lea numeroEmpleados

Para i=0,numeroEmpleados-1,1

Esc ‘Digite la cédula del empleado: ‘ Lea cedula

Esc ‘Digite el apellido del empleado: ‘ Lea apellido

Esc ‘Digite el nombre del empleado: ‘ Lea nombre

Esc ‘Digite número de horas trabajadas del empleado: ‘ Lea horas

Esc ‘Digite valor de sueldo por hora del empleado:’ Lea sueldo cedulas[i] <- cedula apellidos[i] <- apellido nombres[i] <- nombre horasTrabajadas[i] <- horas sueldoXHora[i] <- sueldo Fin-Para

Para i=0, numeroEmpleados-1, 1

total <- total + horasTrabajadas[i] * sueldoXHora[i] Fin-Para

Esc ‘La nómina total es: ‘ + total Fin

Entender el anterior seudocódigo no debe presentar mayores problemas para cualquier

programador. Sin embargo, es conveniente realizar las siguientes aclaraciones y comentarios:

Aunque se puede condensar el código incluyendo las instrucciones del segundo

‘Para’ dentro del primero, de manera intencional se ha dejado así intencionalmente

para delimitar funcionalmente cada bloque de código.

En el algoritmo se captura información, como la cédula, el nombre y el apellido,

(13)

que no se utiliza; sin embargo esta información se mantiene porque posteriormente

puede ser útil para ampliar la funcionalidad de la aplicación.

Como la intención es que sea un ejemplo didáctico, inicialmente el algoritmo no

contempla validaciones como impedir el doble ingreso de un mismo número de

cédula.

C

odifiCaCiónen

J

avadelalgoritmoparaelCálCulodelanómina empleandoprogramaCiónestruCturada

Se presenta a continuación la codificación del ejemplo anterior aunque apenas se estén dando

los primeros pasos en el aprendizaje del lenguaje de programación Java. Esto porque es más

sencillo aprender a través de ejemplos y del establecimiento de analogías, asociaciones y

comparaciones.

import java.io.BufferedReader; import java.io.InputStreamReader; class Nomina {

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

int numeroEmpleados;

String[] cedulas = new String[50]; String[] apellidos = new String[50]; String[] nombres = new String[50];

double[] horasTrabajadas = new double[50]; double[] sueldoXHora = new double[50]; String cedula, apellido, nombre; double horas, sueldo;

double total = 0;

BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );

System.out.print(“Digite numero de empleados: “);

numeroEmpleados = Integer.valueOf(br.readLine()).intValue(); for(int i=0;i<numeroEmpleados;i++){

System.out.print(“\nDigite la cedula del empleado: “ ); cedula = br.readLine();

System.out.print(“Digite el apellido del empleado: “ ); apellido = br.readLine();

System.out.print(“Digite el nombre del empleado: “ ); nombre = br. ();

System.out.print(“Digite num de horas trabajadas del empleado: “); horas = Double.valueOf(br.readLine()).doubleValue();

(14)

sueldo = Double.valueOf(br.readLine()).doubleValue(); cedulas[i] = cedula; apellidos[i] = apellido; nombres[i] = nombre; horasTrabajadas[i] = horas; sueldoXHora[i] = sueldo; }

for (int i=0;i<numeroEmpleados;i++)

total = total + sueldoXHora[i]*horasTrabajadas[i];

System.out.println(“\nLa nómina total es: “+ total); }

}

Del código anterior vale la pena resaltar algunos puntos:

Las dos primeras líneas donde aparecen instrucciones

import

sirven para importar

componentes necesarios para la lectura de datos por pantalla.

La instrucción

public static void main(String args[])

corresponde a la

definición del método principal.

El tipo de dato en Java

double

se corresponde con el tipo

Real

en el seudocódigo; el

tipo de dato en Java

String

se corresponde con el tipo

Caracteres

en seudocódigo; y

el tipo de dato

int

en Java se corresponde con el tipo de dato

Entero

en seudocódigo.

La lectura de información por pantalla requiere la configuración de un componente de

tipo

BufferedReader

.

La instrucción que permite leer información de la pantalla (lo que en seudocódigo se

escribe como la instrucción

Lea

, o en C la instrucción

cin

) corresponde a la función

readLine()

. Esta función siempre devuelve lo que digita el usuario como una cadena

de caracteres; si se desea trabajar con un tipo de dato distinto, deben realizarse

conversiones adicionales.

La instrucción que permite escribir información en pantalla (lo que en seudocódigo se

escribe como la instrucción

Esc

, o en C la instrucción

cout

) corresponde a la función

System.out.println()

.

El carácter de escape ‘\n’ corresponde al retorno de carro y

nueva línea

.

El segundo bloque ‘for’ no define llave de apertura(

{

) y de cierre(

}

), debido a que solo

posee una línea de código.

La concatenación de un número a una cadena de caracteres se realiza con el simple uso

(15)

Es conveniente identificar cómo es el manejo de los arrays en Java y cómo se realiza la

conversión entre tipos de datos.

En Java, los índices de los arrays comienzan en el valor 0; es por ello que los contadores

de los bloques de código ‘Para’ se inicializan en dicho valor, y llegan hasta el valor

menos 1.

1.2. O

bjetO

Dentro del paradigma de desarrollo de aplicaciones orientadas a objetos cambia el enfoque

de la solución. Lo importante para el paradigma procedimental o estructurado es el bloque

de código principal (instrucciones dentro de la marca de inicio y fin). Para el paradigma

orientado a objetos lo principal es entender y modelar el problema, y luego sí definir el

bloque de código principal que empleando el modelo definido brinde solución al problema

específico.

La programación orientada a objetos requiere inicialmente identificar y modelar cada uno de

los entes que hace parte del problema. Facilita la comprensión del tema hacerse una imagen

mental de una posible situación; por ejemplo, para el caso del cálculo de la nómina suponga

que la empresa cuenta únicamente con tres empleados cuya información se muestra en el

siguiente gráfico.

Para un programador con poca experiencia en la orientación a objetos es moderadamente

sencillo identificar que para el caso anterior los entes que toman parte del problema

(16)

empleado en la empresa, aparecerá otro objeto que seguramente poseerá las características

descriptivas de cédula, apellido, nombre, sueldo por hora y horas trabajadas, y demás

valores para dichas características.

Es conveniente presentar una definición para la noción de objeto.

Definición de objeto

Un objeto es un concepto, abstracción o cosa con límites bien definidos y con

significado dentro del problema.

Como se puede apreciar la definición de objeto es realmente amplia pues en realidad

cualquier cosa puede ser un objeto. De allí que puedan existir objetos que representen cosas

concretas (como automóviles, casas, libros, etc.) y objetos que representan cosas abstractas

(como pensamientos, ideas, etc.).

1.3. c

lAse

Para traducirlo a algún lenguaje de programación se requiere una estructura de datos a fin

de almacenar la información de cada uno de los objetos del problema. Sin embargo, no tiene

sentido definir una estructura de datos independiente para cada uno de los posibles objetos

de tipo empleado (como, por ejemplo, EstructuraTrabajor1, EstructuraTrabajador2, etc.), es

más conveniente definir una única estructura de datos que pueda servir para almacenar la

información de cualquier objeto del mismo tipo. La siguiente tabla muestra la información

que debe permitir registrar esta estructura genérica y su correspondiente tipo de dato.

Campo

Tipo dato

Descripción

cédula

Caracteres

En este campo se registra el número de la cédula de

ciudadanía de un empleado.

apellido

Caracteres

En este campo se registra la cadena de caracteres que

corresponde al apellido de un empleado.

nombre

Caracteres

En este campo se registra la cadena de caracteres que

corresponde al nombre de un empleado.

horasTrabajadas

Real

En este campo se registra el número de horas trabajadas

por un empleado; por ejemplo, el valor de 1.5 indica que

el empleado ha trabajado una hora y media (90 minutos).

sueldoXHora

Real

En este campo se registra el valor que debe ser pagado a

(17)

Definición de clase

Una clase describe a un conjunto de objetos que comparten una estructura y un

comportamiento común.

Una clase es un molde o plantilla que indica cómo será un objeto de dicha clase. En el área de

la construcción, una clase podría ser el plano de una casa que indica la estructura que debe

tener cada una de las casas, y los objetos son la materialización de las casas construidas a

partir de dicho plano. Es por ello que se define a un objeto como una instancia de una clase.

Para definir una clase en Java se utiliza la palabra reservada ‘

class

. La sintaxis de dicha

instrucción requiere además de la especificación de un nombre para la clase. La comunidad

de programadores de Java maneja una convención de nombramiento para las clases (más

que una regla es una simple sugerencia); dicha convención establece que el nombre de la

clase debe escribirse todo en minúsculas a excepción de la primera letra del nombre de la

clase. Si para establecer el nombre de la clase se requieren varias palabras se deben unir las

letras de todas las palabras y la primera letra de cada palabra debe estar en mayúscula (por

ejemplo,

EmpleadoDeEmpresa

). A continuación se presenta el código que permite definir en

Java la clase para describir a objetos tipo empleado.

class Empleado{ String cedula; String apellido; String nombre; double horasTrabajadas; double sueldoXHora; }

Cada uno de elementos incluidos dentro de una clase recibe el nombre de atributos.

1.4. A

tributO

Definición de atributo

Un atributo es una propiedad que ayuda a describir un objeto.

Es conveniente tener en cuenta lo siguiente:

Hasta el momento y con las definiciones dadas, dos objetos distintos, pero de la

(18)

El orden de definición de los atributos es irrelevante.

El concepto de atributo está estrechamente ligado al concepto de variable; en

realidad todo atributo es un tipo de variable, sin embargo, no toda variable que

pueda definirse en un programa en Java es un atributo.

Note que en Java para definir una variable se requiere, además de un nombre

2

, su tipo de

dato. La comunidad de programadores de Java maneja una convención de nombramiento

para los atributos (más que una regla es una sugerencia), con la cual establece que el nombre

del atributo debe escribirse en letras minúsculas. Si el nombre del atributo está compuesto

por varias palabras, se unen las letras de todas las palabras y se colocan en mayúsculas las

primeras letras de cada palabra a excepción de la primera letra del nombre del atributo (por

ejemplo, horasTrabajadas).

Básicamente los tipos de datos para los atributos (y variables) pueden ser de dos clases:

Tipo de dato primitivo

3

. Corresponde a un tipo de dato predefinido por el lenguaje.

Cuando se define un atributo (o variable) de este tipo, entonces hay que separar un

espacio en memoria para guardar su valor. Los ocho tipos de datos primitivos son:

byte

,

short

,

int

,

long

,

float

,

double

,

boolean

y

char

. Se hace relativamente sencillo

inferir el propósito de cada uno de ellos. Es conveniente resaltar que el tipo de dato

char

corresponde a un solo carácter, lo que significa que no existe un tipo de dato

primitivo en Java para una cadena de caracteres. La buena noticia es que existe

String

que no corresponde a un tipo de dato primitivo, sino a un tipo de dato de

referencia.

Tipo de dato de referencia. Corresponde a un objeto de una clase (no obligatoriamente

distinta a la definida). En este punto es donde radica gran parte de la importancia,

flexibilidad y reutilización del paradigma de orientación a objetos; porque cuando

se definen atributos cuyo tipo sea una clase, se amplía el espectro de posibilidades.

Cuando se define un atributo de este tipo no se separa espacio en memoria para

un nuevo objeto, sino que se define una referencia que apuntará a un espacio de

memoria con la estructura definida en la clase.

2 Detalles sobre la convención de nombramiento de variables pueden ser consultados en la siguiente referencia: http:// java.sun.com/docs/books/tutorial/java/nutsandbolts/variables.html

3 Mayor información sobre cada uno de estos tipos de datos puede ser consultada en la siguiente referencia: http://java. sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html

(19)

s

obrelaComposiCióndeobJetos

Uno de los pilares fundamentales de la programación orientada a objetos corresponde a la

reutilización. Aquí la idea fundamental no es reinventar la rueda cada vez que se necesite,

sino poder reutilizar la que ya esta inventada.

La siguiente podría ser una buena definición para la clase Casa.

class Casa{ String colorTecho; String tipoTecho; double largoTecho; double anchoTecho; double altoTecho; String colorParedes; String tipoParedes; int numeroDeVentanas; }

En la anterior definición el atributo

tipoTecho

hace referencia al material con que está

construido el techo de la casa, que puede tomar los valores de: paja, cinc, teja, etc.; similarmente,

el atributo

tipoParedes

hace referencia al material que compone las paredes de la casa, por

ejemplo: ladrillo, madera, barro, etc. El resto de la anterior definición de la clase

Casa

no es

demasiado compleja y la mayoría de los atributos se entienden fácilmente.

Una definición alternativa para modelar una casa podría ser la siguiente:

class Techo{ String color; String tipo; int largo; int ancho; int alto; }

(20)

class Pared{ String tipo; String color; } class Casa{ Techo elTecho; Pared lasParedes; int numeroDeVentanas; }

Note que en este caso para lograr la definición de la clase

Casa

ha sido necesaria la previa

definición de las clases

Techo

y

Pared

.

Adicionalmente cabe resaltar que en la clase

Casa

existe un atributo de tipo de referencia de clase

Techo

cuyo nombre es

elTecho

, y, además,

existe un atributo de tipo de referencia de la clase

Pared

de nombre

lasParedes

.

¿Cuál de las dos definiciones es la mejor? Depende del problema. La primera definición de la

clase

Casa

es simple y sencilla de trabajar, pero no muy reutilizable. La segunda es un poco

más compleja, aunque más reutilizable (imagine que se necesita la clase

Edificio

, para la cual

(21)

s

obreladefiniCiónymanipulaCióndelostiposdedatosprimitivosylosdereferenCia

Es realmente importante tener claridad sobre los tipos de datos de los atributos pues Java trata

de forma muy distinta a cada uno de ellos.

Imagínese un objeto de la clase

Casa

donde solo se utilicen datos primitivos (la primera

definición que aparece en el apartado sobre la composición de objetos). Java reservaría espacio

en memoria de la siguiente manera (el texto en la parte superior del rectángulo es simplemente

para denotar la clase del objeto)

:

: Casa

colorTecho = Negro

poTecho = teja

largoTecho = 15

anchoTecho = 10

altoTecho = 2.5

colorParedes = Rojo

poParedes = ladrillo

numeroDeVentanas = 3

Para la segunda definición de la clase

Casa

(en el ejemplo donde se usa composición en el

apartado sobre la composición de objetos), el mismo ejemplo anterior tendría la siguiente

representación:

Como se mencionó previamente para los atributos cuyo tipo de dato son de referencia no se

separan espacios en memoria, es decir, para atributos de tipo

Pared

,

Techo

y

String

.

En vez

de eso, se definen apuntadores a referencias de objetos de dichos tipos.

Simplemente por facilidad y para no complejizar innecesariamente las gráficas, a lo largo de

este libro se obviará la definición de objetos para los tipos de datos de referencia

String

,

es

(22)

Simplemente para hacer claridad en este último punto, la estructura en memoria para el objeto

de la clase

Casa

nunca es como se muestra en el siguiente gráfico.

La definición de clase hace referencia a dos puntos: primero, la estructura y segundo, el

comportamiento. La definición de la estructura de los objetos de una clase se consigue a

través del establecimiento de sus atributos.

1.5. i

nstAnciAción

Es conveniente introducir en estos momentos la instrucción que posibilita la instanciación

de una clase, de tal manera que se pueda crear un nuevo objeto para el almacenamiento

de valores en sus atributos. En Java, para crear un nuevo objeto es necesario utilizar el

comando

new

, seguido del nombre de la clase que se desea instanciar

4

; entonces para crear

un nuevo empleado se utiliza la siguiente instrucción

new Empleado();

(23)

Con esta instrucción Java separa un espacio en memoria con la estructura definida para

la clase

Empleado

(es decir, debe haber un espacio

cedula

para almacenar la cédula del

empleado, un espacio

apellido

para almacenar el apellido del empleado, etc.).

La pregunta que debe surgir en estos momentos es, si con la instrucción

new Empleado()

se separa espacio en memoria para crear un objeto de la clase

Empleado

, ¿con qué valores

inician los atributos de este nuevo objeto? La respuesta, Java inicializa los valores de los

atributos con valores por defecto de la siguiente manera:

Para atributos cuyo tipo sea de referencia, el valor por defecto es

null;

es decir, la

referencia no apunta a ningún objeto.

Para atributos cuyo tipo sea un tipo de dato primitivo, el valor depende del tipo de

dato: si es un valor numérico (

byte

,

short

,

int

,

long

,

float

y

double

), su valor inicial

es 0; para tipo

boolean,

el valor inicial es falso (

false

), y, para tipo

char,

el valor

inicial es ‘\u0000’, que corresponde al primer carácter que puede ser representado.

Es decir, después de ejecutar la instrucción

new Empleado();

se crea un objeto de la siguiente

manera:

Luego de haber instanciado la clase, puede surgir la siguiente pregunta: ¿cómo se le asignan

valores a los atributos del objeto (para poder cambiar los valores por defecto con los que

se inicializa)? Como el objeto se crea en un espacio de la memoria, es necesario obtener la

referencia a esa posición en memoria y para poder hacerlo se define una variable, a la que

se le asigna dicha posición en memoria. Se requiere modificar la anterior instrucción por las

siguientes:

Empleado elEmpleado;

elEmpleado = new Empleado();

O se puede simplificar en una sola instrucción:

(24)

El entendimiento de esta definición suele causar problemas a algunos programadores.

La siguiente idea puede ayudar a clarificar la situación; al trabajar en cualquier lenguaje

de programación a la hora de definir una variable se emplea una instrucción semejante a

int a = 50,

es decir, primero se define el tipo de dato, luego el nombre de la variable y

posteriormente su valor. Si se analiza con detenimiento esta última instrucción y se compara

con la de creación de una instancia de

Empleado,

se obtiene lo siguiente:

Aquí se mencionan los siguientes puntos:

La primera parte de la definición indica el tipo de dato de la variable (que puede

ser un tipo de dato primitivo o de referencia). Esta parte cobra gran importancia al

trabajar el tópico de herencia.

La segunda parte de la definición corresponde al nombre que identificará a la

variable. Para la primera definición, el nombre de la variable es

elEmpleado;

para la

segunda, simplemente el carácter

a

.

La tercera parte de la definición especifica el valor que le será asignado a la variable.

Es importante considerar que aunque se ha intentado realizar una comparación de

ambas instrucciones, por definir variables de tipo de datos distintos, la manipulación

interna que hace el lenguaje de programación de estas variables es también distinto.

Recuerde que en la primera instrucción la variable

elEmpleado

corresponde a

una referencia de una posición en memoria, mientras que la segunda variable

efectivamente guarda el valor que se le asigna.

Una vez se tiene una referencia a un objeto (a través de la definición de una variable), es

posible consultar o modificar el valor de cualquiera de sus atributos. Para hacer cualquiera de

estas dos operaciones basta con generar una instrucción donde se especifique la referencia al

objeto y al atributo del objeto que se desea manipular; la delimitación entre ambos se logra

empleando el carácter punto (

.’); por ejemplo, suponiendo que la referencia a un objeto de

la clase Empleado se llame

elEmpleado

,

Se puede cambiar el valor del atributo

horasTrabajadas

empleando la siguiente

instrucción:

elEmpleado.horasTrabajadas = 1.5;

Se puede cambiar el valor del atributo sueldoXHora empleando la siguiente

instrucción:

elEmpleado.sueldoXHora = 100;

Se puede consultar el valor del atributo cédula empleando la siguiente instrucción:

(25)

u

neJemploampliadosobrelainstanCiaCión

Considere el siguiente código:

Empleado elEmpleado = new Empleado(); elEmpleado.cedula = “12345”;

elEmpleado.apellido = “Pérez”; elEmpleado.nombre = “Pedro”; elEmpleado.sueldoXHora = 50; elEmpleado.horasTrabajadas = 20;

Empleado otroEmpleado = new Empleado(); otroEmpleado.cedula = “98765”;

otroEmpleado.apellido = “Sánchez”; otroEmpleado.nombre = “María”; otroEmpleado.sueldoXHora = 120; otroEmpleado.horasTrabajadas = 10;

Después de ejecutar este código en Java se obtiene una configuración en memoria similar a la

siguiente:

La anterior gráfica debe entenderse de la siguiente manera: existen dos variables de tipo

Empleado

que referencian a objetos de la clase

Empleado

; la primera referencia tiene el

nombre de

elEmpleado

y apunta a un objeto cuyo valor para el atributo

cedula

es

12345

;

la

segunda referencia tiene el nombre de

otroEmpleado

y apunta a un objeto cuyo valor para el

atributo

cedula

es

98765

.

Es recomendable tener pendiente que los valores para los atributos

de un objeto (por lo menos de la manera en que han sido definidos hasta el momento) son

independientes de los valores que pueda tener cualquier otro objeto.

(26)

s

obreeloperadorlógiCodeComparaCiónysufunCionamientosobre lasvariablesdetipoprimitivoydereferenCia

El lector perspicaz debe estarse preguntando lo siguiente, si los valores de los atributos de un

objeto son totalmente independientes de los valores de los atributos de otros objetos de la misma

clase, ¿qué evita que se puedan crear dos objetos con exactamente los mismos valores para sus

atributos? La respuesta a este cuestionamiento es: nada. Considere el siguiente código:

Empleado elEmpleado = new Empleado(); elEmpleado.cedula = “12345”;

elEmpleado.apellido = “Pérez”; elEmpleado.nombre = “Pedro”; elEmpleado.sueldoXHora = 50; elEmpleado.horasTrabajadas = 20;

Empleado otroEmpleado = new Empleado(); otroEmpleado.cedula = “12345”;

otroEmpleado.apellido = “Pérez”; otroEmpleado.nombre = “Pedro”; otroEmpleado.sueldoXHora = 50; otroEmpleado.horasTrabajadas = 20;

En memoria se obtendría la siguiente configuración:

Es conveniente analizar el comportamiento de las variables al trabajar con el operador lógico

de comparación que provee Java (este operador se denota empleando el símbolo del doble

(27)

¿Cuál sería el resultado de ejecutar la siguiente instrucción?

elEmpleado == otroEmpleado

Aunque parezca ilógico, la respuesta de esta instrucción es el valor lógico de falso

(

false

).

La explicación de esta respuesta es simple: si

elEmpleado

y

otroEmpleado

son referencias

a objetos, la anterior instrucción no compara los valores que componen a los objetos sino las

posiciones en memoria donde se encuentran, como son dos objetos distintos, son dos posiciones

en memoria distintas.

Desde este punto de vista, ¿cuál sería el resultado de ejecutar la siguiente instrucción?

elEmpleado.horasTrabajadas == otroEmpleado.horasTrabajadas

El error más común que cometen los programadores que apenas están conociendo la teoría

de la programación orientada a objetos en Java es responder que la instrucción arrojaría

como resultado el valor lógico falso (

false

). En este caso, la respuesta es el valor verdadero

(

true

). El porqué de esta respuesta es también sencillo: en esta última instrucción no se están

comparando referencias sino tipos primitivos, y como los tipos primitivos almacenan el valor,

esta instrucción sí está comparando los valores de ambas variables.

Como se mencionó en el apartado sobre la definición y manipulación de los tipos de datos

primitivos y los de referencia es realmente importante tener claridad sobre los tipos de datos

y sobre la manipulación que realiza Java sobre ellos.

Un último interrogante que puede surgirle a un programador perspicaz en estos momentos

es, ¿cómo comparar dos objetos basándose en su contenido? Aunque después se analizará más

ampliamente esta situación, por lo pronto es conveniente mencionar que para realizar dicho

tipo de comparación es necesario cotejar uno a uno los valores correspondientes de todos los

atributos de los objetos.

(28)

s

obrelareutilizaCióndelasvariablesdereferenCia

Analícese el siguiente código:

Empleado e1 = new Empleado(); e1.cedula = “12345”; e1.apellido = “Pérez”; e1.nombre = “Pedro”; e1.sueldoXHora = 50; e1.horasTrabajadas = 20; Empleado e2 = null;

Empleado e3 = new Empleado(); e2=e1;

e3=e1;

Después de ejecutadas las anteriores instrucciones en memoria, se obtendría la siguiente

configuración:

Dos puntos para mencionar en esta situación:

Existen en memoria tres referencias:

e1

,

e2

y

e3

.

Todas tres apuntan al mismo objeto.

Si empleando la referencia

e1

se modifica el valor del atributo

horasTrabajadas

,

ese nuevo valor también podrá ser consultado empleando cualquiera de las restantes

referencias.

En la gráfica aparece un objeto

Empleado

con valores por defecto; cuando un objeto

se queda sin ningún tipo de referencia para ser manipulado, un elemento especial de

Java, el recolector de basura, lo elimina automáticamente.

(29)

s

obrelainstanCiaCiónyutilizaCióndearrays

En Java, un array es un objeto que representa un conjunto finito y ordenado de elementos

homogéneos. En el apartado donde se presenta la codificación en Java del algoritmo para el

cálculo de la nómina empleando programación estructurada se encuentran algunos ejemplos

de definiciones de arrays. Se pueden definir arrays de tipos de datos primitivos y de referencia;

los valores con que se inicializan cada una de las posiciones del array siguen las mismas

pautas establecidas para la inicialización de los valores de los atributos explicadas en la sección

de la instanciación.

La manipulación de un array de un tipo de dato primitivo en Java es análoga a la manipulación

que hace cualquier otro lenguaje de programación. Por otro lado, el entendimiento de la

manipulación de arrays de tipo de datos de referencia generalmente causa problemas a los

programadores que apenas comienzan a aprender Java y la programación orientada a objetos.

Es conveniente tener presente lo siguiente:

Un array (sin importar el tipo de dato del que es definido) es un objeto que representa

un conjunto finito, por ello, al momento de crearlo es necesario especificar la cantidad

de elementos que van a ser parte de este conjunto (este valor debe ser especificado

explícitamente).

Resulta útil pensar en un array de un tipo de dato de referencia como una referencia a

referencias, es decir, en un apuntador de memoria en donde se registran referencias a

otras posiciones en memoria.

Analice el código que se presenta a continuación:

Empleado e1 = new Empleado(); e1.cedula = “12345”;

e1.apellido = “Pérez”; e1.nombre = “Pedro”; e1.sueldoXHora = 50; e1.horasTrabajadas = 20; Empleado e2 = new Empleado(); e2.cedula = “98765”;

e2.apellido = “Sánchez”; e2.nombre = “María”; e2.sueldoXHora = 120; e2.horasTrabajadas = 10;

(30)

Empleado[] conjunto = new Empleado[10]; conjunto[0] = e1;

conjunto[1] = e2; conjunto[2] = e1;

Después de ejecutarse el anterior código, la memoria queda de la siguiente manera:

Cabe anotar que al instanciar un array de tipo de datos de referencia todas las posiciones del

array se inicializan en el valor de

null

(como ocurre con los atributos)

El error más común entre los programadores cuando empiezan a conocer el mundo de Java es

imaginarse que después de ejecutar el anterior código el estado de la memoria es similar al que

se muestra a continuación:

(31)

La clave para comprender esta situación se encuentra en tener claro que la instrucción

new

Empleado[10]

no instancia diez objetos de la clase

Empleado

,

sino que define que el array

almacenará hasta un máximo de diez objetos. Considerando esta situación, a lo largo del código

solo se instancian dos objetos

Empleado

; por consiguiente, solo deben existir en memoria dos

(32)

1.6. m

étOdO

p

rimeraaproximaCiónalaapliCaCióndelCálCulodelanómina medianteprogramaCiónorientadaaobJetos

Con los temas cubiertos hasta el momento es posible codificar un primer prototipo para la

aplicación. Se empleará una línea para dividir el código de las distintas clases que se presentan.

El primer componente a codificar corresponde a la clase

Empleado

(

se empleará la codificación

presentada anteriormente).

class Empleado{ String cedula; String apellido; String nombre; double horasTrabajadas; double sueldoXHora; } import java.io.BufferedReader; import java.io.InputStreamReader; class Nomina{

public static void main(String[] args) throws Exception{ int numeroEmpleados;

Empleado[] losEmpleados = new Empleado[50]; String cedula, apellido, nombre;

double horas, sueldo; double total = 0;

BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );

System.out.print(“Digite numero de empleados: “);

numeroEmpleados = Integer.valueOf(br.readLine()).intValue();

for(int i=0;i<numeroEmpleados;i++){

System.out.print(“\nDigite la cedula del empleado: “ ); cedula = br.readLine();

System.out.print(“Digite el apellido del empleado: “ ); apellido = br.readLine();

(33)

nombre = br.readLine();

System.out.print(“Digite num de horas trabajadas del empleado: “); horas = Double.valueOf(br.readLine()).doubleValue();

System.out.print(“Digite sueldo por hora del empleado: “ ); sueldo = Double.valueOf(br.readLine()).doubleValue(); Empleado unEmpleado = new Empleado();

unEmpleado.cedula = cedula; unEmpleado.apellido = apellido; unEmpleado.nombre = nombre; unEmpleado.horasTrabajadas = horas; unEmpleado.sueldoXHora = sueldo; losEmpleados[i]=unEmpleado; }

for (int i=0;i<numeroEmpleados;i++)

total = total + losEmpleados[i].sueldoXHora* losEmpleados[i].horasTrabajadas;

System.out.println(“\nLa nómina total es: “+ total);

} }

Puntos convenientes a resaltar en el anterior código:

Note que en vez de tener arrays independientes para cada uno de los datos a registrar

de un empleado (como la cédula, apellido, etc.) en este código se crea un único array

de elementos de tipo

Empleado

.

Note cómo es la manipulación del array de objetos de tipo

Empleado

que lleva por

(34)

a

proximaCiónalternativadelaapliCaCióndelCálCulodelanómina medianteprogramaCiónorientadaaobJetos

La aplicación presentada en el anterior apartado inicialmente indaga la cantidad de empleados

que posee la empresa y luego va preguntando la información puntual de cada uno de ellos. Se

podría definir una aplicación alternativa que funcione a través de un menú. En este se podrían

definir como opciones el ingreso de un nuevo empleado en la nómina de la empresa, calcular

la nómina total y, finalmente, abandonar la aplicación. El siguiente código en Java representa

esta última situación (se reutiliza la definición de la clase

Empleado

aunque no es necesario

volverla a codificar):

class Empleado{ String cedula; String apellido; String nombre; double horasTrabajadas; double sueldoXHora; } import java.io.BufferedReader; import java.io.InputStreamReader; class Nomina2{

public static void main(String[] args) throws Exception{ int numeroEmpleados=0, opcionMenu=0;

Empleado[] losEmpleados = new Empleado[50]; String cedula, apellido, nombre;

double horas, sueldo; double total = 0;

BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) ); while(opcionMenu!=3){

System.out.println(“Menu de opciones”); System.out.println(“1- Adicionar Empleado”); System.out.println(“2- Calcular nómina total”); System.out.println(“3- Salir”);

(35)

opcionMenu = Integer.valueOf(br.readLine()).intValue(); if (opcionMenu==1){

System.out.print(“\nDigite la cedula del empleado: “ ); cedula = br.readLine();

System.out.print(“Digite el apellido del empleado: “ ); apellido = br.readLine();

System.out.print(“Digite el nombre del empleado: “ ); nombre = br.readLine();

System.out.print(“Digite num de horas trabajadas: “); horas = Double.valueOf(br.readLine()).doubleValue(); System.out.print(“Digite sueldo por hora del empleado: “ ); sueldo = Double.valueOf(br.readLine()).doubleValue(); Empleado unEmpleado = new Empleado();

unEmpleado.cedula = cedula; unEmpleado.apellido = apellido; unEmpleado.nombre = nombre; unEmpleado.horasTrabajadas = horas; unEmpleado.sueldoXHora = sueldo; losEmpleados[numeroEmpleados]=unEmpleado; numeroEmpleados++; } else if (opcionMenu==2){

for (int i=0;i<numeroEmpleados;i++)

total = total + losEmpleados[i].sueldoXHora* losEmpleados[i].horasTrabajadas;

System.out.println(“\nLa nómina total es: “+ total); }

} } }

La definición de la clase

Empleado

puede ser reutilizada en una gran variedad de aplicaciones

(como, por ejemplo, los códigos presentados en los apartados: Primera aproximación de

la aplicación del cálculo de la nómina mediante programación orientada a objetos y

Aproximación alternativa de la aplicación del cálculo de la nómina según programación

(36)

orientada a objetos). En caso de ser necesario calcular cuánto se le debe pagar a un empleado

bastaría con multiplicar el número de horas trabajadas por el sueldo que devenga por hora;

previendo que el uso de esta operación puede que sea necesaria utilizarla en posteriores

ocasiones, sería conveniente incluirla como parte de una función (muchos en este momento

pueden estar pensando en no definir ninguna función debido a la simplicidad del cálculo;

sin embargo, se debe considerar que la fórmula del sueldo mensual de un empleado podría

complejizarse al tener en cuenta la serie de aportes parafiscales como pensión, salud,

retención en la fuente, entre otros ). ¿Pero dónde definir la función? Se manejan las siguientes

alternativas:

Como la clase

Empleado

puede que sea reutilizada en varias aplicaciones, sería

necesario definir dicha función en cada una de ellas; sin embargo, esta no sería una

muy buena alternativa, pues se estaría replicando el código en muchos lados, y,

además, representaría un serio problema en caso de necesitarse la realización de una

modificación en la fórmula del cálculo del sueldo del empleado.

Crear una librería independiente de funciones e incluirla allí. Esta librería podría

abarcar esta función y cualquier otra que aparezca en el desarrollo de la aplicación.

La mejor alternativa correspondería definirla dentro de la propia clase; de todas

formas qué mejor librería a incluirse que la propia clase que genera la necesidad.

En Java desaparecen los conceptos de subrutinas, procedimientos o funciones (que existen

dentro del paradigma de programación procedimental) y se reemplazan por la noción

de método (sin embargo, el comportamiento y la forma de trabajo son análogos al de las

subrutinas). La idea principal es la de ubicar los métodos junto con los datos sobre los que

operan (en este caso, ubicar el método que posibilite el cálculo del salario mensual de un

empleado junto con los datos del empleado).

Definición de método

Abstracción de una acción, servicio, comportamiento o tarea que puede ser realizado

por un objeto. Generalmente, un método manipula la información registrada en los

atributos a través de una o más instrucciones.

La definición de un método en Java requiere básicamente especificar:

El tipo de dato que retornará como resultado el método. Este tipo de dato puede

corresponder a un tipo de dato primitivo, a cualquier tipo de dato de referencia, o en

caso de no retornar ningún valor debe especificarse el valor de

void

.

El nombre del método. La comunidad de programadores de Java maneja una

convención de nombramiento para los métodos, que establece que el nombre del

método debe escribirse en minúsculas. Si el nombre de un método está compuesto

por varias palabras; se unen las letras de todas las palabras (sin usar ningún carácter

(37)

especial adicional) y se colocan en mayúsculas las primeras letras de cada palabra, a

excepción de la primera letra del nombre del método (por ejemplo, calcularSalario).

Un paréntesis de apertura y un paréntesis de cierre (

()

’), y en caso de requerirse

dentro del juego de paréntesis, la definición del conjunto de parámetros que necesita

el método para su funcionamiento.

Añadiendo la definición del método que posibilite el cálculo del salario del empleado, la

clase

Empleado

quedaría de la siguiente manera:

class Empleado{ String cedula; String apellido; String nombre; double horasTrabajadas; double sueldoXHora; double calcularSalario(){

return horasTrabajadas * sueldoXHora; }

}

En pocas palabras, la definición del método

calcularSalario

indica que se debe multiplicar

el valor que se tenga en los atributos

horasTrabajadas

y

sueldoXHora

, y retornar el resultado.

Para invocar un método se requiere una instrucción donde se especifique la referencia al

objeto y al método dentro de ese objeto; la delimitación entre ambos se logra empleando

el carácter punto (

.’); por ejemplo, suponiendo que la referencia a un objeto de la clase

Empleado

se llame

elEmpleado

, se puede invocar el método

calcularSalario

a través de la

siguiente instrucción:

elEmpleado.calcularSalario();

Teniendo en cuenta el siguiente código:

Empleado e1 = new Empleado(); e1.cedula = “12345”;

e1.apellido = “Pérez”; e1.nombre = “Pedro”; e1.sueldoXHora = 50; e1.horasTrabajadas = 20; Empleado e2 = new Empleado(); e2.cedula = “98765”;

e2.apellido = “Sánchez”; e2.nombre = “María”; e2.sueldoXHora = 10; e2.horasTrabajadas = 120;

(38)

corrobora que el resultado de la invocación del método

calcularSalario

depende de los

valores de los atributos del objeto al que se hace referencia.

s

obrelosparámetrosenlosmétodos

Determinar qué parámetros deben definirse como parte de un método es una de las situaciones

que causan problemas para los programadores novatos en la programación orientada a objetos.

Por ejemplo, para el caso de la definición del método

calcularSalario

,

muchos preguntarían

por qué no se incluyen como parámetros el valor de las horas trabajadas y el sueldo por hora

del empleado.

Supóngase por un momento que la definición del método se ha alterado para reflejar dicho

cambio, por consiguiente el código de la clase

Empleado

quedaría de la siguiente manera:

class Empleado{ String cedula; String apellido; String nombre; double horasTrabajadas; double sueldoXHora;

double calcularSalario(double horasTrabajadas, double sueldoXHora){ return horasTrabajadas * sueldoXHora;

} }

Suponga, además, que se tiene el siguiente código:

Empleado e1 = new Empleado(); e1.cedula = “12345”;

e1.apellido = “Pérez”; e1.nombre = “Pedro”; e1.sueldoXHora = 50; e1.horasTrabajadas = 20;

(39)

La instrucción para invocar el método

calcularSalario

para el objeto e1 sería:

e1.calcularSalario(20,50);

El lector perspicaz debe estar notando que en esta instrucción existe algo extraño. El siguiente

gráfico ilustra la situación.

Lo extraño de la situación corresponde a que a través de los parámetros se está suministrando

información que el objeto ya conoce y almacena. Esta instrucción no tiene sentido alguno. El

escenario sería el mismo si se ejecutase la siguiente instrucción:

e1.calcularSalario(e1.horasTrabajadas, e1.sueldoXHora);

Cuando se presentó la definición de clase, se hacía referencia a que esta describe la estructura

y comportamiento común de un conjunto de objetos. La descripción de la estructura se

alcanza a través de la definición de los atributos; y la descripción del comportamiento se

alcanza a través de la definición de los métodos.

1.6.1. Método constructor

Hasta el momento la forma presentada para posibilitar la creación de un objeto corresponde

al empleo de la instrucción

new

seguida del nombre de la clase; para la asignación de los

valores a los atributos se requieren instrucciones posteriores. Si se analiza el código de las

instanciaciones efectuadas hasta el momento se podrá notar la cantidad de código que se

requiere; se podría pensar en definir un método para facilitar dicho proceso. Dentro de la

programación orientada a objetos ese método recibe el nombre de método constructor.

(40)

Definición de método constructor

Método especial que crea un objeto de la clase y que puede emplearse para

especificar aquellas tareas que deban realizarse en el momento de la creación como,

por ejemplo, la inicialización de los valores de los atributos.

El método constructor es un método especial, y su definición varía ligeramente del resto.

Las particularidades son:

Un método constructor no puede tener definido un tipo de dato de retorno cuando

ni siquiera el valor de

void

es válido.

El nombre del método debe ser el mismo nombre de la clase (debe coincidir

exactamente con el nombre cuidando hasta el uso de letras mayúsculas y minúsculas).

s

obreelámbitodelasvariablesylapalabrareservada

this

Con los lineamientos que se tienen hasta el momento el código de la clase

Empleado

quedaría

de la siguiente forma:

class Empleado{ String cedula; String apellido; String nombre; double horasTrabajadas; double sueldoXHora;

Empleado(String pcedula, String papellido, String pnombre, double phorasTrabajadas, double psueldoXHora){

cedula = pcedula; apellido = papellido; nombre = pnombre; sueldoXHora = psueldoXHora; horasTrabajadas = phorasTrabajadas; } double calcularSalario(){

return horasTrabajadas * sueldoXHora; }

(41)

Del anterior código hay varios puntos por analizar:

La cantidad de parámetros definidos es la misma que el número de atributos de la

clase. Esta situación se presenta porque para crear un nuevo objeto empleado es

necesario que se suministre información para cada uno de los atributos. Sin embargo,

no debe seguirse esto como una regla general, porque hay escenarios donde el número

de parámetros puede diferir del número de atributos.

En el apartado sobre los parámetros en los métodos se estuvo analizando una

situación especial, que no se presenta con los parámetros del método constructor

porque, a diferencia del ejemplo allí presentado en este caso el objeto no conoce de

antemano la información del empleado

Para evitar que se presente una confusión con los nombres de los parámetros del

método constructor y de los atributos de la clase, se ha optado por anteponerle la letra

‘p

al nombre del parámetro.

El código del método constructor se encarga de asignar a cada uno de los atributos del

objeto los valores que se suministran en los parámetros correspondientes (es decir, al

atributo

cedula

se le asigna el valor que se recibe en el parámetro

pcedula

, etc.).

En Java también existe la noción de variable de ámbito local y de ámbito global, por consiguiente,

nada evita que la definición del método constructor de Empleado tenga la siguiente signatura:

Empleado(String cedula, String apellido, String nombre, double horasTrabajadas, double sueldoXHora)

El problema que se presentaría con la última definición del constructor de la clase Empleado es

que tanto los parámetros como los atributos tienen los mismos nombres; por ende, instrucciones

como las que se muestran a continuación, además de triviales, son ambiguas e inútiles.

cedula = cedula; apellido = apellido; nombre = nombre;

sueldoXHora = sueldoXHora;

horasTrabajadas = horasTrabajadas

;

¿Qué podrían significar las anteriores instrucciones? Habría cuatro posibilidades:

Asígnese al parámetro el valor que tiene el parámetro. Esto carece de sentido porque

dicho valor ya se encuentra asignado.

Asígnese al atributo el valor que tiene el atributo. Esto carece de sentido porque uno

de los objetivos de un método constructor es inicializar el valor de los atributos del

objeto; entonces, la instrucción no está alterando dicho valor.

(42)

Asígnese al parámetro el valor del atributo. También carece de sentido porque se están

reemplazando los valores suministrados para instanciar al objeto por los valores por

defecto con los que se inicializó la instancia.

Asígnese al atributo el valor suministrado en el parámetro. Esta instrucción si tiene

sentido y es la que se busca darle a entender al lenguaje de programación.

Es conveniente detenerse en este punto para explicar esta situación con más detalle. Dentro del

paradigma procedimental una variable global

2

es aquella que está declarada para el programa

o algoritmo principal, del que dependen todos los subprogramas. En otras palabras, es una

variable que puede ser usada por cualquier procedimiento. Si se piensa que dentro de una

clase un atributo puede ser utilizado en cualquiera de los métodos que se definan al interior

de la clase entonces puede asemejarse el concepto de variable global al de atributo (solo

bajo la consideración presentada anteriormente de variable global pero únicamente para la

clase). Por su parte, una variable local

3

es aquella que está declarada y definida dentro de un

subprograma. Con esta definición se puede decir que cualquier parámetro declarado para un

método, o cualquier variable definida dentro de un método, cae dentro de la definición de una

variable local.

Considérese el siguiente código de ejemplo:

class Ejemplo{ int a=10; void metodo(){ int a = 20; System.out.println(a); } }

En este ejemplo se define una clase de nombre

Ejemplo

, que posee un único atributo de nombre

a

que se inicializa en el valor de

10

, y, además, posee un método donde se define una variable

a

que se inicializa con un valor de

20

. Hay que comenzar diciendo que por el análisis previo

efectuado sobre las variables de ámbito global y local, este ejemplo es totalmente válido. El

interrogante sería, cuál es el valor que se mostrará por pantalla en caso de invocar la ejecución

de

metodo

. La respuesta es

20

, y la razón es porque el método cuando necesita trabajar con la

variable

a

primero busca dentro de las definiciones de variables locales que tenga; si encuentra,

una trabaja con ella; de lo contrario, trabaja con la definición global (exactamente así ocurre

dentro del manejo de variables en el paradigma procedimental).

(43)

Volviendo al caso que inició este análisis, ya se mencionó que para la siguiente definición del

método constructor de la clase Empleado

Empleado(String cedula, String apellido, String nombre, double horasTrabajadas, double sueldoXHora){

cedula = cedula; apellido = apellido; nombre = nombre; sueldoXHora = sueldoXHora; horasTrabajadas = horasTrabajadas; }

Existían cuatro alternativas de ejecución, pero después de conocer cómo es el comportamiento

con el ámbito de las variables, se pueden descartar tres de las posibilidades; queda únicamente

la alternativa mencionada donde la instrucción ocasionaría la asignación al parámetro del

mismo valor que ya tiene (que correspondería a una instrucción trivial).

La solución a este asunto se encuentra evitando la trivialidad en el código del constructor de

la clase

Empleado

, y cuando se especifica que la acción a ejecutar es la de asignarla al atributo

el valor que se recibe en el parámetro. Existe en Java una palabra reservada cuyo significado

ayuda a eliminar la trivialidad; esta palabra es

this

.

this es una propiedad que tienen todos los objetos en Java y a través de ella un objeto puede

obtener su propia referencia en memoria (su propia posición). Para ejemplificar esta situación,

considere el siguiente código:

Empleado e1 = new Empleado(); Empleado e2 = new Empleado();

Suponga que el espacio de memoria que se reserva para el primer objeto

(e1)

tiene la dirección

16f0472

y que el segundo objeto

(e2)

tiene la dirección

18d107f

; si al interior de cualquier

método en el objeto

(e1)

se hace referencia a

this

se obtendrá la dirección

16f0472

, y si al

interior de cualquier método en el objeto

e2

se hace referencia a

this

se obtendrá la dirección

18d107f

.

¿Cómo ayuda

this

a especificar dentro del constructor que se le asignen a los atributos los

valores que se pasan en los parámetros? Si dentro de cualquier método se emplea la instrucción

conformada por la auto referencia

this

y el nombre del atributo (delimitándose uno del otro

(44)

al atributo en mención. Por consiguiente, las instrucciones dentro del constructor de

Empleado

debieran definirse de la siguiente manera:

this.cedula = cedula; this.apellido = apellido; this.nombre = nombre;

this.sueldoXHora = sueldoXHora;

this.horasTrabajadas = horasTrabajadas;

Tomando en cuenta lo presentado anteriormente (y en especial lo analizado en el apartado

sobre el ámbito de las variables y la palabra reservada ‘this’), el código de la clase

Empleado

queda de la siguiente manera:

class Empleado{ String cedula; String apellido; String nombre; double horasTrabajadas; double sueldoXHora;

Empleado(String cedula, String apellido, String nombre, double horasTrabajadas, double sueldoXHora){

this.cedula = cedula; this.apellido = apellido; this.nombre = nombre; this.sueldoXHora = sueldoXHora; this.horasTrabajadas = horasTrabajadas; } double calcularSalario(){

return horasTrabajadas * sueldoXHora; }

}

Con esta nueva definición de la clase se simplifica la instanciación de objetos, pues se pasa

de tener que escribir el siguiente código:

Empleado e1 = new Empleado(); e1.cedula = “12345”;

e1.apellido = “Pérez”; e1.nombre = “Pedro”; e1.sueldoXHora = 50; e1.horasTrabajadas = 20;

Figure

Actualización...

Referencias

Actualización...