viernes, 4 de marzo de 2016

2.7 Sobrecarga de operadores: Concepto y utilidad, operadores unarios y binarios.

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

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

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:

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.


2.6 Sobrecarga de métodos.

La firma de un método es la combinación del tipo de dato que regresa, su nombre y su lista de argumentos.
La sobrecarga de métodos es la creación de varios métodos con el mismo nombre pero con diferentes firmas y definiciones. Java utiliza el número y tipo de argumentos para seleccionar cuál definición de método ejecutar.

Java diferencia los métodos sobrecargados con base en el número y tipo de argumentos que tiene el método y no por el tipo que devuelve.

Tambien existe la sobrecarga de constructores: Cuando en una clase existen constructores múltiples, se dice que hay sobrecarga de constructores.


 

2.5 Constructores y destructores: declaración, uso y aplicaciones.

Constructores y destructores
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.

Constructor
Un método constructor de una clase es un método especial que:
•          tiene el mismo nombre que la clase
•          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.
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).

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


2.4 Métodos: declaración, mensajes, paso de parámetros, retorno de valores.

Los métodos o funciones miembro se definen dentro de la clase a la que pertenecen y constituyen la interfaz o forma de acceder a la estructura interna de los objetos es decir a los datos privados.
Los métodos definen cual son las operaciones que se pueden realizar con los atributos de los objetos de la clase. La ejecución de un programa orientado a objetos consiste, en recibir, interpretar y responder unos objetos a los mensajes que envían otros objetos. En P.O.O. un mensaje está asociado siempre con un método, de manera que cuando un objeto recibe un mensaje la respuesta a ese mensaje es ejecutar el método asociado

Declaración o cabecera:
Modo de acceso: Específica el tipo de acceso permitido indicando que usuarios de la clase podrán acceder a ese método, los métodos son la única forma de acceso a los atributos privados. Por defecto los métodos tienen protección paquete, es decir son accesibles desde cualquier clase que pertenezca al mismo paquete. Todas las clases de un mismo fichero .java pertenecen a un mismo paquete.

Public: Accesible desde cualquier otra clase.

Package: Accesible sólo desde el mismo paquete.

Protected: Se comporta como un método público para los métodos del mismo paquete o de las subclases y para el resto como un método privado.

Prívate: Sólo accesible a través de métodos de la propia clase.

retorno de valores: Un método puede devolver un valor a quien lo llama o no devolver nada. El valor devuelto por un método puede ser de un tipo primitivo de datos o una referencia, pero nunca  puede devolver más de un valor. El valor de retorno nunca puede ser un objeto de una superclase, sí de la misma clase o de una subclase. Si el método no devuelve nada el tipo devuelto por el método es el tipo void.

Paso de parámetros a una función o método.
Los parámetros de una función son variables locales que se inicializan en el momento de la llamada al método. Fuera de la función no se conocen y no pueden ser accedidas. Se crean al entrar en la función y se destruyen al salir de ella.
El paso de parámetros o argumentos a las funciones se puede hacer de dos formas.

Paso por valor , paso por  referencia

2.3 Referencia al objeto actual.

Al acceder a variables de instancia de una clase, la palabra clave this hace referencia a los miembros de la propia clase en el objeto actual; es decir, this se refiere al objeto actual sobre el que está actuando un método determinado y se utiliza siempre que se quiera hace referencia al objetoactual de la clase.
Aquí this.i se refiere al entero i en la clase MiClase, que corresponde al objeto actual. La utilización de this en el tercer constructor de la clase, permite referirse directamente al objeto en sí, en lugar de permitir que el ámbito actual defina la resolución de variables, al utilizar i como parámetro formal y después this para acceder a la variable de instancia del objeto actual.

La utilización de this en dicho contexto puede ser confusa en ocasiones,  y algunos programadores procuran no utilizar variables locales y nombres de parámetros formales que ocultan variables de instancia. Una filosofía diferente dice que en los métodos de inicialización y constructores, es bueno seguir el criterio de utilizar los mismos nombres por claridad, y utilizar this para no ocultar las variables de instancia. Lo cierto es que es más una cuestión de gusto personal que otra cosa el hacerlo de una forma u otra.

