Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Unidad 2
INSTITUTO TECNOLÓGICO SUPERIOR DE COMALCALCO
Asignatura:
Programación avanzada
Alumna:
Ángeles Fernanda Hernández Romero
Profesor:
Elías Rodríguez Rodríguez
Carrera:
Ingeniería Mecatrónica
semestre y grupo:
7° “C”
Actividad:
investigación de conceptos básicos
3
2.1 Declaración de clases: atributos, métodos,
encapsulamiento.
La declaración de una clase define la estructura de la misma. Dicho de otra forma, la declaración de una
clase informa de los elementos que la conforman. Posteriormente a ser declarada, una clase debe ser
implementada convenientemente, es decir, se debe escribir el código correspondiente a los procedimientos
y funciones que determinan el funcionamiento de esa clase.
Las clases se declaran en la sección TIPO del script pues las clases son, al fin y al cabo, tipos de datos.
La programación orientada a objetos se basa en la programación de clases; a diferencia de la programación
estructurada, que está centrada en las funciones.
Una clase es un molde del que luego se pueden crear múltiples objetos, con similares características.
Una clase es una plantilla (molde), que define atributos (variables) y métodos (funciones)
La clase define los atributos y métodos comunes a los objetos de ese tipo, pero luego, cada objeto tendrá
sus propios valores y compartirán las mismas funciones.
Debemos crear una clase antes de poder crear objetos (instancias) de esa clase. Al crear un objeto de una
clase, se dice que se crea una instancia de la clase o un objeto propiamente dicho.
4
Atributo
Los atributos, también llamados datos o variables miembro son porciones de información que un objeto
posee o conoce de sí mismo. Una clase puede tener cualquier número de atributos o no tener ninguno. Se
declaran con un identificador y el tipo de dato correspondiente. Además los atributos y tienen asociado un
modificador que define su visibilidad según se muestra en la siguiente tabla.
Tipos de atributos.
Objetivos:
a) Profundizar en el concepto de atributo de una clase e indicar los tipos de atributos en Java
b) Interpretar el código fuente de una aplicación Java donde aparecen distintos tipos de atributos
c) Construir una aplicación Java sencilla, convenientemente especificada, que emplee clases con diferentes
tipos de atributos.
Los atributos, también llamados datos o variables miembro son porciones de información que un objeto
posee o conoce de sí mismo. Una clase puede tener cualquier número de atributos o no Tener ninguno. Se
declaran con un identificador y el tipo de dato correspondiente.
5
Variables de instancia
Cuando se declara el atributo o variable miembro euros en la clase Precio de la siguiente forma:
se está declarando el atributo euros como una variable de instancia. En consecuencia, cada vez que se
crea una instancia de la clase Precio, se reserva espacio en memoria para una variable de instancia euros.
Por ejemplo, el código:
6
genera dos instancias de la clase Precio como muestra la Figura 9.2. En este caso, cada una de las dos
instancias, p y q, de la clase Precio tiene una variable de instancia euros propia. Las respectivas llamadas al
método pone para cada instancia (p.pone(56.8) y q.pone(75.6)), permiten asignar un valor a las variables de
instancia correspondientes.
Las variables de clase son atributos diferentes de las variables de instancia. Las variables de clase implican
una sola zona de memoria reservada para todas las instancias de la clase, y no una copia por objeto, como
sucede con las variables de instancia. Para diferenciarlas de éstas en el código fuente de Java, las variables
de clase se distinguen con el modificador static en la declaración del atributo correspondiente. Por defecto (si
no se indica la palabra static), el atributo declarado se considera variable de instancia.
7
Durante la ejecución del programa, el sistema reserva un único espacio en memoria para cada variable
estáticas o de clase independientemente del número de instancias creadas de una clase. Esta reserva se
produce la primera vez que encuentra dicha clase en el código, de forma que todas las instancias
pertenecientes a una clase comparten la misma variable de clase. A diferencias de las variables globales
fuera de la POO, las variables de clase garantizan la encapsulación.
Las variables de clase sirven para almacenar características comunes (constantes) a todos los objetos
(número de ruedas de una bicicleta) o para almacenar características que dependen de todos los objetos
(número total de billetes de lotería). Por ejemplo, la clase CuentaBancaria tiene una variable de instancia,
saldo, y una variable de clase, totalCuentas.
8
La creación de varias instancias de la clase CuentaBancaria no conlleva la existencia de varias variables
totalCuentas. Durante la ejecución de un programa que utilice la clase CuentaBancaria sólo existirá una
variable de clase totalCuentas, independientemente del número de instancias de la clase CuentaBancaria
que se generen.
Es más, no es necesario siquiera que exista una instancia de la clase, para que lo haga la variable de
clase.
De hecho, se inicializan a false, cero o null (dependiendo de su tipo) antes de que se genere una instancia
de la clase.
9
Las variables de clase se emplean cuando sólo es necesaria una copia por clase que, además, esté
accesible por todas las instancias de la clase a la que pertenece. En este caso, al ser un atributo public y
static, puede accederse directamente a la variable de clase (totalCuentas) a través de una instancia (c1 o
c2) o de la clase en sí (CuentaBancaria). Un atributo estático puede ser accedido desde cualquier instancia
de la clase, ya que es miembro de la propia clase.
10
La ejecución del código anterior origina la siguiente salida por pantalla:
Para operar con variables de clase también podemos implementar métodos en la clase. Por ejemplo el
siguiente método incTotalCuentas incrementa en una unidad el valor de la variable de clase totalCuentas.
Al ser declarado el método incTotalCuentas como un método public y static, puede llamarse mediante
cualquiera de las instancias (c1 o c2) o de la clase en sí (CuentaBancaria).
Las variables de clase pueden declararse como public o como private y pueden pertenecer a cualquiera de
los tipos de datos primitivos de Java o bien, a otra clase existente en Java o declarada por el usuario. En
principio, la única limitación para el número de variables de clase que puede declarar una clase es el
espacio libre disponible por el sistema que ejecute el programa. 11
Constantes o variables finales (final)
Una clase puede contener atributos de valor constante o variables finales. Este tipo de atributo se indica
con la palabra reservada final. Las variables finales se suelen declarar además como variables de clase
(static final) por razones de ahorro de memoria ya que, al no modificar su valor sólo suele ser necesaria
una copia en memoria por clase (y no una por instancia). Por ejemplo, en la clase Circulo:
La palabra reservada final indica que el atributo debe comportarse como una constante, es decir, no
puede ser modificada una vez declarada e inicializada. Por otro lado, se puede separar la declaración de
la inicialización de la variable final, realizándose ésta más tarde. En este caso, el valor asignado a la
variable final puede hacerse en función de otros datos o de llamadas a métodos, con lo que el valor de la
constante no tiene porqué ser el mismo para diferentes ejecuciones del programa.
12
Métodos.
Java como todo lenguaje de programación orientado a objetos utiliza los llamados métodos. A continuación
veremos cómo se crea un método y como se utilizan.
Se podría decir que existen 2 grandes tipos de métodos, el primer tipo de método son métodos que realizan
procesos, puedes realizar cualquier operación con ellos, sin embargo el propósito es manipular variables
existentes. El segundo tipo de métodos son los que realizan un proceso o cálculo, y calculan una variable
específica, un ejemplo podría ser un método para obtener el valor de una multiplicación.
Los métodos en java pueden tener parámetros, es decir, que un método puede utilizar variables
predefinidas para ser utilizadas en sus procesos.
Un método es una abstracción de una operación que puede hacer o realizarse con un objeto. Una clase
puede declarar cualquier número de métodos que lleven a cabo operaciones de lo más variado con los
objetos. En esta sección los métodos se clasifican en dos grupos: los métodos de instancia y los métodos
de clase.
13
Métodos de instancia
Las clases pueden incluir en su declaración muchos métodos o no declarar ninguno. Los métodos pueden
clasificarse en métodos de instancia y métodos de clase.
Los métodos de instancia operan sobre las variables de instancia de los objetos pero también tienen
acceso a las variables de clase. La sintaxis de llamada a un método de instancia es:
Todas las instancias de una clase comparten la misma implementación para un método de instancia. La
instancia que hace la llamada al método es siempre un parámetro o argumento implícito. Dentro de un
método de instancia, el identificador de una variable de instancia hace referencia al atributo de la
instancia concreta que hace la llamada al método (suponiendo que el identificador del atributo no ha sido
ocultado por el de un parámetro).
14
Ejemplos de llamada a estos métodos dentro de PruebaCuentaBancaria:
15
Métodos de clase
En principio, los métodos de clase no operan sobre las variables de instancia de los objetos. Los métodos
de clase pueden trabajar con las variables de clase pero no pueden acceder a las variables de instancia
declaradas dentro de la clase, a no ser que se crea una nueva instancia y se acceda a las variables de
instancia a través del nuevo objeto. Los métodos de clase también pueden ser llamados precediéndolos
con el identificador de la clase, sin necesidad de utilizar el de una instancia.
La palabra static determina la declaración de un método de clase. Por defecto, si no se indica la palabra
static, el método declarado se considera un método de instancia.
En el ejemplo anterior en la declaración de la clase CuentaBancaria, el método incCuentas es un método
de clase.
16
Las diferencias entre los métodos de instancia y los de clase se resumen aquí:
Encapsulamiento.
Como se puede observar de los diagramas, las variables del objeto se localizan en el centro o núcleo del
objeto. Los métodos rodean y esconden el núcleo del objeto de otros objetos en el programa. Al
empaquetamiento de las variables de un objeto con la protección de sus métodos se le llama
encapsulamiento. Típicamente, el encapsulamiento es utilizado para esconder detalles de la puesta en
práctica no importantes de otros objetos. Entonces, los detalles de la puesta en práctica pueden cambiar en
cualquier tiempo sin afectar otras partes del programa.
17
Existen tres niveles de acceso para el encapsulamiento, los cuales son:
Público (Public): Todos pueden acceder a los datos o métodos de una clase que se definen con este nivel,
este es el nivel más bajo, esto es lo que tu quieres que la parte externa vea.
Protegido (Protected): Podemos decir que estás no son de acceso público, solamente son accesibles
dentro de su clase y por subclases.
Privado (Private): En este nivel se puede declarar miembros accesibles sólo para la propia clase.
18
2.2 Instanciación de una clase.
Podemos interpretar que una clase es el plano que describe como es un objeto de la clase, por tanto
podemos entender que a partir de la clase podemos fabricar objetos. A ese objeto construido se le
denomina instancia, y al proceso de construir un objeto se le llama instanciación.
Cuando se construye un objeto es necesario dar un valor inicial a sus atributos, es por ello que existe un
método especial en cada clase, llamado constructor, que es ejecutado de forma automática cada vez que
es instanciada una variable. Generalmente el constructor se llama igual que la clase y no devuelve ningún
valor. Análogamente, destructor es un método perteneciente a una clase que es ejecutado de forma
automática cuando un objeto es destruido. Java no soporta los destructores. Es posible que exista más de
un constructor en una clase, diferenciados sólo en los parámetros que recibe, pero en la instanciación sólo
será utilizado uno de los constructores.
19
La instanciación de las clases: Los objetos
Referencias a Objeto e Instancias
Los tipos simples de Java describían el tamaño y los valores de las variables. Cada vez que se crea una
clase se añade otro tipo de dato que se puede utilizar igual que uno de los tipos simples. Por ello al
declarar una nueva variable, se puede utilizar un nombre de clase como tipo. A estas variables se las
conoce como referencias a objeto.
Todas las referencias a objeto son compatibles también con las instancias de subclases de su tipo. Del
mismo modo que es correcto asignar un byte a una variable declarada como int, se puede declarar que una
variable es del tipo MiClase y guardar una referencia a una instancia de este tipo de clase:
MiPunto p;
Esta es una declaración de una variable p que es una referencia a un objeto de la clase MiPunto, de
momento con un valor por defecto de null. La referencia null es una referencia a un objeto de la clase
Object, y se podrá convertir a una referencia a cualquier otro objeto porque todos los objetos son hijos de la
clase Object.
Constructores
Las clases pueden implementar un método especial llamado constructor. Un constructor es un método que
inicia un objeto inmediatamente después de su creación. De esta forma nos evitamos el tener que iniciar
las variables explícitamente para su iniciación.
El constructor tiene exactamente el mismo nombre de la clase que lo implementa; no puede haber ningún
otro método que comparta su nombre con el de su clase. Una vez definido, se llamará automáticamente al
constructor al crear un objeto de esa clase (al utilizar el operador new).
20
El constructor no devuelve ningún tipo, ni siquiera void. Su misión es iniciar todo estado interno de un
objeto (sus atributos), haciendo que el objeto sea utilizable inmediatamente; reservando memoria para sus
atributos, iniciando sus valores...
Por ejemplo:
MiPunto( ) {
inicia( -1, -1 );
Este constructor denominado constructor por defecto, por no tener parámetros, establece el valor -1 a las
variables de instancia x e y de los objetos que construya.
El compilador, por defecto ,llamará al constructor de la superclase Object() si no se especifican parámetros
en el constructor.
Este otro constructor, sin embargo, recibe dos parámetros:
} 21
La lista de parámetros especificada después del nombre de una clase en una sentencia new se utiliza para
pasar parámetros al constructor.
Se llama al método constructor justo después de crear la instancia y antes de que new devuelva el control
al punto de la llamada.
Así, cuando ejecutamos el siguiente programa:
Se muestra en la pantalla:
p1.- x = 10 y = 20
Para crear un programa Java que contenga ese código, se debe de crear una clase que contenga un
método main(). El intérprete java se ejecutará el método main de la clase que se le indique como
parámetro.
22
El operador new
El operador new crea una instancia de una clase (objetos) y devuelve una referencia a ese objeto. Por
ejemplo:
Este es un ejemplo de la creación de una instancia de MiPunto, que es controlador por la referencia a
objeto p2.
Hay una distinción crítica entre la forma de manipular los tipos simples y las clases en Java: Las
referencias a objetos realmente no contienen a los objetos a los que referencian. De esta forma se pueden
crear múltiples referencias al mismo objeto, como por ejemplo:
MiPunto p3 =p2;
Aunque tan sólo se creó un objeto MiPunto, hay dos variables (p2 y p3) que lo referencian. Cualquier
cambio realizado en el objeto referenciado por p2 afectará al objeto referenciado por p3. La asignación de
p2 a p3 no reserva memoria ni modifica el objeto.
De hecho, las asignaciones posteriores de p2 simplemente desengancharán p2 del objeto, sin afectarlo:
23
Aunque se haya asignado null a p2, p3 todavía apunta al objeto creado por el operador new.
Cuando ya no haya ninguna variable que haga referencia a un objeto, Java reclama automáticamente la
memoria utilizada por ese objeto, a lo que se denomina recogida de basura.
Cuando se realiza una instancia de una clase (mediante new) se reserva en la memoria un espacio para un
conjunto de datos como el que definen los atributos de la clase que se indica en la instanciación. A este
conjunto de variables se le denomina variables de instancia.
La potencia de las variables de instancia es que se obtiene un conjunto distinto de ellas cada vez que se
crea un objeto nuevo. Es importante el comprender que cada objeto tiene su propia copia de las variables
de instancia de su clase, por lo que los cambios sobre las variables de instancia de un objeto no tienen
efecto sobre las variables de instancia de otro.
El siguiente programa crea dos objetos MiPunto y establece los valores de x e y de cada uno de ellos de
manera independiente para mostrar que están realmente separados.
Durante las impresiones (método println()) se accede al valor de las variables mediante p6.x y p6.y, y entre
una impresión y otra se llama al método inicia(), cambiando los valores de las variables de instancia.
25
Durante las impresiones (método println()) se accede al valor de las variables mediante p6.x y p6.y, y entre
una impresión y otra se llama al método inicia(), cambiando los valores de las variables de instancia.
Este es uno de los aspectos más importantes de la diferencia entre la programación orientada a objetos y
la programación estructurada. Cuando se llama al método p6.inicia(), lo primero que se hace en el método
es sustituir los nombres de los atributos de la clase por las correspondientes variables de instancia del
objeto con que se ha llamado. Así por ejemplo x se convertirá en p6.x.
Si otros objetos llaman a inicia(), incluso si lo hacen de una manera concurrente, no se producen efectos
laterales, ya que las variables de instancia sobre las que trabajan son distintas.
La referencia this
Java incluye un valor de referencia especial llamado this, que se utiliza dentro de cualquier método para
referirse al objeto actual. El valor this se refiere al objeto sobre el que ha sido llamado el método actual. Se
puede utilizar this siempre que se requiera una referencia a un objeto del tipo de una clase actual. Si hay
dos objetos que utilicen el mismo código, seleccionados a través de otras instancias, cada uno tiene su
propio valor único de this.
Un refinamiento habitual es que un constructor llame a otro para construir la instancia correctamente. El
siguiente constructor llama al constructor parametrizado MiPunto(x,y) para terminar de iniciar la instancia:
MiPunto() {
} 26
En Java se permite declarar variables locales, incluyendo parámetros formales de métodos, que se solapen
con los nombres de las variables de instancia.
No se utilizan x e y como nombres de parámetro para el método inicia, porque ocultarían las variables de
instancia x e y reales del ámbito del método. Si lo hubiésemos hecho, entonces x se hubiera referido al
parámetro formal, ocultando la variable de instancia x:
28
29
2.3 Referencia al objeto actual.
La utilización de THIS en lugar de hacer referencia explícitamente al objeto actual por su nombre (por
ejemplo, thisform.command1.caption) hace que el código de programa pueda alternarse entre objetos,
porque evita el nombre del objeto y encapsula automáticamente la clase primaria del objeto.
THIS permite hacer referencia a una propiedad o un objeto de una definición de clase. Los métodos de un
bloque de definición de clase pueden utilizar THIS para especificar una propiedad o un objeto que existirá
cuando se cree la clase.
Puesto que múltiples instancias de objetos comparten el mismo código de método, THIS siempre hace
referencia a la instancia en la que está ejecutándose el código. Si hay múltiples instancias de un objeto, y se
llama a uno de los métodos del objeto, THIS hace referencia al objeto correcto.
Cada objeto puede acceder a una referencia a si mismo mediante la palabra this. Cuando se hace una
llamada a un método no static para un objeto especifico, el cuerpo del método utiliza en forma implícita la
palabra this para hacer referencia a las variables de instancia y los demás métodos del objeto.
Ahora demostraremos el uso implícito y explicito de la referencia this para permitir al método main de la clase
PruebaThis que muestre en pantalla los datos prívate de un objeto de la clase TiempoSimple. Hicimos esto
para demostrar que, al compilador un archivo .java que contiene mas de una clase, el compilador produce un
archivo de clase separado por la extensión .class para cada clase compilada.
30
Referencia a los miembros del objeto actual mediante this
Todo objeto puede hacer referencia a sí mismo. mediante la palabra clave this (lo que se conoce como una
referencia this). En un método, la referencia this puede utilizarse en forma implícita y explicita para hacer
referencia a las variables de instancias y otros métodos del objeto en el cual se haya llamado el método.
31
Palabra clave This
A veces deberá hacer referencia al objeto que lo invoca un método. Para permitir esto, Java define esta
palabra clave. Esto puede utilizarse dentro de cualquier método para hacer referencia al objeto actual.
Es decir, esto siempre es una referencia al objeto en el que se invoca el método. Puede utilizar este
cualquier lugar que es permite una referencia a un objeto de tipo de la clase actual. Para entender mejor
a lo que se refiere considere la siguiente versión de Box( ):
this.width = w;
this.height = h;
this.depth = d;
Esta versión de cuadro () funciona exactamente igual que la versión anterior. El uso de esto es redundante,
pero perfectamente correcto. ()
De la caja, esto será siempre se refieren al objeto invocando. Aunque en este caso es redundante, esto es
útil en otros contextos.
32
2.4 Métodos: declaración, mensajes, paso de
parámetros, retorno de valores.
Declaración de métodos
En Java toda la lógica de programación (Algoritmos) está agrupada en funciones o métodos.
Un método es:
Un bloque de código que tiene un nombre, recibe unos parámetros o argumentos (opcionalmente), contiene
sentencias o instrucciones para realizar algo (opcionalmente) y devuelve un valor de algún Tipo conocido
(opcionalmente).
La sintaxis global es:
Tipo_Valor_devuelto nombre_método (
lista_argumentos ) {
bloque_de_codigo;
}
y la lista de argumentos se expresa declarando el tipo y nombre de los mismos (como en las declaraciones
de variables). Si hay más de uno se separan por comas.
33
Por ejemplo: int sumaEnteros ( int a, int b ) {
int c = a + b;
return c;
}
Uso de métodos
Los métodos se invocan con su nombre, y pasando la lista de argumentos entre paréntesis. El conjunto se
usa como si fuera una variable del Tipo devuelto por el método.
Por ejemplo:
int x;
x = sumaEnteros(2,3);
Aunque el método no reciba ningún argumento, los paréntesis en la llamada son obligatorios. Por ejemplo
para llamar a la función haceAlgo, simplemente se pondría:
haceAlgo();
Observese que como la función tampoco devuelve ningún valor no se asigna a ninguna variable. (No hay
nada que asignar). 34
Métodos de mensajes.
A los objetos solo se puede acceder a través de su interfaz pública. ¿Cómo se permite el acceso a un
objeto? Un objeto accede a otro objeto enviándole un mensaje Un mensaje es una petición de un objeto a
otro objeto al que le solicita ejecutar uno de sus métodos. Por convenio, el objeto que envía la petición se
denomina emisor y el objeto que recibe la petición se denomina receptor.
35
Objeto Fecha “ Fecha sumar 3 meses “
receptor método parámetros
Cuando un objeto está inactivo y recibe un mensaje se hace activo. El mensaje enviado por otros objetos
tiene asociado un método que se activará cuando el receptor recibe dicho mensaje. La petición no
especifica cómo se realiza la operación. Tal información se oculta siempre al emisor.
Paso por valor significa que cuando un argumento se pasa a una función, la función recibe una copia del
valor original. Por lo tanto, si la función modifica el parámetro, sólo la copia cambia y el valor original
permanece intacto.
Paso por referencia significa que cuando un argumento se pasa a una función, la función recibe la dirección
de memoria del valor original, no la copia del valor. Por lo tanto, si la función modifica el parámetro, el valor
original en el código que llamó a la función cambia.
36
Vamos a valernos de ejemplos para explicar el mecanismo con el que Java pasa parámetros a los métodos.
Ahora, en la línea 24 pasamos nuestra variable pass al método cambiarObjeto, método que tiene un
parámetro formal de tipo ValorOReferencia. En dicho método, en la línea 11, se realiza una asignación
Suponiendo que el paso de parámetros en Java fuera por referencia, la referencia pass apuntaría ahora a un
nuevo objeto con el valor “Este es un nuevo objeto.”. Pero, al regresar al método main, en la línea 25,
presentamos de nuevo pass, y vemos que el valor con el que fue originalmente declarado se mantiene.
Ahora, vamos a pasar pass y vamos a modificar solamente su único atributo. En la línea 28, pasamos pass
al método cambiarParam1, en donde tenemos la sentencia
en la línea 16. Así, se ha modificado el valor del atributo param1, y al volver al método main, presentamos
pass otra vez:
Al ver esta última operación, quizá alguien pueda decir que Java sí pasa parámetros por referencia, ya que
se modificó el atributo del objeto, pero estaría equivocado: ¿Por qué en cambiarObjeto la variable pass no
sufre ninguna modificación, y en el método cambiarParam1 su atributo se ve efectivamente modificado?
Porque Java no pasa objetos como parámetros [4], sino copias de las referencias a esos objetos. Exacto.
Java pasa parámetros por valor. Pasa referencias a objetos por valor.
39
cambiarObjeto(ValorOReferencia objeto)
Omito los métodos setters, getters y toString() en el diagrama porque no intervienen en la explicación de
este método. Este método tiene un parámetro formal ValorOReferencia objeto. Como Java pasa
parámetros por valor tenemos que objeto, el parámetro formal de cambiarObjeto, es una copia de la
referencia pass, es un alias, mas no es la referencia pass. Siguiente a la llamada al método lo que
tenemos es lo siguiente:
40
Objeto es una copia de la referencia pass, es otra referencia que apunta al mismo lugar. Al ejecutar la
sentencia
41
objeto, que originalmente era una copia de la referencia pass, apunta ahora a un nuevo objeto creado en
otra posición de memoria. Es por eso que de vuelta al main, el objeto apuntado por pass no ha cambiado.
cambiarParam1(ValorOReferencia objeto)
42
Al ejecutar la sentencia
, lo que estamos haciendo es invocar al método setParam1 del objeto apuntado por la referencia objeto. Es
por eso que el atributo param1 del objeto referenciado por pass es efectivamente modificado.
, no declaramos un objeto ValorOReferencia, sino una referencia a un objeto ValorOReferencia. Java tiene
punteros (referencias a objetos), pero no es posible manejarlos con la aritmética con que se manejan en
C++ [5]. No obstante, la implementación de estos punteros es similar en ambos lenguajes:
Una sentencia Java ValorOReferencia valORef; es exactamente igual a una sentencia C++
ValorOReferencia *valORef;.
Una sentencia Java valORef.cambiarParam1(“Otro valor.”); es exactamente igual a una sentencia C++
valORef -> cambiarParam1(“Otro valor.”);.
43
Hay que tener claro entonces, que cuando se escribe una sentencia del estilo
cualquierFuncion(CualquierTipo argumento);
en Java, lo que se pasa no es un objeto, sino una copia de la referencia al objeto. Es importante no
confundirnos. Java pasa objetos por referencia (pasa las referencias a los objetos), pero nunca pasa un
objeto como parámetro, ni parámetros por referencia.
Retorno de valores
44
Veamos un ejemplo de función que calcula la media de dos números. La función recibirá los dos números y
retornará el valor de la media.
function media(valor1,valor2){
var resultado
resultado = (valor1 + valor2) / 2
return resultado
}
Para especificar el valor que retornará la función se utiliza la palabra return seguida de el valor que se
desea devolver. En este caso se devuelve el contenido de la variable resultado, que contiene la media
calculada de los dos números.
Quizás nos preguntemos ahora cómo recibir un dato que devuelve una función. Realmente en el código
fuente de nuestros programas podemos invocar a las funciones en el lugar que deseemos. Cuando una
función devuelve un valor simplemente se sustituye la llamada a la función por ese valor que devuelve. Así
pues, para almacenar un valor de devolución de una función, tenemos que asignar la llamada a esa función
como contenido en una variable, y eso lo haríamos con el operador de asignación =.
Para ilustrar esto se puede ver este ejemplo, que llamará a la función media() y guardará el resultado de la
media en una variable para luego imprimirla en la página.
45
var miMedia
miMedia = media(12,8)
document.write (miMedia)
Múltiples return
En realidad en Javascript las funciones sólo pueden devolver un valor, por lo que en principio no podemos
hacer funciones que devuelvan dos datos distintos.
Nota: en la práctica nada nos impide que una función devuelva más de un valor, pero como sólo podemos
devolver una cosa, tendríamos que meter todos los valores que queremos devolver en una estructura de
datos, como por ejemplo un array. No obstante, eso sería un uso más o menos avanzado que no vamos a
ver en estos momentos.
Ahora bien, aunque sólo podamos devolver un dato, en una misma función podemos colocar más de un
return. Como decimos, sólo vamos a poder retornar una cosa, pero dependiendo de lo que haya sucedido en
la función podrá ser de un tipo u otro, con unos datos u otros.
En esta función podemos ver un ejemplo de utilización de múltiples return. Se trata de una función que
devuelve un 0 si el parámetro recibido era par y el valor del parámetro si este era impar.
46
function multipleReturn(numero){
var resto = numero % 2
if (resto == 0)
return 0
else
return numero
}
Para averiguar si un número es par hallamos el resto de la división al dividirlo entre 2. Si el resto es cero es
que era par y devolvemos un 0, en caso contrario -el número es impar- devolvemos el parámetro recibido.
47
Podría darse el caso de que podemos declarar variables en funciones que tengan el mismo nombre que
una variable global a la página. Entonces, dentro de la función, la variable que tendrá validez es la variable
local y fuera de la función tendrá validez la variable global a la página.
En cambio, si no declaramos las variables en las funciones se entenderá por javascript que estamos
haciendo referencia a una variable global a la página, de modo que si no está creada la variable la crea,
pero siempre global a la página en lugar de local a la función.
Veamos el siguiente código.
function variables_glogales_y_locales(){
var variableLocal = 23
variableGlobal = "qwerty"
}
En este caso variableLocal es una variable que se ha declarado en la función, por lo que será local a la
función y sólo tendrá validez durante su ejecución. Por otra parte variableGlobal no se ha llegado a
declarar (porque antes de usarla no se ha utilizado la palabra var para declararla). En este caso la variable
variableGlobal es global a toda la página y seguirá existiendo aunque la función finalice su ejecución.
Además, si antes de llamar a la función existiese la variable variableGlobal, como resultado de la ejecución
de esta función, se machacaría un hipotético valor de esa variable y se sustituiría por "qwerty".
48
2.5 Constructores y destructores: declaración,
uso y aplicaciones.
Los constructores y destructores son dos tipos de métodos especiales que se ejecutan, respectivamente,
al crear un nuevo objeto y cuando el recolector de basura detecta que ya no lo estamos utilizando y es
posible eliminarlo de la memoria. Hasta ahora no hemos hecho uso nunca ni de los constructores ni de los
destructores puesto que los ejemplos que hemos venido utilizando eran bastante simples, pero a partir de
ahora vamos a empezar a utilizarlos bastante a menudo. Sobre todo en el caso de los constructores, ya
que los destructores no se suelen usar más que en contadas ocasiones.
Para crear un objeto se necesita reservar suficiente espacio en memoria e inicializar los valores de los
campos que representan el estado del objeto.
Este trabajo es realizado por un tipo especial de método denominado constructor.
49
Constructor
Un método constructor de una clase es un método especial que:
• tiene el mismo nombre que la clase y
• no tiene tipo de retorno.
• inicializa el estado de un objeto.
La sintaxis para la declaración de un método constructor es:
Donde:
atributos (opcional) es información declarativa adicional.
modificadores (opcional) se restringen a extern y a los modificadores de acceso.
identificador es el nombre del método constructor (igual al nombre de la clase).
parámetros (opcional) es la lista de parámetros pasados al constructor.
inicializador (opcional). Con el inicializador, el constructor invoca previamente a otro constructor.
50
El inicializador puede ser uno de los siguientes:
• base([listaDeParámetros])
• this([listaDeParámetros])
Cuerpo del constructor es el bloque de programa que contiene las instrucciones para inicializar la instancia
de clase (objeto).
Ejemplo:
class Producto
{
private int clave;
private double precio;
public Producto( int c, double p)
{
clave = c;
precio = p;
}
public double daPrecio( )
{
return precio;
}
}
51
Destructor
En contraposición al constructor, el destructor elimina el vínculo y libera el espacio de memoria de un
objeto, para que pueda ser ocupado nuevamente.
[atributos] ~ <identificador> ( )
{
// Cuerpo del destructor.
}
Notas:
Una clase solamente puede tener un destructor.
Los destructores no pueden heredarse o sobrecargarse.
Los destructores no pueden invocarse, sino que son invocados automáticamente.
Un destructor no acepta modificadores ni parámetros. Por ejemplo, la siguiente es una declaración de un
destructor para la clase Figura:
52
~ Figura()
{
// Instrucciones para limpiar.
}
El destructor llama implícitamente al método Object.Finalize( ) en la clase base object. Por lo tanto, el código
destructor precedente es traducido automáticamente a:
protected override void Finalize( )
{
try
{
// Instrucciones para limpiar.
}
finally
{
base.Finalize( ) ;
}
}
53
Aplicaciones de constructores y destructores
public <nombreClase>( )
{
}
54
Ejemplo
55
2.6 Sobrecarga de métodos.
Un método sobrecargado se utiliza para reutilizar el nombre de un método pero con diferentes argumentos
(opcionalmente un tipo diferente de retorno). Las reglas para sobrecargar un método son las siguientes:
Lo que define qué método es el que se va a llamar son los argumentos que se envían al mismo durante
la llamada. Si se invoca a un método con un String como argumento, se ejecutará el método que tome
un String como argumento, si se manda a llamar al mismo método pero con un float como argumento, se
ejecutará el método que tome un float como argumento y así sucesivamente. Si se invoca a un método
con un argumento que no es definido en ninguna de las versiones sobrecargadas entonces el compilador
arrojará un mensaje de error.
Reglas de la sobrecarga y sobreescritura de métodos:
Ahora que hemos visto ambas formas de reescribir métodos, revisemos las reglas y diferencias entre
ambos tipos de reescritura:
• Argumentos: En un método sobrecargado los argumentos deben de cambiar mientras que en un
método sobreescrito NO deben cambiar.
• El tipo de retorno: En un método sobrecargado el tipo de retorno puede cambiar, en un método
sobreescrito NO puede cambiar, excepto por subtipos del tipo declarado originalmente.
• Excepciones: En un método sobrecargado las excepciones pueden cambiar, en un método
sobreescrito pueden reducirse o eliminarse pero NO deben de arrojarse excepciones nuevas o más
amplias.
• Acceso: En un método sobrecargado puede cambiar, en un método sobreescrito el acceso NO debe
de hacerse más restrictivo (puede ser menos restrictivo).
• Al invocar: En un método sobrecargado los argumentos son los que determinan qué método es el
que se invocará, en un método sobreescrito el tipo de objeto determina qué método es elegido.
57
Ejemplo :
clase base
package sobrekarga;
58
Clase articulo
package sobrekarga;
}
public void fijarprecio(String precio){
System.out.println("No es un valor");
}
public void fijaprecio (double precio){
this.precio=precio;
}
public void mostrarprecio(){
System.out.printf("precio es %.2f",precio);
System.out.println();
}
}
59
Clase edad
package sobrekarga;
A la hora de hablar de operadores vamos a distinguir entre dos tipos, los unarios y los binarios. Los unarios
son aquellos que solo requieren un operando, por ejemplo a++, en este caso el operando es 'a' y el operador
'++'. Los operadores binarios son aquellos que necesitan dos operadores, por ejemplo a+c , ahora el operador
es '+' y los operandos 'a' y 'c'. Es importante esta distinción ya que la programación se hará de forma diferente.
Los operadores que podemos sobrecargar son los unarios, +, -, !, ~, ++, --; y los binarios +, -, *, /, %, &, |, ^, <<,
>>. Es importante decir que los operadores de comparación, ==, !=, <, >, <=, >=, se pueden sobrecargar pero
con la condición que siempre se sobrecargue el complementario, es decir, si sobrecargamos el == debemos
sobrecargar el != 61
Operadores Unarios
En esta sección se verá cómo sobrecargar los operadores unarios, es decir aquellos que toman un solo
operando, como por ejemplo a++. El prototipo de los métodos que van a sobrecargar operadores unarios
será:
public static Operando operator++(Operando a)
Como antes sustituyendo el ++ por cualquier operador unario. El ejemplo dentro de nuestra clase de
números complejos sería:
62
Operadores binarios
Para empezar vamos a sobrecargar el operador suma('+') para que al sumar dos objetos de la clase
ComplexNum, es decir dos números complejos obtengamos un número complejo que será la suma de
ambas partes. Cabe destacar que los prototipos para sobrecargar operadores serán:
public static Operando operator+(Operando a, Operando b)
Este es el prototipo para el operador +, el resto de operadores binarios van a seguir el mismo patrón. Por
tanto el código del método de sobrecarga será el siguiente:
Este método sobrecarga el operador suma para que podamos sumar dos números complejos. Un dato a
tener en cuenta es que los métodos que sobrecargan operadores deben ser static. Como se ve en el
código los operandos son 'a' y 'b', que se reciben como parámetro y el resultado de la operación es otro
número complejo que es el que retorna el método. Por tanto se limita a crear un nuevo número complejo
con ambas partes operadas. De la misma forma podemos crear la sobrecarga del operador resta('-') para
que lleve a cabo la misma función:
63
public static ComplexNum operator-(ComplexNum a, ComplexNum
b)
{
return new ComplexNum(a.Real - b.Real, a.Img - b.Img);
}
Como vemos el método es idéntico solo que sustituyendo los + por -. En este caso el trabajo que hacemos
dentro del método es trivial pero podría ser tan complejo como se quisiera.
64
Operadores Relacionales y Condicionales
Aunque Java y C++ soportan los mismos operadores relacionales, devuelven valores diferentes. Los
operadores relacionales en Java devuelven un tipo booleano, true o false; mientras que en C++
devuelven un valor entero, en donde se puede considerar al valor cero como false y a un valor no-cero
como true.
>
el operando izquierdo es mayor que el derecho
>=
el operando izquierdo es mayor o igual que el derecho
<
el operando izquierdo es menor que el derecho
<=
el operando izquierdo es menor o igual que el derecho
==
el operando izquierdo es igual que el derecho
!=
el operando izquierdo es distinto del derecho
Los operadores relacionales combinados con los operadores condicionales (o lógicos en C++), se utilizan
para obtener expresiones más complejas. Los operadores condicionales que soporta Java son:
&&
65
expresiones izquierda y derecha son true
||
o la expresión izquierda o al expresión de la derecha son true
!
la expresión de la derecha es false
Los programadores C++ se encontrarán con que Java restringe el uso de estos operadores, porque en C++
la representación de true y false es muy diferente a Java. En Java, los operandos de estos operadores
deben ser tipos booleanos, o expresiones que devuelvan un tipo booleano, mientras que en C++ puede ser
cualquier tipo entero o expresión que devuelva un tipo entero, sin restricciones.
Una característica importante del funcionamiento de los operadores && y ||, tanto en Java como en C++ (y
que es pasado a veces por alto, incluso por programadores experimentados) es que las expresiones se
evalúan de izquierda a derecha y que la evaluación de la expresión finaliza tan pronto como se pueda
determinar el valor de la expresión. Por ejemplo, en la expresión siguiente:
( a < b ) || ( c < d )
si la variable a es menor que la variable b, no hay necesidad de evaluar el operando izquierdo del operador
|| para determinar el valor de la expresión entera. En casos de complejas y largas expresiones, el orden en
que se realizan estas comprobaciones puede ser fundamental, y cualquier error en la colocación de los
operandos puede dar al traste con la evaluación que se desea realizar y, estos errores son harto difíciles de
detectar, ya que se debe estudiar concienzudamente el resultado de las expresiones en tiempo de
ejecución para poder detectar el problema.
66
Operadores de Asignación
67
Operadores Ternario if-then-else
Java, lo mismo que C y C++, soporta este operador ternario. No obstante, la construcción utilizada por
este operador es lago confusa, aunque se puede llegar a entender perfectamente cuando uno lee en el
pensamiento lo que está escrito en el código. La forma general del operador es:
expresion ? sentencia1 : sentencia2
en donde expresion puede ser cualquier expresión de la que se obtenga como resultado un valor
booleano, porque en Java todas las expresiones condicionales se evalúan a booleano; y si es true
entonces se ejecuta la sentencia1 y en caso contrario se ejecuta la sentencia2. La limitación que impone
el operador es que sentencia1 y sentencia2 deben devolver el mismo tipo, y éste no puede ser void.
Puede resultar útil para evaluar algún valor que seleccione una expresión a utilizar, como en la siguiente
sentencia:
cociente = denominador == 0 ? 0 : numerador / denominador
Cuando Java evalúa la asignación, primero mira la expresión que está a la izquierda del interrogante. Si
denominador es cero, entonces evalúa la expresión que está entre el interrogante y los dos puntos, y se
utiliza como valor de la expresión completa. Si denominador no es cero, entonces evalúa la expresión
que está después de los dos puntos y se utiliza el resultado como valor de la expresión completa, que se
asigna a la variable que está a la izquierda del operador de asignación, cociente.
En el ejemplo java402.java se utiliza este operador para comprobar que el denominador no es cero antes
de evaluar la expresión que divide por él, devolviendo un cero en caso contrario. Hay dos expresiones,
una que tiene un denominador cero y otra que no.
68
Errores comunes en el uso de Operadores
Uno de los errores más comunes que se cometen cuando se utilizan operadores es el uso incorrecto, o
no uso, de los paréntesis cuando la expresión que se va a evaluar es compleja. Y esto sigue siendo
cierto en Java.
Cuando se programa en C/C++, el error más común es el siguiente:
while( x = y ) {
// . . .
}
EL programador intenta realmente hacer una equivalencia (==) en vez de una asignación. En C/C++ el
resultado de esta asignación siempre será true si y no es cero, y lo más seguro es que esto se convierta
en un bucle infinito. En Java, el resultado de esta expresión no es un booleano, y el compilador espera
un booleano, que no puede conseguir a partir de un entero, así que aparecerá un error en tiempo de
compilación que evitará que el programa se caiga al ejecutarlo. Es decir, este error tan común, para que
se dé en Java tienen que ser x e y booleanos, lo cual no es lo más usual.
Otro error muy difícil de detectar en C++ es cuando se utiliza el operador unario & cuando la lógica
requiere un operador &&; o utilizar el operador unario |, en lugar del operador ||. Este es otro problema
difícil de detectar porque el resultado es casi siempre el mismo, aunque sólo por accidente. En Java, no
ocurre esto y se puede utilizar perfectamente el operador unario & como sinónimo del operador &&, o el
operador | como sinónimo de ||; pero si se hace así, la evaluación de la expresión no concluirá hasta que
todos los operandos hayan sido evaluados, perdiendo de esta forma las posibles ventajas que podría
reportar la evaluación de izquierda a derecha.
69
Moldeo de Operadores
Es lo que se conoce como casting, refiriéndose a "colocar un molde". Java automáticamente cambia el tipo
de un dato a otro cuando es pertinente. Por ejemplo, si se asigna un valor entero a una variable declarada
como flotante, el compilador convierte automáticamente el int a float.
Para realizar un moldeo, se coloca el tipo de dato que se desea (incluyendo todos los modificadores) dentro
de paréntesis a la izquierda del valor. Por ejemplo:
void moldeos() {
int i = 100;
long l = (long)i;
long l2 = (long)200;
}
Como se puede ver, es posible realizar el moldeo de un valor numérico del mismo modo que el de una
variable. No obstante, en el ejemplo el moldeo es superfluo porque el compilador ya promociona los enteros
a flotantes cuando es necesario automáticamente, sin necesidad de que se le indique. Aunque hay otras
ocasiones en que es imprescindible colocar el moldeo para que el código compile.
En C/C++ el moldeo puede causar auténticos quebraderos de cabeza. En Java, el moldeo es seguro, con la
excepción de cuando se realiza una conversión estrecha, es decir, cuando se quiere pasar de un dato que
contiene mucha información a otro que no puede contener tanta, en donde se corre el riesgo de perder
información. Aquí es donde el compilador fuerza a que se coloque un moldeo expreso, indicando al
programador que "esto puede ser algo peligroso, así que si quieres que lo haga, dímelo expresamente".
Cuando se trata de una conversión ancha, no es necesario el moldeo explícito, ya que el nuevo tipo podrá
contener más información que la que contiene el tipo original, no ocasionándose ninguna pérdida de
información, 70
Referencias bibliográficas
• Valbuena, S. J., Torres, S. A. C., & Zapata, D. A. V. (2008). Programación avanzada en java.
ELIZCOM SAS.
• Balena, F., & Rodríguez Vega, J. (2000). Programación avanzada con microsoft visual basic
6.0.
• Taylor, D. (1992). Object-oriented information systems: planning and implementation. John
Wiley & Sons, Inc..
• Ramírez, F. (2007). Introducción a la programación: algoritmos y su implementación en VB.
NET, C#, Java y C++ (No. 005.1 R173i). México, MX: Alfaomega.
71