CLASES,OBJETIVOS Y METODO

Tipos de métodos
Objetivos:
a) Profundizar en el concepto de método de una clase e indicar los tipos de
métodos en Java: métodos de instancia y métodos de clase
b) Interpretar el código fuente de una aplicación Java donde aparecen métodos de
distintos tipos
c) Construir una aplicación Java sencilla,  convenientemente especificada,  que
emplee clases con diferentes métodos.
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. Además se cierra el capítulo con los métodos de clase o estáticos de la clase Math.
14.1. 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:
idReferencia.idMetodo(parametros);    // Llamada tipica a un metodo de instancia
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.
public double saldo() {
   return saldo;
}
public void transferencia( CuentaBancaria origen ) {
   saldo += origen.saldo;
   origen.saldo=0;
}
Ejemplos de llamada a estos métodos dentro de PruebaCuentaBancaria:
CuentaBancaria c1 = new CuentaBancaria();
CuentaBancaria c2 = new CuentaBancaria(20.0);
c1.transferencia(c2);
System.out.println("Cuenta con: " + c1.saldo() + " euros");154  A. García-Beltrán y J.M. Arranz
14.2. 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 precediendolos con  el identificador de la clase, sin necesidad de utilizar  el de  una
instancia.
IdClase.idMetodo(parametros);    // Llamada tipica a un metodo de clase
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.
public static void incCuentas () {
    totalCuentas++;
}
Un ejemplo de llamada a este método dentro de PruebaCuentaBancaria sería:
CuentaBancaria.incCuentas();
Las diferencias entre los métodos de instancia y los de clase se resumen en la Tabla 14.1.
Tabla 14.1. Diferencias entre los métodos de instancia y los métodos de clase
Métodos... Modificador en
la declaración
Sintaxis de llamada Operan normalmente...
... de instancia --
(por defecto)
instancia.metodo(parametros) Sobre variables de instancia
... de clase static Clase.metodo(parametros) Sobre variables de clase o
sobre otros datos
Los métodos de clase o estáticos se pueden considerar equivalentes a las rutinas (globales) de
otros lenguajes de programación como Pascal o C. Como ejemplos típicos de métodos estáticos
pueden indicarse los métodos de Java correspondientes a las funciones matemáticas sin, cos, exp,
pow... de la clase  java.lang.Math (Tabla  14.2). Las llamadas a estos métodos se realizan
anteponiendo el identificador de la clase  Math al identificador del método:
Math.sin(angulo)… Programación orientada a objetos con Java 155
Tabla 14.2. Métodos estáticos de la clase Math
Modificadores Identificador y parámetros Función
static double abs(double a) Devuelve el valor absoluto de un dato de tipo double.
static float abs(float a) Devuelve el valor absoluto de un dato de tipo float.
static int abs(int a) Devuelve el valor absoluto de un dato de tipo int.
static long abs(long a) Devuelve el valor absoluto de un dato de tipo long.
static double acos(double a) Devuelve el valor del arco coseno de un ángulo entre 0 y .
static double asin(double a) Devuelve el valor del arco seno de un ángulo entre –/2 y /2.
static double atan(double a) Devuelve el arco tangente de un ángulo entre –/2 y /2
static double atan2(double a,
double b)
Devuelve el  ángulo en polares correspondientes a las
coordenadas rectangulares.
static double ceil(double a) Devuelve el menor entero (en formato  double) que no es
menor que el parámetro.
static double cos(double a) Devuelve el coseno de un ángulo
static double exp(double a) Devuelve el valor de la función exponencial (e
a
)
static double floor(double a) Devuelve el mayor entero (en formato  double) que no es
mayor que el parámetro.
static double IEEEremainder(double f1,
double f2)
Devuelve el resto (en formato double) de la división entre los
dos parámetros según la especificación IEEE 754
static double log(double a) Devuelve el logaritmo neperiano de un valor.
static double max(double a, double b) Devuelve el mayor de dos valores de tipo double.
static float max(float a, float b) Devuelve el mayor de dos valores de tipo float.
static int max(int a, int b) Devuelve el mayor de dos valores de tipo int.
static long max(long a, long b) Devuelve el mayor de dos valores de tipo long.
static double min(double a, double b) Devuelve el menor de dos valores de tipo double.
static float min(float a, float b) Devuelve el menor de dos valores de tipo float.
static int min(int a, int b) Devuelve el menor de dos valores de tipo int.
static long min(long a, long b) Devuelve el menor de dos valores de tipo long.
static double pow(double a, double b) Devuelve el valor del primer parámetro elevado al segundo
static double random() Devuelve un valor aleatorio de tipo double mayor o igual que
cero y menor que 1.
static double rint(double a) Devuelve el valor entero (en formato double) más cercano.
static long round(double a) Devuelve el valor entero (long) más cercano al parámetro.
static int round(float a) Devuelve el valor entero (int) más cercano al parámetro.
static double sin(double a) Devuelve el seno de un ángulo
static double sqrt(double a) Devuelve la raiz cuadrada positiva del parámetro double.
static double tan(double a) Devuelve la tangente de un ángulo
static double toDegrees(double angulo) Devuelve el resultado de la conversión de un ángulo dado en
radianes a grados
static double toRadians(double angulo) Devuelve la conversión de un ángulo dado en grados a radianes