2.2 Instanciación de una clase.

En realidad, un objeto es una instancia de una clase, por lo que se pueden intercambiar los términos objeto o instancia (o incluso evento).

Concepto de clase/Instancia.
Como hemos comentado una clase es el tipo que tendrán nuestros objetos, también llamados instancias de esa clase, es decir, la clase es la forma que tendrán los objetos empleados por nuestra aplicación. Un ejemplo puede ser el plano de una casa, el plano sería nuestra clase, pero con ese mismo plano podremos contruir diversas casas que serían los objetos. El plano en sí no es nada es sólamente la especificación de lo que será una casa una vez construida.
Alcance de los miembros: de instancia o de clase.

Cuando creamos una instancia de la clase en ejecución tendremos las variables de instancia, una por cada atributo, y todas integradas dentro de la misma instancia. Todas las instancias de la misma clase tendrán los mismos atributos (nombre y tipo), pero cada una de ellas irá tomando distintos valores para ellos. Es decir, tendremos una copia de los atributos por cada objeto de una clase que creemos. Por ejemplo, tuCoche sería una instancia de la clase Coche y daremos a la variable de instancia velocidadMaxima el valor 180. Mientras que la instancia cocheDeNigell tiene su propia variable velocidadMaxima con el valor 300.


Hay otro tipo de atributos, las llamadas variables de clase, que son los atributos que sólo existen una vez para cada clase. Es decir este tipo de atributos será compartido por todos los objetos que creemos de una clase, de modo que si cambio el valor del atributo en un objeto se verá reflejado en todos los demás. Por ejemplo, el atributo numDeCoches de nuestra clase Coche, de tipo entero, pensado para contar los coches que vamos teniendo en nuestro sistema, sólo debería existir una vez: no tiene sentido que esta variable sea distinta en tuCoche y en cocheDeNigell. Es la misma (única) variable para toda la clase Coche.
El comportamiento, la funcionalidad de la clase, es la concreción de qué puede hacer cada una de las instancias de la clase, cómo cambian su estado, o cómo se relaciona con otras.
Por ejemplo, en la clase Coche podríamos determinar la siguiente funcionalidad:
•          Arrancar
•          Parar (el motor)
•          Acelerar
•          Decelerar
•          Girar
•          Frenar
•          Cambiar la marcha…
Para definir el comportamiento de los objetos definiremos métodos, que no serán más que funciones o procedimientos definidas dentro de la clase que se ejecutan y operan sobre instancias de esa clase. Notar que estos métodos se encapsulan dentro de la clase, es decir, encapsulamos conjuntamente datos y funcionalidad relativa a un mismo objeto, cada objeto debe proveer el mecanismo de almacenamiento y gestión de sus datos, y la funcionalidad relativa a dicho objeto como una entidad cerrada.

Igual que los atributos, también hay métodos de instancia (se aplican sobre una instancia: son los más comunes, sobre un objeto concreto) y métodos de clase (se aplican sobre la propia clase). Lo veremos.

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.

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.


Modificador       Visibilidad
public                 Pública (+)
protectec            Protegida / en la herencia(#)
private                Privada(-)
package              De paquete (~)

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.

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.


2. Clases y objetos

Clases:
Las clases son plantillas que agrupan comportamiento (métodos) y estados (atributos) de los futuros objetos.
Los objetos son instancias de una clase. Usando el símil “variable – tipo” de la programación estructurada, se entiendo que un objeto es una variable que tiene el comportamiento y estados del tipo (objeto)

Objetos:
Se puede decir que un objeto es todo aquello que pueda ser identificable dentro de una especificación de requerimientos o problema y tenga las siguiente características:
Tenga estados definibles (abierto, cerrado).
Posea comportamientos asociados (puede correr, saltar, volar, etc). Éstos son denominados métodos.
Son capaces de interactuar/comunicarse con otros objetos por medio de sus métodos

Una característica propia de este paradigma, es la transparencia entre la implementación a nivel de código y la funcionalidad que provee un método (no me interesa cómo lo haga, sólo que lo haga).