lunes, 22 de octubre de 2012

Pasar Información a un Método


Pasar Información a un Método.

Cuando se escribe un método, se declara el número y tipo de los argumentos requeridos por ese método. Esto se hace en la firma del método. Por ejemplo, el siguiente método calcula el pago mensual de una hipoteca basándose en la cantidad prestada, el interés, la duración de la hipoteca (número de meses) y el valor futuro de la hipoteca (presumiblemente el valor futuro sea cero, porque al final de la hipoteca, ya la habrás pagado):

double hipoteca(double cantidad, double interes, double valorFinal, int numPeriodos)
{
double I, parcial1, denominador, respuesta;

I = interes / 100.0;
parcial1 = Math.pow((1 + I), (0.0 - numPeriodos));
denominador = (1 - parcial1) / I;
respuestar = ((-1 * cantidad) / denominador) - ((valorFinal * parcial1) /
denominador);
return respuesta;
}

Este método toma cuatro argumentos: la cantidad prestada, el interés, el valor futuro y el número de meses. Los tres primeros son números de coma flotante de doble precisión y el cuarto es un entero.

Al igual que este método, el conjunto de argumentos de cualquier método es una lista de declaraciones de variables delimitadas por comas donde cada declaración de variable es un par tipo/nombre:

tipo nombre

Como has podido ver en el ejemplo anterior, sólo tienes que utilizar el nombre del argumento para referirte al valor del argumento.

Tipos de Argumentos

En Java, se puede pasar como argumento a un método cualquier tipo de dato válido en Java. Esto incluye tipos primitivos, como enteros, dobles, etc.. y tipos de referencia como arrays, objetos, etc...
Aquí tienes un ejemplo de un constructor que acepta una array como argumento. En este ejemplo el constructor inicializa un objeto Polygon a partir de una lista de puntos (Point es una clase del paquete java.awt que representa una coordenada xy):

Polygon polygonFrom(Point[] listadePuntos) {
. . .
}

Al contrario que en otros lenguajes, no se puede pasar un método a un método Java. Pero
si se podría pasar un objeto a un método y luego llamar a los métodos del objeto.

Nombres de Argumentos

Cuando se declara un argumento para un método Java, se proporciona el nombre para ese argumento. Este nombre es utilizado dentro del cuerpo del método para referirse al valor del argumento.
Un argumento de un método puede tener el mismo nombre que una variable de la clase.
En este caso, se dice que el argumento oculta a la variable miembro. Normalmente los argumentos que ocultan una variable miembro se utilizan en los constructores para inicializar una clase. Por ejemplo, observa la clase Circle y su constructor:

class Circle {
int x, y, radius;
public Circle(int x, int y, int radius) {
. . .
}
}

La clase Circle tiene tres variables miembro x, y y radius. Además, el constructor de la clase Circle acepta tres argumentos cada uno de los cuales comparte el nombre con la variable miembro para la que el argumento proporciona un valor inicial.
Los nombres de argumentos ocultan los nombres de las variables miembro. Por eso utilizar x, y o radius dentro del cuerpo de la función, se refiere a los argumentos, no a las variables miembro. Para acceder a las variables miembro, se debe referenciarlas a través de this--el objeto actual.

class Circle {
int x, y, radius;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
}

Los nombres de los argumentos de un método no pueden ser el mismo que el de otros argumentos del mismo método, el nombre de cualquier variable local del método o el nombre de cualquier parámetro a una clausula catch() dentro del mismo método.

Paso por Valor
En los métodos Java, los argumentos son pasados por valor. Cuando se le llama, el método recibe el valor de la variable pasada. Cuando el argumento es de un tipo primitivo, pasar por valor significa que el método no puede cambiar el valor. Cuando el argumento es del tipo de referencia, pasar por valor significa que el método no puede cambiar el objeto referenciado, pero si puede invocar a los métodos del objeto y puede modificar las variables accesibles dentro del objeto.
Consideremos esta serie de sentencias Java que intentan recuperar el color actual de un objeto Pen en una aplicación gráfica:

. . .
int r = -1, g = -1, b = -1;
pen.getRGBColor(r, g, b);
System.out.println("red = " + r + ", green = " + g + ", blue = " + b);
. . .