CLASES Y OBJETOS
A. Introducción

Durante los capítulos anteriores se han dado unas nociones básicas de la sintaxis de Java. A partir de ahora es cuando entramos la verdadera potencia de Java como lenguaje orientado a objetos: las clases y los objetos.
Aquellas personas que nunca hayan programado en un lenguaje orientado a objeto, o que no conozcan las nociones básicas de paradigma conviene que lean el capítulo "I.1 Introducción a la programación orientada a objetos" de este tutorial, ya que a partir de ahora los conceptos que en él se exponen se darán por entendidos.
Durante todo este capítulo se va a trabajar en la construcción de una clase MiPunto, que modeliza un punto en un espacio plano:
class MiPunto{
int x, y;
int metodoSuma( int paramX, int paramY ) {
return ( paramX + paramY );
}
double distancia(int x, int y) {
int dx= this.x – pX;
int dy = this.y – pY;
return Math.sqrt(dx*dx + dy*dy);
}
void metodoVacio( ) { }
void inicia( int paramX, int paramY ) {
x = paramX;
y = paramY;
}
void inicia2( int x, int y ) {
x = x; // Ojo, no modificamos la variable de instancia!!!
this.y = y; // Modificamos la variable de instancia!!!
}
MiPunto( int paramX, int paramY ) {
this.x = paramX; // Este this se puede omitir
y = paramY; // No hace falta this
}
MiPunto() {
inicia(-1,-1); //Por defecto ; this(-1,-1) hace lo mismo
}
}
B. Definición de una clasea.) Introducción
El elemento básico de la programación orientada a objetos en Java es la clase. Una clase define la forma y comportamiento de un objeto.
Para crear una clase sólo se necesita un archivo fuente que contenga la palabra clave reservada class seguida de un identificador legal y un bloque delimitado por dos llaves para el cuerpo de la clase.
class MiPunto {
}

