Está en la página 1de 71

Objetos y Clases

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

Comalcalco, tabasco 22 de Septiembre del 2020 2


Unidad 2: objetos y clases
2.1 Declaración de clases: atributos, métodos, encapsulamiento.
2.2 Instanciación de una clase.
2.3 Referencia al objeto actual.
2.4 Métodos: declaración, mensajes, paso de parámetros, retorno de valores.
2.5 Constructores y destructores: declaración, uso y aplicaciones.
2.6 Sobrecarga de métodos.
2.7 Sobrecarga de operadores

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.

Variables de clase (static)

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

En el ejemplo anterior en la declaración de la clase CuentaBancaria, los métodos saldo y transferencia


son métodos de instancia.

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.

Un ejemplo de llamada a este método dentro de PruebaCuentaBancaria sería:

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.

El encapsulamiento de variables y métodos en un componente de software ordenado es, todavía, una


simple idea poderosa que provee dos principales beneficios a los desarrolladores de software.

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:

MiPunto( int paraX, int paraY ) {

inicia( paramX, paramY );

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

MiPunto p1 = new MiPunto(10, 20);


System.out.println( "p1.- x = " + p1.x + " y = " + p1.y );

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:

MiPunto p2 = new MiPunto(2,3);

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:

p2 = null; // p3 todavía apunta al objeto creado con new

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.

MiPunto p4 = new MiPunto( 10, 20 );


MiPunto p5 = new MiPunto( 42, 99 );
System.out.println("p4.- x = " + p4.x + " y = " + p4.y);
System.out.println("p5.- x = " + p5.x + " y = " + p5.y);

Este es el aspecto de salida cuando lo ejecutamos.


p4.- x = 10 y = 20
p5.- x = 42 y = 99 24
Acceso al objeto
El operador punto (.)
El operador punto (.) se utiliza para acceder a las variables de instancia y los métodos contenidos en un
objeto, mediante su referencia a objeto:
referencia_a_objeto.nombre_de_variable_de_instancia
referencia_a_objeto.nombre_de_método( lista-de-parámetros );
Hemos creado un ejemplo completo que combina los operadores new y punto para crear un objeto MiPunto,
almacenar algunos valores en él e imprimir sus valores finales:

MiPunto p6 = new MiPunto( 10, 20 );


System.out.println ("p6.- 1. X=" + p6.x + " , Y=" + p6.y);
p6.inicia( 30, 40 );
System.out.println ("p6.- 2. X=" + p6.x + " , Y=" + p6.y);

Cuando se ejecuta este programa, se observa la siguiente salida:


p6.- 1. X=10 , Y=20
p6.- 2. X=30 , Y=40

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

this( -1, -1 ); // Llama al constructor parametrizado

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

void inicia2( int x, int y ) {

x = x; // Ojo, no modificamos la variable de instancia!!!

this.y = y; // Modificamos la variable de instancia!!!


}

La destrucción del objeto


La destrucción de los objetos
Cuando un objeto no va a ser utilizado, el espacio de memoria de dinámica que utiliza ha de ser liberado,
así como los recursos que poseía, permitiendo al programa disponer de todos los recursos posibles. A esta
acción se la da el nombre de destrucción del objeto.
En Java la destrucción se puede realizar de forma automática o de forma personalizada, en función de las
características del objeto.
27
La destrucción por defecto: Recogida de basura
El intérprete de Java posee un sistema de recogida de basura, que por lo general permite que no nos
preocupemos de liberar la memoria asignada explícitamente.
El recolector de basura será el encargado de liberar una zona de memoria dinámica que había sido
reservada mediante el operador new, cuando el objeto ya no va a ser utilizado más durante el programa (por
ejemplo, sale del ámbito de utilización, o no es referenciado nuevamente).
El sistema de recogida de basura se ejecuta periódicamente, buscando objetos que ya no estén
referenciados.
La destrucción personalizada: finalize
A veces una clase mantiene un recurso que no es de Java como un descriptor de archivo o un tipo de letra
del sistema de ventanas. En este caso sería acertado el utilizar la finalización explícita, para asegurar que
dicho recurso se libera. Esto se hace mediante la destrucción personalizada, un sistema similar a los
destructores de C++.
Para especificar una destrucción personalizada se añade un método a la clase con el nombre finalize:

El intérprete de Java llama al método finalize(), si existe cuando vaya a


reclamar el espacio de ese objeto, mediante la recogida de basura.
Debe observarse que el método finalize() es de tipo protected void y por
lo tanto deberá de sobreescribirse con este mismo tipo.

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

// Un uso redundante de this.

Box(double w, double h, double d) {

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

• El método se llama sumaEnteros.


• Recibe dos parámetros también enteros. Sus nombres son a y b.
• Devuelve un entero.
En el ejemplo la claúsula return se usa para finalizar el método devolviendo el valor de la variable 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.

Comunicación entre objetos


Los objetos realizan acciones cuando ellos reciben mensajes. El mensaje es esencialmente una orden que
se envía a un objeto para indicarle que realice alguna acción. Esta técnica de enviar mensajes a objetos se
denomina paso de mensajes. Mensajes y métodos son dos caras de la misma moneda. Los métodos son
los procedimientos que se invocan cuando un objeto recibe un mensaje. En terminología de programación
tradicional, un mensaje es una llamada a una función.

Activación y mensajes de un objeto

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.

Estructuralmente un mensaje consta de tres partes:


• Identidad del receptor.
• El método que ha de ejecutar.
• Información especial necesaria para realizar el método invocado (argumentos o parámetros requeridos)

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 de parámetros en Java


Existe comúnmente la creencia errónea de que en Java es posible pasar parámetros por referencia, y no es
así. Java siempre pasa los parámetros por valor. Esta confusión se da debido a que todas las variables de
objeto son referencias a objetos. En el libro “The Java Programming Language” de Ken Arnold y James
Gosling (autores de Java), sección 2.6.1., tenemos la siguiente cita: “There is exactly one parameter passing
mode in Java – pass by value – and that helps keep things simple.” (Existe un solo modo de paso de
parámetros en Java – paso por valor – y eso ayuda a mantener las cosas simples.).
Antes de continuar, vamos a recordar cuáles son las definiciones de paso por valor y paso por referencia:

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.

Tenemos el siguiente programa Java:


1 public class ValorOReferencia {
2
3 private String param1 = new String();
4
5 /** Creates a new instance of PassValueOrReference */
6 public ValorOReferencia(String param1) {
7 this.setParam1(param1);
8}
9
10 public static void cambiarObjeto(ValorOReferencia objeto) {
11 objeto = new ValorOReferencia("Este es un nuevo objeto.");
12 System.out.println("Luego de \"reasignar\" pass: " + objeto);
13 }
14
15 public static void cambiarParam1(ValorOReferencia objeto) {
16 objeto.setParam1("Este es un nuevo valor para param1.");
17 }
18
19 public static void main(String[] args) {
20 ValorOReferencia pass =
21 new ValorOReferencia("Objeto inicial.");
22 System.out.println("Entender que Java pasa parámetros por valor: ");
23 System.out.println("Antes de modificar pass es: " + pass);
24 ValorOReferencia.cambiarObjeto(pass);
25 System.out.println("De vuelta en main pass es: " + pass);
26 System.out.println("Ahora vamos a cambiar sólo param1:");
28 ValorOReferencia.cambiarParam1(pass);
29 System.out.println("De seguro param 1 ha cambiado: " + pass);
30 System.out.println("Parece difícil, pero no lo es.");
31 }
32
33 public String getParam1() {
34 return param1;
35 }
36
37 public void setParam1(String param1) {
38 this.param1 = param1;
39 }
40
41 public String toString() {
42 return "[param1 = " + this.getParam1() + "]";
43 }
44
45 }
37
Remitámonos a línea 20. Declaramos una variable pass, de tipo ValorOReferencia, con su único atributo
param1 inicializado con el valor “Objeto inicial.”. En la línea 23, presentamos el objeto en pantalla, y se
muestra el valor con el que fue declarado.

Salida del programa:


Entender que Java pasa parámetros por valor:
Antes de modificar pass es: [param1 = Objeto inicial.]

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

objeto = new ValorOReferencia("Este es un nuevo objeto.");

, se presenta el objeto “modificado” y el control regresa al método main.

Salida del programa:


Luego de "reasignar" pass: [param1 = Este es un nuevo objeto.]

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.

Salida del programa 38


De vuelta en main() pass es: [param1 = Objeto inicial.]

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

objeto.setParam1("Este es un nuevo valor para param1.");

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:

Salida del programa:

Ahora vamos a cambiar sólo param1:


De seguro param 1 ha cambiado: [param1 = Este es un nuevo valor para param1.]
Parece difícil, pero no lo es.

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)

En main, declaramos una variable

ValorOReferencia pass = new ValorOReferencia("Objeto inicial.");

Se ha creado un objeto ValorOReferencia en cierta posición de memoria y la forma de acceder a él es usar


la referencia pass.

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

objeto = new ValorOReferencia("Este es un nuevo objeto.");

lo que hacemos de hecho es esto:

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)

