1.- Programación Orientada a Objetos.
1.1.- Introducción:
Célebre es la frase de Napoleón Bonaparte “divide y
vencerás”, que en determinadas circunstancias puede servir, pero sucumbió ante
la división de un ejército popular en guerrillas.
La frase sería “divide, comunica y vencerás”. De esto
hablamos cuando pensamos en Programación Orientada a Objetos (POO en adelante).
Advertencia: Este tema lamentablemente tiene una elevadísima
carga teórica.
1.2.- ¿Qué es?
Es un estilo de programación donde el diseño gira alrededor
de los datos a manipular, en lugar de alrededor de las operaciones sobre esos
datos como sucedía en la programación secuencial.
La principal ventaja es la estabilidad de los datos en el
tiempo aumentando la reutilización y extensión.
Alan Kay resumió cinco características básicas de Smalltalk,
el primer lenguaje orientado a objetos y uno de los lenguajes en que se basa
Java. Estas características representan un acercamiento puro a la programación
orientada a objetos:
- Todo es un
objeto. Todo se puede representar como objetos en el programa.
- Un programa
es un conjunto de objetos que se indican entre sí lo que tienen que hacer
enviándose mensajes.
- Cada objeto
tiene su propia memoria formada por otros objetos.
- Todo objeto
tiene un tipo asociado.
- Todos los
objetos de un tipo particular pueden recibir los mismos mensajes.
En este capítulo introduciremos los conceptos de la POO en
detalle, y lo haremos no sólo para el lenguaje de programación Java, sino para
todos los lenguajes que permitan la POO.
1.3.- Clases y objetos
En los lenguajes basados en el concepto de POO el concepto
de clase (DIVIDE) constituye el mecanismo básico de organización del código,
agrupando en un mismo módulo datos y operaciones para manipularlos.
Sintácticamente una clase es un conjunto de variables y un
conjunto de operaciones (métodos) que interactúan con las variables,
determinando y modificando el propio estado y comportamiento de un conjunto de
objetos.
El objeto es a la clase lo que un tipo de datos a un valor.
Una clase no es más que una plantilla para generar objetos, y un objeto una
instancia de una clase, es decir, una realización específica de la clase.
Una clase es una agrupación de datos (variables o atributos)
y de funciones (métodos) que operan sobre esos datos. A estos datos y funciones
pertenecientes a una clase se les denomina atributos y métodos. La programación
orientada a objetos se basa en la programación de clases y un programa se
construye a partir de un conjunto de clases.
Los atributos podrán ser tipos primitivos, explicados más
adelante, Java u otras clases.
Los métodos proporcionan acceso a los datos de una clase
para modificarlos, modificando así el estado de un objeto.
Los mensajes (COMUNICA) que se envían a un objeto deben
corresponder a alguno de los métodos definidos en la clase a la que este
pertenece.
Sintaxis:
class nombre-clase{
[modificador-acceso] tipo nombre-attrib;
[modificador-acceso] tipo-retorno nombre-metodo(lista de parametros){
….}
}
1.4.- El constructor
El constructor es un tipo específico de método que siempre
tiene el mismo nombre que la clase y se utiliza para construir objetos de esa
clase. No tiene tipo de dato específico de retorno, ni siquiera void. Esto se
debe a que el tipo específico que debe devolver un constructor de clase es el
propio tipo de la clase.
1.5.- Creación de objetos
Se crean objetos con la palabra reservada new, que reserará
memoria para ubicar el objeto e invocará al constructor de la clase.
Sintaxis:
Nombre-Clase variable = new Nombre-Clase();
A partir de la clase Coche podemos crear distintos objetos,
(instancias de la clase) utilizando el operador new.
Coche
a, b;
a = new Coche (“Ford gran Torino”, 1972.04.09,
150000);
b = new Coche (“Mustang Eleanor”, 1967.06.04,
70000);
Ahora
podemos llamar a los métodos de la clase coche.
a.tasar();
b.comprar();
1.6.- Encapsulación
Es una de las principales ventajas de la POO, tener los
atributos accesible únicamente a través de los métodos.
De esta forma se conserva la integridad y consistencia de
los datos y se mantienen a salvo de accesos y modificaciones indeseadas.
1.7.- Herencia y polimorfismo
La herencia y el polimorfismo permiten reutilizar el
comportamiento de una clase en la definición de otras nuevas. Es decir, permite
reutilizar código evitando esfuerzos innecesarios en el desarrollo de
aplicaciones.
La herencia es una relación entre clases y no entre objetos.
A la clase padre se la denomina “base” y a la hija
“derivada”.
En Java todas las clases heredan como mínimo en última
instancia de la clase Object, si no se especifica que hereda de otra clase.
Sintaxis:
Class clase-hija extends clase-padre{… }
Una clase hereda los miembros de la clase padre
independientemente del modificador de acceso. La palabra reservada “super”
permite acceder a los miembros de la clase padre.
Java no permite la herencia múltiple.
Cuando se trabaja con una clase derivada debe tenerse en
cuenta el orden de instanciación de los constructores de las clases, primero el
de la clase base y después el de la clase derivada.
1.8.- Redefinición de métodos
Es posible crear un método nuevo con el mismo nombre y
parámetros en la clase derivada que en la clase base.
De esta forma se puede modificar, en un aspecto determinado,
el comportamiento de la clase base respecto a la clase derivada.
1.9.- Interfaces
Una interface es una clase abstracta donde todos los métodos
son abstractas.
Una interface puede contener miembros, pero éstos serán
siempre static y final.
Para crear una interface se utiliza la palabra reservada
“interface”.
Para implementar los comportamientos de la interfaz se
utiliza la palabra reservada “implements”.
Todos los métodos de una interface son públicos.
Sintaxis:
Class clase-hija extends clase-padre{… }
Cuando un método funciona como una clase en lugar de con un
interfaz, estamos limitados a utilizar dicha clase o sus subclases. Si
quisiéramos aplicar ese método a una clase que no se encontrara en esa
jerarquía, no podríamos. Las interfaces relajan considerablemente esta
restricción y como resultado escribir un código más reutilizable.
1.10.- Polimorfismo
El polimorfismo permite definir múltiples clases con
funcionalidad diferente pero con métodos y atributos denominados de forma
idéntica, de manera que pueden ser utilizados de forma común.
Una variable es polimórfica cuando su tipo en la declaración
no coincide con el tipo de objeto al que referencia (tiempo de ejecución).
El polimorfismo es la capacidad de acceder a un variado
rango de funciones distintas a través del mismo interfaz, un mismo
identificador puede tener distintas formas (distintas funciones y
comportamientos) dependiendo del contexto en que se utilice.
La idea básica es que una referencia a un objeto de una
determinada clase es capaz de servir de referencia o de nombre a objetos de
cualquiera de sus clases derivadas.
Podríamos hacer:
Figura
a = new Circulo ();
Figura
b = new Triangulo ();
Se han creado 2 referencias de la clase Figura que
posteriormente apuntan a objetos de las clases derivadas Circulo y Triangulo.
El polimorfismo tiene que ver con la relación que se
establece entre la llamada a un método y el código que efectivamente se asocia
con dicha llamada. A esta relación se llama vinculación (binding). La
vinculación puede ser temprana (en tiempo de compilación) o tardía (en tiempo
de ejecución). Con funciones normales o sobrecargadas se utiliza vinculación
temprana (es posible y es lo más eficiente). Con funciones redefinidas en Java
se utiliza siempre vinculación tardía, excepto si el método es final.
Ahora imaginemos que en el ejemplo anterior tanto la clase
Figura como la clase
Circulo tiene el método pintar. Podemos hacer:
a.pintar();
Se podría pensar que invocamos al método pintar de la clase
Figura, ya que realmente es una referencia a Figura. Sin embargo, se invoca el
método apropiado Circulo.pintar() debido al acoplamiento tardío (polimorfismo).
2.- Tipos de datos y modificadores
2.1.- Modificadores de acceso
Los modificadores de acceso definen en nivel de
encapsulación de los diferentes tipos java.
Los modificadores de acceso (public, protected y private)
van en la posición anteriormente comentada.
- Public: si no se especifica nada es el
modificador por defecto. Se puede acceder desde cualquier lugar sin ningún tipo
de restricciones.
- Private: sólo es accesible desde su propia clase.
- Protected: accesible desde su propia clase y sus subclases (posteriormente hablaremos
de herencia).
-
Nivel de Acceso
|
Clase
|
Subclase
|
Paquete
|
Todas
|
Private
|
X
|
X |
X
|
X
|
Protected
|
X
|
X |
X
|
|
Public
|
X
|
X |
|
|
Package
|
X
|
|
|
|
2.2.- Tipos de datos
Existe un conjunto de tipos de datos en Java con un
tratamiento especial, se denominan tipos primitivos y no funcionan como los
objetos, explicados anteriormente.
No es necesario crearlos con la palabra reservada “new”, el
compilador se encarga de reservar memoria implícitamente.
Cada tipo primitivo tiene asociado una clase de envoltura.
Explicadas en cursos sucesivos.
VARIABLES DE TIPOS PRIMITIVOS
|
Nombre
|
Tipo
|
Tamaño
|
Valor por defecto
|
Forma de inicializador
|
Rango
|
boolean
|
Lógico
|
1 bit
|
False
|
boolean a=true
|
True-False
|
char
|
Carácter
|
16 bits
|
NULL
|
char a =’a’
|
Unicodde
|
byte
|
Número entero
|
8 bits
|
0
|
byte a=0
|
-128 a 127
|
short
|
Número entero
|
16 bits
|
0
|
short a = 12
|
-32768 a 32767
|
int
|
Número entero
|
32 bits
|
0
|
int a = 1280
|
-2147483648 a 2147483649
|
long
|
Número entero
|
64 bits
|
0
|
long a = 12500
|
-2^63 a 2^63-1
|
float
|
Número entero
|
32 bits
|
0
|
float a = 3.1
|
-3,4x10^38 a 3,4x10^38
|
double
|
Número entero
|
128 bits
|
0
|
double = 125.335
|
-1,79x10^308 a -1,79x10^308
|
2.3.- Operadores
Un operador toma operandos y produce un nuevo valor a partir
de los mismos.
En Java son importantísimas las reglas de precedencia de
operadores, por ejemplo, suma y resta tienen preferencia respecto a
multiplicación y división.
Si se deuda es recomendable el uso de paréntesis, a fin de
establecer explícitamente el orden de precedencia.
Los operadores matemáticos son los mismos que en otros
lenguajes de programación:
-
Suma +
-
Resta –
-
Multiplicación
*
-
División /
-
Módulo %:
resto de la división entera.
Java permite varios tipos de notaciones:
Notación completa:
int
suma = operando1 + operando2
Notación abreviada:
int
suma +=4
Otros operadores Java matemáticos son el autoincremento ++ y
autodecremento --, que aumentan o disminuyen una unidad al operando utilizado.
Para estos
operadores también existen dos notaciones:
-
Notación
prefija ++a: primero se evalúa el operador y después se asigna.
-
Notación
postfija a++: primero se asigna y después se evalúa el operador.
Operador
|
Utilización
|
Expresión equivalente
|
+=
|
op1 += op2
|
op1 = op1 + op2
|
-=
|
op1 -= op2
|
op1 = op1 - op2
|
*=
|
op1 *= op2
|
op1 = op1 * op2
|
/=
|
op1 /= op2
|
op1 = op1 / op2
|
%=
|
op1 %= op2
|
op1 = op1 % op2
|
Otro tipo de operadores Java son los operadores lógicos AND &&,
OR || y NOT !. Solo se pueden aplicar a tipos de datos boolean.
Operador
|
Nombre
|
Utilización
|
Resultado
|
&&
|
AND
|
op1 && op2
|
true si op1 y op2 son true. Si
op1 es false ya no se evalúa op2
|
||
|
OR
|
op1 || op2
|
true si op1 u op2 son true. Si op1
es true ya no se evalúa op2
|
!
|
negación
|
! op
|
true si op es false y false si op es true
|
&
|
AND
|
op1 & op2
|
true si op1 y op2 son true. Siempre se evalúa op2
|
|
|
OR
|
op1 | op2
|
true si op1 u op2 son true. Siempre
se evalúa op2
|
|
|
|
|
|
Otro tipo de operadores resultando tipos de datos booleanos
son los de comparación IGUAL == y
DISTINTO !=. Puede llevar a confusión a la hora de comparar objetos, pues
comparan la referencia y no el estado del objeto.
Operador
|
Utilización
|
El resultado es true
|
>
|
op1 > op2
|
si op1 es mayor que op2
|
>=
|
op1 >= op2
|
si op1 es mayor o igual
que op2
|
<
|
op1 < op2
|
si op1 es menor que op2
|
<=
|
op1 <= op2
|
si op1 es menor o igual
que op2
|
==
|
op1 == op2
|
si op1 y op2 son iguales
|
!=
|
op1 ¡= op2
|
si op1 y op2 son
diferentes
|
Para comparar los estados de los objetos se utiliza el
operador equals.
Otro tipo de operadores son los operadores de bit y
desplazamiento AND &, OR |, XOR ^, NOT ~, el
operador de desplazamiento a la izquierda << y el operador de
desplazamiento a la derecha >>.
Si llegados a este punto de esta sesión teórica no
comprendes muchos conceptos no te preocupes los ejemplos completan este tema
oportunamente.