Un archivo de Java debe tener el mismo nombre que la clase que contiene, y se les suele asignar la extensión ".java". Por ejemplo la clase MiPunto se guardaría en un fichero que se llamase MiPunto.java. Hay que tener presente que en Java se diferencia entre mayúsculas y minúsculas; el nombre de la clase y el de archivo fuente han de ser exactamente iguales.
Aunque la clase MiPunto es sintácticamente correcta, es lo que se viene a llamar una clase vacía, es decir, una clase que no hace nada. Las clases típicas de Java incluirán variables y métodos de instancia. Los programas en Java completos constarán por lo general de varias clases de Java en distintos archivos fuente.
Una clase es una plantilla para un objeto. Por lo tanto define la estructura de un objeto y su interfaz funcional, en forma de métodos. Cuando se ejecuta un programa en Java, el sistema utiliza definiciones de clase para crear instancias de las clases, que son los objetos reales. Los términos instancia y objeto se utilizan de manera indistinta. La forma general de una definición de clase es:
class Nombre_De_Clase {
tipo_de_variable nombre_de_atributo1;
tipo_de_variable nombre_de_atributo2;
// . . .
tipo_devuelto nombre_de_método1( lista_de_parámetros ) {
cuerpo_del_método1;
}
tipo_devuelto nombre_de_método2( lista_de_parámetros ) {
cuerpo_del_método2;
}
// . . .
}
Los tipos tipo_de_variable y tipo_devuelto, han de ser tipos simples Java o nombres de otras clases ya definidas. Tanto Nombre_De_Clase, como losnombre_de_atributo y nombre_de_método, han de ser identificadores Java válidos.
b.) Los atributos
Los datos se encapsulan dentro de una clase declarando variables dentro de las llaves de apertura y cierre de la declaración de la clase, variables que se conocen como atributos. Se declaran igual que las variables locales de un método en concreto.
Por ejemplo, este es un programa que declara una clase MiPunto, con dos atributos enteros llamados x e y.
class MiPunto {
int x, y;
}
Los atributos se pueden declarar con dos clases de tipos: un tipo simple Java (ya descritos), o el nombre de una clase (será una referencia a objeto, véase el punto C.a de este mismo apartado).
Cuando se realiza una instancia de una clase (creación de un objeto) se reservará en la memoria un espacio para un conjunto de datos como el que definen los atributos de una clase. A este conjunto de variables se le denomina variables de instancia.
c.) Los métodos
Los métodos son subrutinas que definen la interfaz de una clase, sus capacidades y comportamiento.
Un método ha de tener por nombre cualquier identificador legal distinto de los ya utilizados por los nombres de la clase en que está definido. Los métodos se declaran al mismo nivel que las variables de instancia dentro de una definición de clase.
En la declaración de los métodos se define el tipo de valor que devuelven y a una lista formal de parámetros de entrada, de sintaxis tipo identificador separadas por comas. La forma general de una declaración de método es:
tipo_devuelto nombre_de_método( lista-formal-de-parámetros ) {
cuerpo_del_método;
} 
Por ejemplo el siguiente método devuelve la suma de dos enteros:
int metodoSuma( int paramX, int paramY ) {
return ( paramX + paramY );
}
En el caso de que no se desee devolver ningún valor se deberá indicar como tipo la palabra reservada void. Así mismo, si no se desean parámetros, la declaración del método debería incluir un par de paréntesis vacíos (sin void):
void metodoVacio( ) { };
Los métodos son llamados indicando una instancia individual de la clase, que tendrá su propio conjunto único de variables de instancia, por lo que los métodos se pueden referir directamente a ellas.
El método inicia() para establecer valores a las dos variables de instancia sería el siguiente:
void inicia( int paramX, int paramY ) {
x = paramX;
y = paramY;
}
C. La instanciación de las clases: Los objetosa.) 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 comoreferencias 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 nulles 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.
b.) 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).
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 );
}
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 mainde la clase que se le indique como parámetro.
Para más información sobre cómo crear y ejecutar un programa, así como los tipos de programas que se pueden crear en Java, véase el capítulo "II.12. Creación de programas Java" de este tutorial.
c.) 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
Aunque se haya asignado null a p2p3 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 denominarecogida 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
D. Acceso al objetoa.) 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.
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étodop6.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.
b.) 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 parametrizadoMiPunto(x,y) para terminar de iniciar la instancia:
MiPunto() { 
this( -1, -1 ); // Llama al constructor parametrizado
}
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!!!
}
E. La destrucción del objetoa.) La destrucción de los objetos


b.) 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.
c.) 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:

class ClaseFinalizada{
ClaseFinalizada() { // Constructor
// Reserva del recurso no Java o recurso compartido
}
protected void finalize() {
// Liberación del recurso no Java o recurso compartido
}
}
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.