En el momento que se llama al método getRGBColor(), las variables r, g, y b tienen un valor de -1. El llamador espera que el método getRGBColor() le devuelva los valores de rojo, verde y azul para el color actual en las variables r, g, y b.
Sin embargo, el sistema Java pasa los valores de las variables(-1) al método getRGBColor(); no una referencia a las variables r, g, y b. Con esto se podría visualizar la llamada a getRGBColor() de esta forma: getRGBColor(-1, -1, -1).
Cuando el control pasa dentro del método getRGBColor(), los argumentos entran dentro del ámbito (se les asigna espacio) y son inicializados a los valores pasados al método:
class Pen {
int valorRojo, valorVerde, valorAzul;
void getRGBColor(int rojo, int verde, int azul) {
// rojo, verde y azul han sido creados y sus valores son -1
. . .
}
}
Con esto getRGBColor() obtiene acceso a los valores de r, g, y b del llamador a través de sus argumentos rojo, verde, y azul, respectivamente. El método obtiene su propia copia de los valores para utilizarlos dentro del ámbito del método. Cualquier cambio realizado en estas copias locales no serán reflejados en las variables originales del llamador.
Ahora veremos la implementación de getRGBColor() dentro de la clase Pen que implicaba la firma de método anterior:

class Pen {
int valorRojo, valorVerde, valorAzul;
. . .
// Este método no trabaja como se espera
void getRGBColor(int rojo, int verde, int azul) {
rojo = valorRojo;
verde=valorVerde;
azul=valorAzul;
}
}

Este método no trabajará como se espera. Cuando el control llega a la sentencia println() en el siguiente fragmento de código, los argumentos rojo, verde y azul de getRGBColor() ya no existen. Por lo tanto las asignaciones realizadas dentro del método no tendrán efecto; r, g, y b seguiran siendo igual a -1.
. . .
int r = -1, g = -1, b = -1;
pen.getRGBColor(r, g, b);
System.out.println("rojo = " + r + ", verde = " + g + ", azul = " + b);
. . .

El paso de las variables por valor le ofrece alguna seguridad a los programadores: los métodos no puede modificar de forma no intencionada una variable que está fuera de su ámbito. Sin embargo, alguna vez se querrá que un método modifique alguno de sus argumentos. El método getRGBColor() es un caso apropiado. El llamador quiere que el método devuelva tres valores a través de sus argumentos. Sin embargo, el método no puede modificar sus argumentos, y, además, un método sólo puede devolver un valor a través de su valor de retorno. Entonces, ¿cómo puede un método devolver más de un valor, o tener algún efecto (modificar algún valor) fuera de su ámbito?

Para que un método modifique un argumento, debe ser un tipo de referencia como un objeto o un array. Los objetos y arrays también son pasados por valor, pero el valor de un objeto es una referencia. Entonces el efecto es que los argumentos de tipos de referencia son pasados por referencia. De aquí el nombre. Una referencia a un objeto es la dirección del objeto en la memoria. Ahora, el argumento en el método se refiere a la misma posición de memoria que el llamador.

Reescribamos el método getRGBColor() para que haga lo que queremos. Primero introduzcamos un nuevo objeto RGBColor, que puede contener los valores de rojo, verde y azul de un color en formato RGB:

class RGBColor {
public int rojo, verde, azul;
}

Ahora podemos reescribir getRGBColor() para que acepte un objeto RGBColor como argumento. El método getRGBColor() devuelve el color actual de lápiz, en los valores de las variables miembro rojo, verde y azul de su argumento RGBColor:

class Pen {
int valorRojo, valorVerde, valorAzul;
void getRGBColor(RGBColor unColor) {
unColor.rojo = valorRojo;
unColor.verde = valorVerde;
unColor.azul = valorAzul;
}
}

Y finalmente, reescribimos la secuencia de llamada:
. . .
RGBColor penColor = new RGBColor();
pen.getRGBColor(penColor);
System.out.println("ojo = " + penColor.rojo + ", verde = " + penColor.verde + ",
azul = " + penColor.azul);
. . .

Las modificaciones realizadas al objeto RGBColor dentro del método getRGBColor() afectan al objeto creado en la secuencia de llamada porque los nombres penColor (en la secuencia de llamada) y unColor (en el método getRGBColor()) se refieren al mismo objeto.

No hay comentarios:

Publicar un comentario