1. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
Lección 11: Métodos
Autor: José Navarro
Referencias:
Texto del curso: Texto del Curso: “Java How to Program: Late Objects Version” 8va. Ed., Cap.
5.
Texto suplementario, Big Java, 3ra Ed., secciones 3.2 a 3.6 y capítulo 6.
Fred Swartz, Java Basics - Control Flow: Methods, url: http://leepoint.net/JavaBasics/index.html,
2007.
Oracle, Java™ Platform, Standard Edition 6 API Specification, url:
http://download.oracle.com/javase/6/docs/api/index.html , 2010.
Objetivos:
Diseñar programas que utilicen métodos de paquetes existentes
Definir y codificar métodos
Diseñar métodos que no devuelven valor
Diseñar métodos que devuelven un valor
Diseñar métodos que reciben argumentos
Bosquejo
11.0 Introducción
11.1 Métodos predefinidos
11.2 Métodos definidos por el programador
11.2.1 Métodos sin argumentos y que no devuelven un valor
11.2.2 Métodos que no reciben argumentos y devuelven un valor
11.2.3 Variables locales
11.2.4 Métodos con argumentos
11.2.5 Argumentos: por valor y por referencia
11.3 Caso de estudio
11.3.1 Descripción del ejercicio
11.3.2 Análisis y Diseño
11.0 Introducción
Los programas de computadoras pueden ser sencillos, complejos o muy complejos. En general,
los programas de computadoras son complejos o muy complejos. La mayoría de los programas
2. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
realiza tres procesos: leer datos, analizar/procesar los mismos y reportar los resultados. Cada uno
de estos procesos puede dividirse a su vez en más subprocesos. Por ejemplo, leer los datos
requiere presentar mensajes a los usuarios para que sepan que datos deben entrar, procesos para
validar los datos, procesos para manejar data no válida, rutinas para manejar mensajes de error,
etc. El análisis/procesamiento de los datos es quizás la parte del programa que se puede dividir
en más subprocesos. Se puede construir un subproceso por cada algoritmo que existe para
procesar los mismos y existen algoritmos cuya complejidad es tal que a su vez deben ser
descompuestos en subprocesos para poder manejarlos apropiadamente. De la misma forma el
proceso de reportar los resultados puede requerir imprimir tablas, gráficas, animación, audio,
señales electrónicas y muchas otras. Vemos entonces que prácticamente cualquier programa con
alguna utilidad practica puede, y casi siempre debe, ser descompuesto en subprocesos.
La idea de dividir los programas en subprocesos (métodos) ofrece grandes ventajas:
Son más fáciles de entender. Debido a que se puede enfocar la atención en partes secciones
específicas del programa en lugar de tratar de analizar el programa como un todo.
Son más fáciles de modificar. Si los subprogramas son creados apropiadamente, realizar
modificaciones en un subprograma requiere una cantidad mínima de cambios, si alguno, en
el resto del programa.
Facilitan el que más personas trabajen de forma simultánea en él. Los subprocesos
permiten que diferentes personas o grupos de personas se dediquen a trabajar con diferentes
grupos de subprocesos.
Facilitan el proceso de mantenimiento. Aunque en este momento no parezca evidente, una
de las actividades relacionadas con el ciclo de vida de los programas que más recursos
requiere es el mantenimiento. Según las necesidades de quienes necesitan los programas
evolucionan, los programas deben evolucionar también. Imagine modificar un programa
escrito por otras personas (generalmente si lo escribió usted mismo hace algunos meses el
efecto es similar) con una longitud de decenas de miles de líneas y que no está dividido en
subprocesos. Evidentemente, mientras mejor esta dividido el programa más fácil resultará
modificar el mismo.
Facilita el proceso de documentación. Resulta más fácil documentar subprocesos cortos y
con objetivos específicos que el programa completo.
Facilitan el reuso de sus partes. Existen diferentes tareas que se utilizan en varios
programas. Si estas tareas se codifican como un subprocesos independientes del resto del
programa, pueden ser utilizadas en otros programas reduciendo así la necesidad de rescribir
código.
En programación a los subprocesos se les da los nombres de subrutinas, funciones, módulos o
métodos. En programación orientada a objetos generalmente se les da el nombre de métodos.
Dado que Java es un lenguaje diseñado para desarrollar programas orientados a objetos
utilizaremos el nombre método para referirnos a los subprocesos.
3. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
11.1 Métodos Predefinidos
En muchos casos, se necesita implementar un subproceso cuyo código no sólo está disponible
sino que ha sido escrito de forma tal que está incluido en los paquetes (un paquete es un conjunto
de archivos que incluyen diferentes clases. Las clases permiten crear objetos a partir de ellas y
contienen métodos que podemos utilizar en nuestros programas) que se proveen junto con el
compilador. Estos paquetes, por lo tanto, están disponibles para que los programadores los
utilicen en sus programas. A las clases que están disponibles en estos paquetes se les llama
clases predefinidas y a los métodos que incluyen se les llama métodos predefinidos. Algunas
clases (con sus métodos) predefinidas se utilizan con tanta regularidad que acompañan al
compilador. Otras son vendidas por terceras compañías. Las clases generalmente se agrupan
según su propósito en archivos conocidos como paquetes. De esta forma tenemos paquetes para
manejar operaciones matemáticas, para realizar operaciones de entrada y salida de datos, para
manejar gráficas, etc. Existen cientos de paquetes y continuamente se crean más.
Para ilustrar el uso de métodos predefinidos observemos el siguiente programa:
1 import java.util.Scanner;
2
3 public class Prueba
4 {
5 public static void main (String args[])
6 {
7 int valor;
8
9 Scanner input = new Scanner(System.in);
10
11 System.out.println("Entre un valor: ");
12 valor = input.nextInt();
13 System.out.println("El valor es: " + valor);
14 }
15 }
Este programa lee un valor y luego lo imprime en la pantalla. En la línea (1) se utiliza import.
Esta palabra clave le indica al compilador que haga disponible al programa la clase o clases que
se encuentran en un paquete particular. En el caso de este ejemplo está solicitando que se haga
disponible la clase Scanner que se encuentra en el paquete util. Los objetos creados a partir de la
clase Scanner nos permiten leer valores del teclado. En la línea 9 se crea un objeto de esta clase
y se le asigna el nombre input (el nombre seleccionado pudo ser otro). En la línea 12 se utiliza el
objeto input para leer un valor entero del teclado. La clase Scanner tiene distintos métodos para
leer valores del teclado. Entre estos métodos se encuentra nextInt(). Este método se utiliza para
leer valores enteros. Otros métodos se utilizan para leer valores de otros tipos. Como estos
métodos no tienen que ser creados por el programador sino que ya fueron previamente creados se
les conoce como métodos predefinidos.
4. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
El siguiente programa muestra otro ejemplo del uso de clases y métodos predefinidos.
1 import java.util.Scanner;
2
3 public class Prueba
4 {
5 public static void main (String args[])
6 {
7 double valor,
8 raizCuadrada;
9
10 Scanner input = new Scanner(System.in);
11
12 System.out.print("Entre el valor: ");
13 valor = input.nextDouble();
14 raizCuadrada = Math.sqrt(valor);
15 System.out.println("La raíz cuadrada del valor es: "
+ raizCuadrada);
16 }
17 }
En este caso en la línea 14 se utiliza el método sqrt() de la clase Math para obtener la raíz
cuadrada de un valor. La clase Math no se tuvo que importar utilizando
import java.lang.Math;
porque el paquete java.lang por defecto está disponible para todos los programas. A
continuación se muestra un ejemplo de la ejecución del programa
Para ver las clases que están disponibles con el compilador de Java provisto por Oracle podemos
acceder a
http://download.oracle.com/javase/6/docs/api/index.html
Existen muchos otros paquetes con clases para incorporar a Java. Algunos son realizados por
compañías y otros por individuos. Unos están disponibles de forma gratuita y otros hay que
Entre el valor: 10
La raíz cuadrada del valor es: 3.1622776601683795
5. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
comprarlos. Cualquier programador puede crear clases y paquetes para Java. De hecho, en
muchas ocasiones nos encontraremos con que desarrollamos clases que usamos con frecuencia
en diferentes programas. Para estos casos lo más conveniente es que creemos nuestros propios
paquetes y los importemos a los programas. No hay necesidad de copiar el código nuevamente
en cada programa.
El próximo programa le pide al usuario que entre los lados de los catetos de un triángulo
rectángulo y devuelve la longitud de la hipotenusa utilizando el teorema de Pitágoras.
1 import java.util.Scanner;
2
3 public class Prueba
4 {
5 public static void main (String args[])
6 {
7 double cateto1,
8 cateto2,
9 hipotenusa;
10
11 Scanner input = new Scanner(System.in);
12
13 System.out.print("Entre la longitud del primer cateto: ");
14 cateto1 = input.nextDouble();
15 System.out.print("Entre la longitud del segundo cateto: ");
16 cateto2 = input.nextDouble();
17 hipotenusa = Math.sqrt(Math.pow(cateto1,2)
+ Math.pow(cateto2,2));
18 System.out.println("La longitud de la hipotenusa es: "
+ hipotenusa);
19 }
20 }
La fórmula para obtener la hipotenusa de un triángulo rectángulo es
22
yxh
en donde x & y representan la longitud de cada cateto. En la línea 17 se evalúa esta ecuación. En
la misma se utiliza, además del método o función sqrt el método pow. Este método se utiliza para
elevar un valor a un exponente. El método tiene el siguiente formato
pow(base, exponente)
En donde base y exponente representan la base y el exponente de la expresión. A continuación se
muestra un ejemplo de la ejecución del programa.
6. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
11.2 Métodos definidos por el programador
Durante el desarrollo de sus trabajos el programador se encontrará con la necesidad de crear sus
propios métodos. Métodos que el programador no tiene disponibles en librerías y que necesita
crear en su programa. Recuerde que no es un requisito del lenguaje el dividir el programa en
múltiples métodos, pero no hacerlo es prácticamente inaceptable en los programas que no son
extremadamente simples. Java provee mecanismos para que el programador cree sus propios
métodos.
Los métodos se componen de dos partes:
- encabezado
- cuerpo
El encabezado de un método tiene el siguiente formato:
<visibilidad> <”static”> <tipo> nombre (lista de argumentos)
Los < > se utilizan para denotar que lo que se incluye dentro de los mismos es opcional. Por
ejemplo, <tipo> indica que escribir el tipo es opcional. O sea, que se puede escribir el mismo o
se puede omitir.
visibilidad tiene tres posibles valores: public, prívate & protected. En alguno de nuestros
códigos hemos visto que se usa public. Estas opciones se utilizan para indicar desde dónde se
puede acceder a los métodos, variables y otros elementos del código. Para efectos de esta
lección no nos ocuparemos de esta opción.
<”static”> indica que podemos escribir o no la palabra static. Si escribimos static la función,
variable o elemento es estático, o sea, static. Si no lo escribimos entonces el elemento es non-
static. En Java, un elemento que no es static no se puede utilizar en un método que es static. Si
observamos los programas que hemos trabajado en el curso en todos ellos el método main ha
sido declarado como static. Por lo tanto, todos los métodos y variable que queramos invocar o
utilizar desde main (y desde cualquier otro método que sea static) tienen que ser static. No todos
los métodos y variables se tienen que declarar static, de hecho, en la mayoría de los casos no se
hace de esta forma como veremos más adelante en cursos de programación orientada a objetos.
Entre la longitud del primer cateto: 10
Entre la longitud del segundo cateto: 15
La longitud de la hipotenusa es: 18.027756377319946
7. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
El tipo indica si el método devolverá o no un valor u objeto y si devuelve uno entonces indica las
características del mismo. Si el método no devolverá resultado alguno entonces el tipo es void.
Se devolverá un resultado entonces el tipo corresponde al del resultado que se devolverá, por
ejemplo: int, double ,boolean, etc. El nombre del método es el nombre que se utiliza para
identificar el mismo y se le aplican las mismas reglas que al nombre de las variables. La lista de
argumentos indica los valores o parámetros que recibe el método y sobre los cuáles deberá
operar. El cuerpo de la función es la parte de la función que se encarga de hacer el
procesamiento de los datos. Si el método devuelve un valor entonces el cuerpo debe incluir la
instrucción return valor en donde valor representa el valor que devuelve el método. Cuando un
método devuelve un valor (a través de su nombre) también se le conoce como función. Los
métodos sqrt() y pow() que vimos anteriormente son ejemplos de funciones.
Para facilitar la explicación de las funciones las clasificaremos utilizando dos características:
1. Las que reciben argumentos y las que no reciben argumentos
2. Las que devuelven un valor y las que no lo devuelven
11.2.1 Métodos sin argumentos y que no devuelven un valor
Este tipo de función es, en general, el más fácil de modificar sin causar impacto en el resto del
programa. Al no recibir ni devolver valores, su impacto en el resto del código es mínimo (si
alguno). Cuando una función no devuelve valor su tipo se declara void. Si, como en este caso,
no tienen argumentos, su nombre va seguido de paréntesis vacíos. A continuación presentamos
un método de este tipo y cuyo propósito es imprimir un mensaje en la pantalla.
static void imprimeSaludo()
{
System.out.println("Hola a todos");
}
Este método, al ser ejecutado, imprime el mensaje Hola a todos en la pantalla. Note que un
método de este tipo no necesita recibir valor alguno del programa (u otro método) que lo invoca
y tampoco necesita devolver valor alguno. A continuación presentamos un programa en donde
se utiliza este método:
1 import java.util.Scanner;
2
3 public class Prueba
4 {
5
6 static void imprimeSaludo()
7 {
8 System.out.println("Hola a todos");
9 }
10
11 public static void main (String args[])
8. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
12 {
13
14 imprimeSaludo();
15
16 }
17 }
Las líneas 6 a la 9 definen al método imprimeSaludo. En este caso los paréntesis a la derecha del
nombre están vacíos porque el método no requiere argumentos. La palabra void indica que el
método no devuelve valor alguno a través de su nombre. Más adelante en la lección veremos
ejemplos de métodos que devuelven valores a través del nombre.
Para ejecutar el método en el programa sólo se necesita escribir el nombre del mismo con los
paréntesis vacíos (línea 14). Si miramos la estructura de main se darán cuenta de que el mismo
es también un método. main es un método especial que se ejecuta automáticamente cuando
comienza la ejecución del programa. Al ejecutar este programa main invoca la ejecución del
método imprimeSaludo. Al ejecutarse imprimeSaludo sus instrucciones se ejecutan y se imprime
el mensaje “Hola a todos” en la pantalla. Podemos ver a los métodos como subprogramas que se
ejecutan dentro de otros.
Luego de que un método se ejecuta la ejecución del programa continúa debajo de la línea desde
donde se invocó el mismo. Este punto se explicará mejor con el siguiente programa:
1 import java.util.Scanner;
2
3 public class Prueba
4 {
5
6 static void imprimeSaludo()
7 {
8 System.out.println("Hola a todos");
9 }
10
11 static void imprimeDespedida()
12 {
13 System.out.println("Hasta a próxima");
14 }
15
16 public static void main (String args[])
17 {
18
19 imprimeSaludo();
20 imprimeDespedida();
21
22 }
23 }
El programa anterior incluye ahora al método imprimeDespedida. En el método principal (main)
se invoca (se pide que se ejecute) primero al método imprimeSaludo y luego al método
9. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
imprimeDespedida. La secuencia de ejecución es la siguiente: cuando se llega a la línea 19 se
invoca a imprimeSaludo y el programa pasa a ejecutar las instrucciones que van de las líneas 6 a
la 9. Cuando se completa su ejecución se regresa a la línea que sigue a la invocación, o sea, la
línea 20. Aquí se invoca a imprimeDespedida, entonces el programa pasa a ejecutar las líneas de
la 11 a la 14. Luego regresa nuevamente a main y finaliza el programa. La ejecución del
programa se muestra a continuación:
11.2.2 Métodos que no reciben argumentos y devuelven un valor
Los métodos pueden devolver un valor u objeto al programa o método que los invoca. Este tipo
de método tiene que indicar a la izquierda del nombre el tipo o clase del valor que devuelve. Los
métodos o funciones que devuelven valores utilizan la instrucción return para indicar el valor
que será devuelto. A continuación se presenta un ejemplo de un programa con un método que
devuelve un valor que el usuario entra por el teclado.
1 import java.util.Scanner;
2
3 public class Prueba
4 {
5
6 static Scanner input = new Scanner(System.in);
7
8 static double getValor()
9 {
10 double elValor;
11
12 System.out.print("Entre el valor: ");
13 elValor = input.nextDouble();
14
15 return (elValor);
16 }
17
18 public static void main (String args[])
19 {
20 double valor;
21
22 valor = getValor();
23 System.out.println("El valor = " + valor);
24
25 }
26 }
Hola a todos
Hasta a próxima
10. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
El método o función que devolverá el valor es getValor. El método le indica al usuario que entre
un valor, lo guarda en la variable elValor y luego lo devuelve con return. Cuando un método
devuelve un valor con return se dice que lo devuelve a través del nombre. Esto es así porque el
nombre del método se puede utilizar desde el lugar de invocación como si fuera una variable,
aunque no se pueden guardar valores en el mismo. Las funciones que devuelven valores se
pueden utilizar en expresiones matemáticas como vimos en el ejemplo de calcular la hipotenusa.
Un ejemplo de la ejecución del programa se muestra a continuación:
Los métodos que hemos creado en estos ejemplos son métodos estáticos. Un método estático
también se conoce como un método de clase (class method) Los métodos estático se pueden
invocar directamente de la clase sin crear un objeto para entonces poder utilizarlos. Por ejemplo,
los métodos sqrt y pow de la clase Math son métodos estáticos y por eso los podemos utilizar sin
crear un objeto de clase Math.
Los métodos estáticos no pueden invocar objetos que no sean estáticos, esta es la razón por la
cual en la línea 6 el objeto input que se creó como una instancia de la clase Scanner se declaró
estático, porque de lo contrario no podría ser invocado por el méodo getValor.
11.2.3 Variables locales
Cuando una variable se define dentro de un método la misma sólo existe dentro del método en
donde se define. O sea, que si en el ejemplo de la sección anterior tratamos de usar la variable
elValor en main recibiremos un mensaje de error al compilar el programa. Se le conoce como
ámbito (scope en inglés) a los lugares del programa en donde una variable existe.
11.2.4 Métodos con argumentos
Además de devolver valores a través del nombre, los métodos pueden recibir valores a través de
una lista de argumentos. La lista de argumentos puede tener cualquier cantidad de ellos,
incluyendo ninguno. Cuando un método recibe argumentos es la lista de los mismos se escribe
entre los paréntesis a la derecha del nombre y se separan por comas. Antes del nombre de cada
argumento se escribe el tipo o clase del mismo, de la misma forma que declaramos variables y
objetos. Los argumentos que se declaran en la lista funcionan como variables locales en el
método, o sea, como si variables que se definieron dentro del método.
El siguiente programa muestra un ejemplo de un método que recibe dos argumentos y devuelve
un valor (se pueden tener métodos que con argumentos que no devuelvan valor alguno). El
método, calculaHipotenusa, recibe como argumentos dos valores de tipo double (los argumentos
Entre el valor: 23
El valor = 23.0
11. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
pueden ser de distintos tipos cada uno) que representan las longitudes de los catetos de un
triángulo rectángulo. El método calcula la longitud correspondiente a la hipotenusa y la
devuelve a través del nombre con un return. El código del método se incluye en las líneas de la
8 a la 13.
main lee los dos valores del los catetos en las líneas 22 y 24. Luego el programa invoca al
método calculaHipotenusa. El método calcula el valor de la hipotenusa y al devolverlo a través
del nombre el resultado se guarda en la variable h. Note que en main el nombre de los dos
catetos son x & y. Sin embargo, en la definición del método los nombres de los argumentos son
cateto1 y cateto2. Eso no es ningún problema porque lo importante es la posición de los
argumentos en la lista. Cuando se invoque el método el valor que se coloque en la primera
posición corresponderá al primer argumento de la lista y el segundo corresponderá al segundo
argumento de la lista. De hecho, aún en el caso en que los nombres de las variables que se usen
para llamar al método se llamen igual que los argumentos, los mismos representarán variables
distintas, aunque se llamen igual.
1 import java.util.Scanner;
2
3 public class Prueba
4 {
5
6 static Scanner input = new Scanner(System.in);
7
8 static double calculaHipotenusa(double cateto1,
double cateto2)
9 {
10 double hipotenusa;
11 hipotenusa = Math.sqrt(Math.pow(cateto1,2) +
Math.pow(cateto2,2));
12 return hipotenusa;
13 }
14
15 public static void main (String args[])
16 {
17 double x,
18 y,
19 h;
20
21 System.out.print("Longitud del primer cateto: ");
22 x = input.nextDouble();
23 System.out.print("Longitud del segundo cateto: ");
24 y = input.nextDouble();
25
26 h = calculaHipotenusa(x,y);
27
28 System.out.println("Hipotenusa = " + h);
29
30 }
31 }
12. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
A continuación se presenta un ejemplo de la ejecución del programa
11.2.5 Argumentos: por valor y por referencia
Cuando se envían o pasan argumentos a un método los mismos se pueden pasar de diferentes
maneras. Una de las maneras de hacerlo es pasarlos por valor (aunque no es exactamente lo
mismo, para efectos de esta discusión trataremos pasar por valor y pasar por copia como si fuera
lo mismo). Cuando se pasa un argumento por valor el argumento, que en el método se trata como
una variable local, se inicializa con el valor que se envía al invocar el método. La forma más
común de pasar argumentos por valor es por medio de una copia. Esto es, el argumento recibe
una copia del valor que se envía en la invocación. En este caso, si el valor del argumento se
modifica dentro del método, no se afecta el valor original en el lugar en donde se realizó la
invocación. A continuación presentamos un programa para explicar un ejemplo concreto.
1 import java.util.Scanner;
2
3 public class ParametersByValueReference {
4
5 static void tryToModify(int value)
6 {
7 System.out.println("in method before assignment: value = " + value);
8 value = 5;
9 System.out.println("in method after assignment : value = " + value);
10 }
11
12
13 public static void main(String[] args)
14 {
15 int value;
16
17 value = 10;
18
19 System.out.println("in main() before method call: value = " + value);
20
21 tryToModify(value);
22
23 System.out.println("in main(): after method call: value = " + value);
24 }
25 }
26
Longitud del primer cateto: 10
Longitud del segundo cateto: 15
Hipotenusa = 18.027756377319946
13. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
El método tryToModify recibe el argumento value, imprime su contenido, le asigna un 5 y
luego lo imprime nuevamente. Este método es invocado desde main(). En main()tenemos la
variable value la cual es local al mismo. En la línea 17 se asigna un valor de 10 a la variable. Esa
variable se envía como argumento al método tryToModify. tryToModify recibirá el valor del
argumento así que originalmente tendrá un valor inicial de 10. Cuando se ejecuta la línea 8 el valor de
value (que aunque se llama igual a la variable de main()es distinta ya que es local a tryToModify)
cambia de 10 a 5. Sin embargo, la modificación del valor no afecta el contenido de la variable value en
main() porque dentro de tryToModify lo que se modificó fue el contenido de la “copia” no del
original.
Para facilitar la visualización de lo que ocurre en las líneas 19 & 23 del programa principal se
imprime el contenido de value antes y después de invocar al método tryToModify. De esta
forma podemos apreciar si el mismo se modificó o no. Dentro de tryToModify se imprime el
contenido de value antes y después de la instrucción de asignación en la línea 8 para poder ver
el valor que recibió del argumento y el que tiene luego de la instrucción de asignación. La
ejecución del programa se muestra a continuación.
in main() before method call: value = 10
in method before assignment: value = 10
in method after assignment : value = 5
in main(): after method call: value = 10
Como podemos apreciar el valor inicial del argumento en el método tryToModify es 10.
Luego de la instrucción de asignación el mismo se cambió a 5. Sin embargo el valor de la
variable en main() permaneció inalterado. En Java los argumentos a los métodos siempre se
pasan por valor.
Otra forma de pasar los argumentos a un método es por referencia. Cuando se pasa un
argumento por referencia en lugar de enviarse una copia del valor se envía una referencia
(dirección de memoria) que indica (también se dice que apunta a) en dónde en memoria se
encuentra el valor. En estos casos, si el contenido del argumento se modifica dentro del método
se modificará el original porque no se está trabajando con una copia sino que se hace referencia
al original.
La Figura 11.1 muestra lo que ocurre cuando se pasa un argumento por valor. En el lugar en
donde se realizó la invocación hay una copia de la variable cuando se ejecuta el método se crea
una copia de la misma con el valor que se pasa a través del argumento.
14. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
Figura 11.1 Cuando se pasa un argumento por valor copia se crea una
copia, dentro del método, del argumento enviado.
Posteriormente, si el valor del argumento se modifica dentro del método lo que se modifica es la
copia pero no el original. Por lo tanto, el contenido de la variable en el programa principal
seguirá siendo el mismo que había al momento de hacer la invocación como se ilustra en la
Figura 11.2.
Figura 11.2 Al modificarse el argumento pasado por copia no se
afecta el contenido de la variable original.
Cuando se pasa un argumento por referencia ocurre lo que se muestra en la Figura 11.3. En
lugar de crearse una copia del valor lo que se envía es una referencia de forma que tanto la
variable (u otra entidad) desde el lugar en donde se hace la invocación como el argumento en el
método apuntan al mismo contenido de memoria.
15. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
Figura 11.3 Cuando se envía un argumento por referencia el mismo a punta a la
misma localización que la variable que se envió en la invocación.
En este caso, si el contenido del argumento se modifica dentro del método el cambio se percibirá
en el ámbito desde el que se hizo la invocación porque se hace referencia al mismo contenido de
memoria. Un ejemplo se muestra en la Figura 11.4.
Figura 11.4 Las modificaciones realizadas al argumento
afectan el contenido de la variable original.
11.3 Caso de estudio
En esta sección presentaremos un ejercicio, el análisis del mismo y el programa que se desarrolló
como solución.
11.3.1 Descripción del ejercicio:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
COMP 2315 – Programación Estructurada
16. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
Diseño de programa para determinar las raíces de una función cuadrática
Introducción
Una ecuación cuadrática es aquella que tiene la forma
cbxaxy 2
Como por ejemplo
835 2
xxy
Para muchas aplicaciones es necesario determinar cuáles son los valores de x que hacen que el
valor de de y sea 0. Valores a los que se les conoce como los ceros o raíces de la función. Uno de
los métodos para determinar estos valores, si es que existen, es utilizar la fórmula
a
acbb
x
2
42
Ésta fórmula puede producir dos resultados. Uno cuando se usa el signo de + luego de la b y otro
si se usa -. O sea que es como si realmente tuviésemos dos fórmulas
a
acbb
x
2
42
&
a
acbb
x
2
42
También puede ocurrir que las raíces no sean reales. Esto ocurre si el valor que se encuentra
dentro de la raíz ( acb 42
) es negativo. Este valor se conoce como el discriminante. Si el valor
del discriminante es 0 entonces las dos raíces son iguales. También puede ocurrir que el valor de
a sea 0. En ese caso no se puede aplicar la fórmula porque tendríamos división por 0.
El Diseño
Diseñe un programa para determinar las raíces de una función cuadrática. El programa le pedirá
al usuario que entre los valores de a, b & c. El programa le indicará al usuario una de las
siguientes:
- Las raíces no son reales
- No se puede aplicar la fórmula porque la función es lineal ( a == 0)
- Las raíces son iguales (e indica el valor)
- Las raíces son (e indica el valor de ambas)
17. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
El programa tendrá una función que le pedirá al usuario que entre los valores de a, b & c. Estos
valores se almacenarán en variables que serán globales para el programa. El programa tendrá otra
función para determinar el valor del discriminante en la cual el valor se devolverá a través del
nombre de la función. Otras dos funciones (raiz1 & raiz2) se utilizarán para determinar las raíces
de la función. Las funciones recibirán los valores de a, b & c a través de los argumentos y
devolverán la raíz a través del nombre. Otra función en el programa se utilizará para imprimir los
resultados. En los casos en que la función no tenga raíces reales el programa tiene que detectarlo
e indicarlo.
Los nombres de las funciones tienen que ser significativos, todos los valores hacia y desde las
funciones se enviarán y recibirán a través de argumentos o el nombre de la función. Todos los
nombres de las variables y argumentos tienen que ser significativos, el programa tiene que estar
bien indentado y organizado. Puede crear funciones adicionales si las necesita.
Entregables
Entregará el archivo del programa en java y un documento en Word donde muestre imágenes con
diferentes ejecuciones del programa. Debe haber por lo menos una ejecución que genere cada
tipo distinto de resultado.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11.3.2 Análisis y Diseño
El procedimiento para obtener las raíces de una función cuadrática, tomando en consideración la
descripción del ejercicio, es el siguiente:
- Leer los valores de los coeficientes
- Determinar si la función es una lineal
- Determinar si la función tiene raíces complejas
- Determinar las raíces de la función de la misma no ser lineal ni tener raíces complejas
- Imprimir los resultados
El primer método que diseñaremos será el correspondiente a la lectura de los coeficientes. Según
las especificaciones del ejercicio, los valores de los coeficientes para este método se manejarán de
forma global. Por lo tanto, el método no recibirá argumentos y tampoco devolverá un valor
utilizando return. El código para el método se muestra a continuación.
static void entradaDeDatos()
{
System.out.println("Entre los valores para los coeficientes de la función
cuadrática");
System.out.print("a = ");
a = input.nextDouble();
System.out.print("b = ");
b = input.nextDouble();
System.out.print("c = ");
18. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
c = input.nextDouble();
}
Note que el método se declaró static y void. Se declaró static (como todos los demás que
diseñaremos para este ejercicio) porque el mismo se invocará desde main que es un método
estático. Se declaró void porque el mismo no devolverá un valor a través de return sino que leerá
los valores y almacenará los mismos en variables globales para que esté accesibles a otras
secciones del programa.
El próximo método que diseñaremos es el que determina si la función es lineal o no.
Prácticamente el método lo que hará será verificar si el coeficiente correspondiente al componente
cuadrático es o no cero (0) y devolverá un valor booleano indicando si es o no lineal. El código
para el método se muestra continuación.
static boolean esLineal(double coeficienteCuadratico)
{
boolean result;
if (coeficienteCuadratico == 0)
{
result = true;
}
else
{
result = false;
}
return (result);
}
Note que en este caso el tipo del método es boolean. Esto se debe a que el método devolverá un
valor true si la función es lineal y false si no lo es. Note que el nombre del método corresponde a
una aseveración que se puede clasificar como cierta o falsa. Este estilo se debe seguir para
cualquier método cuyo resultado sea booleano. Observemos ahora el nombre del argumento que
recibe la función. El nombre del mismo es coeficienteCuadratico. Cuando se leen los
coeficientes en el método entradaDeDatos el nombre correspondiente al coeficiente cuadrático es
a. Sin embargo, cuando se crea un método se puede utilizar cualquier nombre (preferiblemente
significativo) para los argumentos. Para este método pudo utilizarse a como nombre para el
argumento pero utilizamos otro para demostrar que no se tienen que llamar igual.
El próximo método que diseñaremos será el que determine el valor del discriminante. Este
método o función recibirá como argumentos los valores de los coeficientes a, b & c y devolverá
como resultado el valor del discriminante. Note que los argumentos son de tipo double razón por
la cual el resultado de la evaluación es double. Por lo tanto, el tipo asignado a la función será
double. El código de la función se muestra a continuación.
static double discriminante(double a, double b, double c)
{
return(Math.pow(b,2)-4*a*c);
}
19. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
Note que el cuerpo de la función consta de una sola línea ejecutable. En la misma, se determina
el valor del discriminante y se devuelve por medio de return. Aunque puede dar la impresión de
que es trabajo innecesario crear un método para tener una sola línea en este caso esa no es la
situación. Note que determinar el valor del discriminante no es algo que es necesariamente obvio.
Por lo tanto, encerrar el mismo dentro de un método con el nombre discriminante facilita el
entendimiento del código. Otra forma válida en con la que se podría construir el método de la
siguiente.
static double discriminante(double a, double b, double c)
{
double resultado;
resultado = Math.pow(b,2)-4*a*c;
return(resultado);
}
En este caso el código resulta más fácil de entender porque se separa el cómputo del resultado del
código para devolver el resultado.
Los próximos métodos que desarrollaremos son los que se encargan de determinar las raíces de la
función. La ecuación cuadrática utiliza el signo para determinar las raíces de la función
cuadrática. Esto quiere decir que realmente tenemos dos ecuaciones: Una que utiliza el signo + y
otra que usa el signo -. Debido a esto crearemos dos métodos, uno que utiliza la suma y otro que
utilizar la resta. El código de los métodos se muestra a continuación.
static double raiz1(double a, double b, double c)
{
double raiz;
raiz = (-b + Math.sqrt(discriminante(a,b,c)))/(2*a);
return(raiz);
}
static double raiz2(double a, double b, double c)
{
double raiz;
raiz = (-b - Math.sqrt(discriminante(a,b,c)))/(2*a);
return(raiz);
}
Note que en ambos métodos se declarar la variable raiz. No hay conflicto entre las declaraciones
de estas variables porque realmente son variables distintas aunque se llamen igual. Esto se debe a
que las variables son locales a sus respectivos métodos. Cuando una variable se declara dentro de
un método la misma es local y sólo existe dentro del mismo mientras éste se encuentre activo.
Por lo tanto, la variable raíz que se declara dentro del método raíz1 sólo existe mientras se está
ejecutando el método y se destruye cuando el mismo termina. Lo mismo ocurre con la variable
20. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
declarada en raiz2. También queremos volver a recalcar que, aunque se utilizan los nombres a, b
& c para los argumentos por ser los mismos adecuados en este caso, se pueden utilizar nombres
distintos. Por ejemplo, el método raiz1 se pudo escribir de la siguiente forma:
static double raiz1(double coef1, double coef2, double coef3)
{
double raiz;
raiz = (-coef2 + Math.sqrt(discriminante(coef1,coef2,coef3)))/(2*coef1);
return(raiz);
}
Recuerde que lo más importante no es el nombre que se le asigne a los argumentos sino que los
mismos se usen de forma apropiada en el código del método y que en la invocación del mismo se
envíen los valores de forma apropiada. Note que en la versión anterior del método raiz1 además
de modificarse el nombre de los argumentos también se hicieron los cambios correspondientes en
la instrucción que calcula el resultado.
El próximo método que diseñaremos será el que imprime los resultados del programa. Éste
método recibirá un valor que le indicará si la función es lineal o no de forma que imprima el
mensaje correspondiente si es lineal. De la misma forma el método recibirá un valor booleano
que le indica si las raíces son o no complejas para que indique que son complejas si fuera el caso.
El método también recibe como argumentos los valores de las dos raíces de la función los cuales
imprimirá en caso de que la función no sea lineal y que las raíces no sean complejas.
static void muestraResultados(boolean lineal, boolean compleja,
double r1, double r2)
{
System.out.println("La función " + a + "x^2 + " + b + "x + " + c);
if (lineal == true)
{
System.out.println("es una función lineal");
}
else if (compleja == true)
{
System.out.println("tiene raíces complejas");
}
else
{
System.out.println("tiene raíces reales cuyos valores son:");
System.out.println("x = " + r1 + ", x = " + r2);
}
}
Ya que tenemos diseñados los métodos que necesita el programa procederemos a diseñar el
programa principal. En el mismo tenemos que incluir la invocación al método que lee los valores
de los coeficientes, al método que determina si la función es lineal, al que determina sin la
función tiene raíces complejas, los métodos que determinan las raíces de la función en caso de
21. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
que no sean complejas y el método que muestra los resultados. El código del programa principal,
main, se muestra a continuación.
public static void main(String [] args)
{
boolean esLineal = false,
raicesComplejas = false;
double raizMas = 0,
raizMenos = 0;
entradaDeDatos(); //invoca el método que lee los coeficientes
if (esLineal(a)) //para determinar si la función es o no lineal
{
esLineal = true;
}
else if (discriminante(a,b,c) < 0) //si el discrimiante es negativo
{
raicesComplejas = true;
}
else
{
raizMas = raiz1(a,b,c); //si la función no es lineal ni tiene raíces
raizMenos = raiz2(a,b,c); //complejas se buscan las raíces reales
}
muestraResultados(esLineal, raicesComplejas, raizMas, raizMenos);
}
En este caso de estudio hemos hecho el diseño de una forma lineal. Primero diseñamos los
métodos requeridos por el programa principal y luego diseñamos el programa principal. Pero en
la práctica, casi nunca el diseño es lineal sino iterativo. Algunos métodos y secciones del
programa principal se diseñan, se evalúa lo que se tiene, se determina qué métodos o secciones
hacen faltan o se deben mejorar, se rediseña y se vuelve a repetir el proceso una y otra vez hasta
que se tiene el producto deseado. A continuación se tiene el programa completo. Recuerde leer
las notas que se incluyen luego del código.
import java.util.Scanner;
public class AsigCuadratica
{
static Scanner input = new Scanner( System.in );
static double a,
b,
c;
static void entradaDeDatos()
{
System.out.println("Entre los valores para los coeficientes de la función
cuadrática");
System.out.print("a = ");
a = input.nextDouble();
22. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
System.out.print("b = ");
b = input.nextDouble();
System.out.print("c = ");
c = input.nextDouble();
}
static boolean esLineal(double coeficienteCuadratico)
{
boolean result;
if (coeficienteCuadratico == 0)
{
result = true;
}
else
{
result = false;
}
return (result);
}
static double discriminante(double a, double b, double c)
{
return(Math.pow(b,2)-4*a*c);
}
static double raiz1(double a, double b, double c)
{
double raiz;
raiz = (-b + Math.sqrt(discriminante(a,b,c)))/(2*a);
return(raiz);
}
static double raiz2(double a, double b, double c)
{
double raiz;
raiz = (-b - Math.sqrt(discriminante(a,b,c)))/(2*a);
return(raiz);
}
static void muestraResultados(boolean lineal, boolean compleja,
double r1, double r2)
{
System.out.println("La función " + a + "x^2 + " + b + "x + " + c);
if (lineal == true)
{
System.out.println("es una función lineal");
}
else if (compleja == true)
{
23. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
System.out.println("tiene raíces complejas");
}
else
{
System.out.println("tiene raíces reales cuyos valores son:");
System.out.println("x = " + r1 + ", x = " + r2);
}
}
public static void main(String [] args)
{
boolean esLineal = false,
raicesComplejas = false;
double raizMas = 0,
raizMenos = 0;
entradaDeDatos(); //invoca el método que lee los coeficientes
if (esLineal(a)) //para determinar si la función es o no lineal
{
esLineal = true;
}
else if (discriminante(a,b,c) < 0) //si el discriminante es negativo
{
raicesComplejas = true;
}
else
{
raizMas = raiz1(a,b,c); //si la función no es lineal ni tiene raíces
raizMenos = raiz2(a,b,c); //complejas se buscan las raíces reales
}
muestraResultados(esLineal, raicesComplejas, raizMas, raizMenos);
}
}
En la parte superior del código del programa podemos encontrar las siguientes líneas.
static Scanner input = new Scanner( System.in );
static double a,
b,
c;
En la primera de ellas se crea un objeto de clase Scanner que en ese caso ser llama input. Esta
declaración la hemos utilizado mucho en durante el curso pero regresamos a ella para hacer notar
que la declaración indica que el objeto es static. Esto se debe a que el mismo se utiliza o invoca
en el programa desde un método estático que en este ejemplo es entradaDeDatos(). La segunda
línea declara estáticas las variables a, b & c. Como las variables se declaran fuera de los métodos
las mismas son globales a todos los métodos. Sin embargo, en aquellos métodos en donde los
24. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
nombres de los argumentos que reciben tienen los nombres a, b & c estos nombres corresponden
a variables locales dentro de los mismos y no a las variables globales a, b & c.
Miremos un momento el encabezado del método muestraResultados.
static void muestraResultados(boolean lineal, boolean compleja,
double r1, double r2)
Como podemos apreciar del mismo los nombres de los argumentos son lineal, compleja, r1 & r2.
Sin embargo, cuando se invoca el método desde el programa principal se hace de la siguiente
forma:
muestraResultados(esLineal, raicesComplejas, raizMas, raizMenos);
Note que en la invocación los nombres de los argumentos son distintos a los que se usaron
aparecen en el código del método. Como indicamos anteriormente, esto no afecta el
funcionamiento del método. Lo importante es el orden en que se manejan los argumentos. El
primer valor que enviamos (esLineal) indica con true o false si la función es o no lineal y eso es
lo que espera recibir el método muestraResultados a través del argumento lineal. De la misma
forma a través del segundo argumento se envía un valor booleano que indica si la función es
compleja o no. En este ejemplo usamos nombres distintos para demostrar que los nombres de las
variables que utilizamos para invocar a los métodos no tienen que ser los mismos de los
argumentos pero se pueden utilizar los mismos. El tercer y cuarto valor (raizMas & raizMenos)
que se envían al método serán recibidos y almacenados en argumentos r1 & r2 y manejados de la
forma correspondiente. Es importante señalar que aunque los nombres que se usen para los
argumentos al momento de invocar un método pueden ser distintos, los tipos tienen que ser
iguales. Por ejemplo, el encabezado del método muestraResultados espera recibir cuatro
argumentos de tipo boolean, boolean, double, double. Por lo tanto, irrespectivamente de de los
nombres de los argumentos que se usen en la invocación, los tipos tienen que ser iguales a los del
encabezado del método y en el mismo orden. Recuerde que durante la invocación se conecta el
primer argumento de la invocación con el primero del encabezado del método, el segundo con el
segundo y así sucesivamente.
ÏϧÏEntre los valores para los coeficientes de la función cuadrática
¼¼§Ïa = 0
¼¼§Ïb = 1
¼¼§Ïc = 2
ÏϧÏLa función 0.0x^2 + 1.0x + 2.0
ÏϧÏes una función lineal
ÏϧÏEntre los valores para los coeficientes de la función cuadrática
¼¼§Ïa = 1
¼¼§Ïb = -3
25. COMP 2315 : Programación Estructurada Métodos
José Navarro 2011
¼¼§Ïc = 2
ÏϧÏLa función 1.0x^2 + -3.0x + 2.0
ÏϧÏtiene raíces reales cuyos valores son:
ÏϧÏx = 2.0, x = 1.0
ÏϧÏEntre los valores para los coeficientes de la función cuadrática
¼¼§Ïa = 1
¼¼§Ïb = 2
¼¼§Ïc = 3
ÏϧÏLa función 1.0x^2 + 2.0x + 3.0
ÏϧÏtiene raíces complejas