Desde el método main pasamos a cambiarParam1 la referencia pass:

Incluyo el método setter setParam1(String param1) porque interviene en esta explicación.


cambiarParam1 tiene un parámetro formal ValorOReferencia objeto, que es un alias de pass.

42
Al ejecutar la sentencia

objeto.setParam1("Este es un nuevo valor para param1.");

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

Cuando declaramos variables, por ejemplo,

ValorOReferencia valoRef = new ValorOReferencia();

, 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

Devolución de valores en las funciones


Las funciones en Javascript también pueden retornar valores. De hecho, ésta es una de las utilidades más
esenciales de las funciones, que debemos conocer, no sólo en Javascript sino en general en cualquier
lenguaje de programación. De modo que, al invocar una función, se podrá realizar acciones y ofrecer un valor
como salida.
Por ejemplo, una función que calcula el cuadrado de un número tendrá como entrada a ese número y como
salida tendrá el valor resultante de hallar el cuadrado de ese número. La entrada de datos en las funciones la
vimos anteriormente en el artículo sobre parámetros de las funciones. Ahora tenemos que aprender acerca
de la salida.

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.

Ámbito de las variables en funciones


Dentro de las funciones podemos declarar variables. Sobre este asunto debemos de saber que todas las
variables declaradas en una función son locales a esa función, es decir, sólo tendrán validez durante la
ejecución de la función.
Nota: Incluso, si lo pensamos, nos podremos dar cuenta que los parámetros son como variables que se
declaran en la cabecera de la función y que se inicializan al llamar a la función. Los parámetros también
son locales a la función y tendrán validez sólo cuando ésta se está ejecutando.

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:

[atributos] [modificadores] <identificador> ( [parámetros] ) [inicializador]


{
// Cuerpo del constructor.
}

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.

La sintaxis para declarar un destructor es:

[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

En esta sección se presenta una serie de ejemplos donde se implementarán:


1.- clases que sólo poseen el constructor predeterminado ,
2.- clases con un constructor definido por el programador y
3.- clases con un constructor definido por el programador y el predefinido (que deberá ser reescrito
por el programador).
El constructor predeterminado es incluído automáticamente.
Cuando el programador define un constructor, el predeterminado se anula. En caso de requerir el
constructor predeterminado junto con un constructor definido por el programador, deberá volverse a
escribir el constructor predefinido, de acuerdo al siguiente formato :

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:

• Los métodos sobrecargados deben de cambiar la lista de argumentos.


• Pueden cambiar el tipo de retorno.
• Pueden cambiar el modificador de acceso.
• Pueden declarar nuevas o más amplias excepciones.
• Un método puede ser sobrecargado en la misma clase o en una subclase.

Veamos un método que se desea sobrecargar:


public void cambiarTamano(int tamano, String nombre, float patron){ }

Los siguientes métodos son sobrecargas legales del método cambiarTamano():

public void cambiarTamano(int tamano, String nombre){}


public int cambiarTamano(int tamano, float patron){}
public void cambiarTamano(float patron, String nombre) throws IOException{}
56
Cómo invocar un método sobrecargado:

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;

public class Main {

public static void main(String[] args) {


// TODO code application logic here
articulo objarticulo=new articulo();
objarticulo.fijarprecio("70");
objarticulo.mostrarprecio();

edad objedad= new edad();


objedad.poneredad();
objedad.mostraredad();
}
}

58
Clase articulo

package sobrekarga;

public class articulo {


private double precio;

public void fijarprecio(){


precio=5.50;

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

public class edad {


private int edad;

public void poneredad(){


edad= 22;
}
public void poneredad(String edad){
System.out.println("no es una edad");
}
public void poneredad(int edad){
this.edad= edad;
}
public void mostraredad(){
System.out.printf("la edad es : %d ",edad);
System.out.println();
}
}
60
2.7 Sobrecarga de operadores
La sobrecarga de operadores es la capacidad para transformar los operadores de un lenguaje como por
ejemplo el +, -, etc, cuando se dice transformar se refiere a que los operandos que entran en juego no tienen
que ser los que admite el lenguaje por defecto. Mediante esta técnica podemos sumar dos objetos creados por
nosotros o un objeto y un entero, en vez de limitarnos a sumar números enteros o reales, por ejemplo.
La sobrecarga de operadores ya era posible en c++ y en otros lenguajes, pero sorprendentemente java no lo
incorpora, así que podemos decir que esta característica es una ventaja de c# respecto a java, aunque mucha
gente, esta posibilidad, no lo considera una ventaja porque complica el código.

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:

public static ComplexNum operator++(ComplexNum a)


{

float auximg = a.Img;


float auxreal = a.Real;

return new ComplexNum(++auxreal, ++auximg);


}

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:

public static ComplexNum operator+(ComplexNum a, ComplexNum b)


{
return new ComplexNum(a.Real + b.Real, a.Img + b.Img);
}

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

El operador = es un operador binario de asignación de valores. El valor almacenado en la memoria y


representado por el operando situado a la derecha del operador es copiado en la memoria indicada por el
operando de la izquierda. Al contrario que en C++, el operador de asignación (ni ningún otro) no se puede
sobrecargar en Java.
Java soporta toda la panoplia de operadores de asignación que se componen con otros operadores para
realizar la operación que indique ese operador y luego asignar el valor obtenido al operando situado a la
izquierda del operador de asignación. De este modo se pueden realizar dos operaciones con un solo
operador.
+= -= *= /= %= &= |= ^= <<=
>>= >>>=
Por ejemplo, las dos sentencias que siguen realizan la misma función:
x += y;
x = x + y;
Y las otras comprobaciones siguen el mismo patrón. C++ no soporta el operador >>>= porque tampoco
soporta el operador a nivel de bits de desplazamiento sin signo (>>>).

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

También podría gustarte