CodeGym/Blog Java/Random-ES/Métodos en Java
Autor
John Selawsky
Senior Java Developer and Tutor at LearningTree

Métodos en Java

Publicado en el grupo Random-ES
¡Hola de nuevo! En la última lección nos familiarizamos con las clases y los constructores, y aprendimos a crear los nuestros propios. Hoy nos familiarizaremos mejor con los Métodos de Java, una parte esencial de las clases. Un método en Java es un conjunto de comandos que le permiten realizar una operación específica en un programa. En otras palabras, un método es una función; algo que su clase es capaz de hacer. En otros lenguajes de programación, los métodos a menudo se denominan "funciones", pero en Java la palabra "método" es más común. :) Si recuerdas, en la última lección creamos métodos simples para una clase Cat , para que nuestros gatos pudieran decir maullar y saltar:
public class Cat {

    String name;
    int age;

    public void sayMeow() {
        System.out.println("Meow!");
    }

    public void jump() {
        System.out.println("Pounce!");
    }

    public static void main(String[] args) {
        Cat smudge = new Cat();
        smudge.age = 3;
        smudge.name = "Smudge";

        smudge.sayMeow();
        smudge.jump();
    }
}
sayMeow() y jump() son métodos de nuestra clase. Y ejecutar estos métodos da como resultado la siguiente salida de la consola:
Meow!
Pounce!
Nuestros métodos son bastante simples: simplemente envían texto a la consola. Pero en Java, los métodos tienen una tarea importante: realizan acciones sobre los datos de un objeto. Cambian los datos del objeto, lo transforman, lo muestran y hacen otras cosas con él. Nuestros métodos actuales no hacen nada con los datos del objeto Cat . Veamos un ejemplo más ilustrativo:
public class Truck {

    int length;
    int width;
    int height;
    int weight;

    public int getVolume() {
        int volume = length * width * height;
        return volume;
    }
}
Por ejemplo, aquí tenemos una clase que representa un Camión . El semirremolque tiene una longitud, un ancho, una altura y un peso (que necesitaremos más adelante). En el método getVolume() , realizamos cálculos, convirtiendo los datos de nuestro objeto en un número que representa su volumen (multiplicamos la longitud, el ancho y la altura). Este número será el resultado del método. Tenga en cuenta que la declaración del método se escribe como public int getVolume . Eso significa que este método debe devolver un int . Calculamos el valor de retorno del método y ahora debemos devolverlo al programa que llamó a nuestro método. Para devolver el resultado de un método en Java, usamos la palabra clave return. volumen de retorno;

Parámetros del método Java

Podemos pasar valores llamados "argumentos" a un método cuando lo llamamos. La declaración de un método incluye una lista de variables que nos dicen el tipo y el orden de las variables que el método puede aceptar. Esta lista se denomina "parámetros del método". El método getVolume() de nuestra clase Truck actualmente no define ningún parámetro, así que intentemos extender nuestro ejemplo de camión. Cree una nueva clase llamada BridgeOfficer . Este es un oficial de policía de servicio en un puente, que revisa todos los camiones que pasan para ver si su carga excede el peso permitido.
public class BridgeOfficer {

    int maxWeight;

    public BridgeOfficer(int normalWeight) {
        this.maxWeight = normalWeight;
    }

    public boolean checkTruck(Truck truck) {
        if (truck.weight > maxWeight) {
            return false;
        } else {
            return true;
        }
    }
}
El método checkTruck acepta un argumento, un objeto Truck , y determina si el oficial permitirá o no que el camión pase por el puente. Dentro del método, la lógica es bastante simple: si el peso del camión excede el máximo permitido, el método devuelve falso . Tendrá que buscar otro camino :( Si el peso es menor o igual al máximo, puede pasar, y el método devuelve verdadero. Si aún no comprende completamente las frases "devolver" o "el método devuelve un valor", tomemos un descanso de la programación y considerémoslas usando un ejemplo simple de la vida real. :) Digamos que te enfermas y no vas al trabajo por unos días. Vas al departamento de contabilidad con la nota de tu médico, porque se supone que la licencia por enfermedad se paga. Si comparamos esta situación con los métodos, entonces el contador tiene un paySickLeave()método. Pasas una nota del médico como argumento para este método (sin ella, el método no funcionará y no te pagarán). Luego se hacen los cálculos necesarios dentro del método usando su nota (el contador la usa para calcular cuánto debe pagarle la empresa), y se le devuelve el resultado de su trabajo (una cantidad de dinero). Nuestro programa funciona de manera similar. Llama a un método, le pasa datos y finalmente recibe un resultado. Aquí está el método main() de nuestro programa BridgeOfficer :
public static void main(String[] args) {
    Truck first = new Truck();
    first.weight = 10000;
    Truck second = new Truck();
    second.weight = 20000;

    BridgeOfficer officer = new BridgeOfficer(15000);
    System.out.println("Truck 1! Can I go, officer?");
    boolean canFirstTruckGo = officer.checkTruck(first);
    System.out.println(canFirstTruckGo);

    System.out.println();

    System.out.println("Truck 2! And can I?");
    boolean canSecondTruckGo = officer.checkTruck(second);
    System.out.println(canSecondTruckGo);
}
Creamos dos camiones con cargas de 10.000 y 20.000. Y el puente donde trabaja el oficial tiene un peso máximo de 15.000. El programa llama al método oficial.checkTruck(primero) . El método calcula todo y luego devuelve verdadero , que luego el programa guarda en la variable booleana canFirstTruckGo . Ahora puedes hacer lo que quieras con él (tal como puedes hacerlo con el dinero que te dio el contador). Al final del día, el código
boolean canFirstTruckGo = officer.checkTruck(first);
se reduce a
boolean canFirstTruckGo =  true;
Aquí hay un punto muy importante: la declaración de devolución no solo devuelve el valor de retorno del método, ¡también detiene la ejecución del método! ¡ Cualquier código que venga después de la declaración de devolución no se ejecutará!
public boolean checkTruck(Truck truck) {

    if (truck.weight > maxWeight) {
        return false;
        System.out.println("Turn around, you're overweight!");
    } else {
        return true;
        System.out.println("Everything looks good, go ahead!");
    }
}
¡Los comentarios del oficial no se mostrarán porque el método ya ha devuelto un resultado y ha terminado! El programa vuelve al lugar donde se llamó al método. No tiene que estar atento a esto: el compilador de Java es lo suficientemente inteligente como para generar un error cuando intenta escribir código después de una declaración de devolución .

Vengadores: guerra de parámetros

Hay situaciones en las que querremos varias formas de llamar a un método. ¿Por qué no crear nuestra propia inteligencia artificial? Amazon tiene Alexa, Apple tiene Siri, entonces, ¿por qué no deberíamos tener uno? :) En la película Iron Man, Tony Stark crea su propia inteligencia artificial increíble, Jarvis. Rindamos homenaje a ese increíble personaje y nombremos nuestra IA en su honor. :) Lo primero que tenemos que hacer es enseñar a Jarvis a saludar a las personas que entran en la habitación (sería raro que un intelecto tan asombroso resultara ser descortés).
public class Jarvis {

    public void sayHi(String name) {
        System.out.println("Good evening, " + name + ". How are you?");
    }

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark");
    }
}
Salida de la consola:
Good evening, Tony Stark. How are you?
¡Muy bien! Jarvis ahora puede recibir invitados. Por supuesto, la mayoría de las veces será su maestro, Tony Stark. ¡Pero qué pasa si no viene solo! Nuestro método sayHi() solo acepta un argumento. Por lo tanto, solo puede saludar a una persona que ingresa a la habitación e ignorará a la otra. No es muy educado, ¿no estás de acuerdo? :/

Sobrecarga del método Java

En este caso, podemos resolver el problema simplemente escribiendo 2 métodos con el mismo nombre, pero diferentes parámetros:
public class Jarvis {

    public void sayHi(String firstGuest) {
        System.out.println("Good evening, " + firstGuest + ". How are you?");
    }

    public void sayHi(String firstGuest, String secondGuest) {
        System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
    }
}
Esto se llama sobrecarga de métodos. La sobrecarga de métodos permite que nuestro programa sea más flexible y se adapte a varias formas de trabajar. Repasemos cómo funciona:
public class Jarvis {

    public void sayHi(String firstGuest) {
        System.out.println("Good evening, " + firstGuest + ". How are you?");
    }

    public void sayHi(String firstGuest, String secondGuest) {
        System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
    }

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark");
        jarvis.sayHi("Tony Stark", "Captain America");
    }
}
Salida de la consola:
Good evening, Tony Stark. How are you?
Good evening, Tony Stark and Captain America. How are you?
Excelente, ambas versiones funcionaron. :) ¡Pero no solucionamos el problema! ¿Qué pasa si hay tres invitados? Por supuesto, podríamos volver a sobrecargar el método sayHi() para que acepte tres nombres de invitados. Pero podría haber 4 o 5. Todo el camino hasta el infinito. ¿No hay una mejor manera de enseñar a Jarvis a manejar cualquier cantidad de nombres, sin sobrecargar el método sayHi() un millón de veces? :/ ¡Claro que lo hay! Si no lo hubiera, ¿crees que Java sería el lenguaje de programación más popular del mundo? ;)
public void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ". How are you?");
    }
}
Cuando ( String... nombres ) se usa como parámetro, indica que se pasará una colección de cadenas al método. No tenemos que especificar de antemano cuántos habrá, por lo que ahora nuestro método es mucho más flexible:
public class Jarvis {

    public void sayHi(String...names) {
        for (String name: names) {
            System.out.println("Good evening, " + name + ". How are you?");
        }
    }

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
    }
}
Salida de la consola:
Good evening, Tony Stark. How are you?
Good evening, Captain America. How are you?
Good evening, Black Widow. How are you?
Good evening, Hulk. How are you?
Parte del código aquí no le resultará familiar, pero no se preocupe. Es simple en esencia: ¡el método toma cada nombre por turno y saluda a cada invitado! ¡Además, funcionará con cualquier cantidad de cadenas pasadas! Dos, diez, incluso mil: el método funcionará correctamente con cualquier número de invitados. Mucho más conveniente que sobrecargar el método para todas las posibilidades, ¿no crees? :) Aquí hay otro punto importante: ¡el orden de los argumentos es importante! Digamos que nuestro método toma una Cadena y un número:
public class Person {

    public static void sayYourAge(String greeting, int age) {
        System.out.println(greeting + " " + age);
    }

    public static void main(String[] args) {
        sayYourAge("My age is ", 33);
        sayYourAge(33, "My age is "); // Error!
    }
}
Si el método sayYourAge de la clase Person toma una cadena y un número como entradas, ¡entonces el programa debe pasarlos en ese orden específico! Si las pasamos en otro orden, el compilador generará un error y la persona no podrá decir su edad. Por cierto, los constructores, que cubrimos en la última lección, ¡también son métodos! También puede sobrecargarlos (es decir, crear varios constructores con diferentes conjuntos de parámetros) y el orden de los argumentos pasados ​​también es fundamentalmente importante para ellos. ¡Son métodos reales! :)

Una vez más con respecto a los parámetros

Sí, lo siento, aún no hemos terminado con ellos. :) El tema que estudiaremos ahora es muy importante. ¡Hay un 90% de posibilidades de que le pregunten sobre esto en cada entrevista futura! Hablemos de pasar argumentos a métodos. Considere un ejemplo simple:
public class TimeMachine {

    public void goToFuture(int currentYear) {
        currentYear = currentYear+10;
    }

    public void goToPast(int currentYear) {
        currentYear = currentYear-10;
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        int currentYear = 2018;

        System.out.println("What year is it?");
        System.out.println(currentYear);

        timeMachine.goToPast(currentYear);
        System.out.println("How about now?");
        System.out.println(currentYear);
    }
}
La máquina del tiempo tiene dos métodos. Ambos toman como entrada el número que representa el año en curso, y aumentan o disminuyen su valor (dependiendo de si queremos ir al pasado o al futuro). Pero, como puede ver en la salida de la consola, ¡el método no funciona! Salida de la consola:
What year is it?
2018
How about now?
2018
Pasamos la variable añoActual al método GoToPast() , pero su valor no cambió. Estuvimos en 2018, y aquí nos hemos quedado. ¿Pero por qué? :/ Porque las primitivas en Java se pasan a los métodos por valor. ¿Qué significa eso? Cuando llamamos al método goToPast() y le pasamos la variable int currentYear (=2018) , el método no obtiene la variable currentYear en sí, sino una copia de ella. Por supuesto, el valor de esta copia también es 2018, ¡pero cualquier cambio en la copia no afecta nuestra variable año actual original de ninguna manera! Hagamos nuestro código más explícito y veamos qué sucede con el año actual:
public class TimeMachine {

    public void goToFuture(int currentYear) {
        currentYear = currentYear+10;
    }

    public void goToPast(int currentYear) {
        System.out.println("The goToPast method has started running!");
        System.out.println("currentYear inside the goToPast method (at the beginning) = " + currentYear);
        currentYear = currentYear-10;
        System.out.println("currentYear inside the goToPast method (at the end) = " + currentYear);
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        int currentYear = 2018;

        System.out.println("What was the year when the program started?");
        System.out.println(currentYear);

        timeMachine.goToPast(currentYear);
        System.out.println("And what year is it now?");
        System.out.println(currentYear);
    }
}
Salida de la consola:
What was the year when the program started?
2018
The goToPast method has started running!
currentYear inside the goToPast method (at the beginning) = 2018
currentYear inside the goToPast method (at the end) = 2008
And what year is it now?
2018
Esto muestra claramente que la variable pasada al método goToPast() es solo una copia de currentYear . Y cambiar la copia no afecta el valor "original". "Pasar por referencia" significa exactamente lo contrario. ¡Practiquemos con gatos! Quiero decir, veamos cómo se ve pasar por referencia usando un ejemplo de gato. :)
public class Cat {

    int age;

    public Cat(int age) {
        this.age = age;
    }
}
¡Ahora, con la ayuda de nuestra máquina del tiempo, enviaremos a Smudge , el primer gato del mundo que viaja en el tiempo, al pasado y al futuro! Modifiquemos la clase TimeMachine para que funcione con objetos Cat ;
public class TimeMachine {

    public void goToFuture(Cat cat) {
        cat.age += 10;
    }

    public void goToPast(Cat cat) {
        cat.age -= 10;
    }
}
Ahora los métodos no solo cambian el número pasado. Más bien, cambian el campo de edad de ese gato específico . Recordarás que esto no funcionó para nosotros con las primitivas, porque el número original no cambió. ¡Veamos que pasa!
public static void main(String[] args) {

    TimeMachine timeMachine = new TimeMachine();
    Cat smudge = new Cat(5);

    System.out.println("How old was Smudge when the program started?");
    System.out.println(smudge.age);

    timeMachine.goToFuture(smudge);
    System.out.println("How about now?");
    System.out.println(smudge.age);

    System.out.println("Holy smokes! Smudge has aged 10 years! Back up quickly!");
    timeMachine.goToPast(smudge);
    System.out.println("Did it work? Have we returned the cat to its original age?");
    System.out.println(smudge.age);
}
Salida de la consola:
How old was Smudge when the program started running?
5
How about now?
15
Holy smokes! Smudge has aged 10 years! Back up quickly!
Did it work? Have we returned the cat to its original age?
5
¡Guau! Ahora el método hizo algo diferente: nuestro gato envejeció drásticamente, ¡pero luego volvió a ser joven! :) Vamos a tratar de averiguar por qué. A diferencia del ejemplo con primitivas, cuando los objetos se pasan a un método, se pasan por referencia. Se pasó una referencia al objeto de borrón original al método changeAge() . Entonces, cuando cambiamos smudge.age dentro del método, estamos haciendo referencia a la misma área de memoria donde está almacenado nuestro objeto. Es una referencia al mismo Smudge que creamos inicialmente. ¡Esto se llama "pasar por referencia"! Sin embargo, no todo con referencias es tan fácil. :) Intentemos cambiar nuestro ejemplo:
public class TimeMachine {

    public void goToFuture(Cat cat) {
        cat = new Cat(cat.age);
        cat.age += 10;
    }

    public void goToPast(Cat cat) {
        cat = new Cat(cat.age);
        cat.age -= 10;
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        Cat smudge = new Cat(5);

        System.out.println("How old was Smudge when the program started?");
        System.out.println(smudge.age);

        timeMachine.goToFuture(smudge);
        System.out.println ("Smudge went to the future! Has his age changed?");
        System.out.println(smudge.age);

        System.out.println ("And if you try going back?");
        timeMachine.goToPast(smudge);
        System.out.println(smudge.age);
    }
}
Salida de la consola:
How old was Smudge when the program started running?
5
Smudge went to the future! Has his age changed?
5
And if you try going back?
5
¡No vuelve a funcionar! О_О Vamos a averiguar qué pasó. :) Tiene todo que ver con los métodos goToPast / goToFuture y cómo funcionan las referencias. ¡Ahora, su atención, por favor! Esto es lo más importante que hay que entender sobre cómo funcionan las referencias y los métodos. El hecho es que, cuando llamamos al método goToFuture(Cat cat) , lo que se pasa es una copia de la referencia al objeto cat, no la referencia en sí. Así, cuando pasamos un objeto a un método, hay dos referencias al objeto. Esto es muy importante para entender lo que está pasando. Esta es precisamente la razón por la cual la edad del gato no cambió en nuestro último ejemplo. En el ejemplo anterior, al cambiar la edad, simplemente tomamos la referencia pasada a goToFuture()y lo usó para encontrar el objeto en la memoria y cambiar su edad ( cat.age += 10 ). Pero ahora, dentro del método goToFuture() , estamos creando un nuevo objeto ( cat = new Cat(cat.age) ), y a este objeto se le asigna la misma copia de referencia que se pasó al método. Como resultado:
  • La primera referencia ( Cat smudge = new Cat (5) ) apunta al gato original (con 5 años)
  • Después de eso, cuando le pasamos a la variable cat el método goToPast() y le asignamos un nuevo objeto, la referencia se copió.
Y esto nos llevó al resultado final: dos referencias que apuntan a dos objetos diferentes. Pero solo cambiamos la edad de uno de ellos (el creado dentro del método).
cat.age += 10;
Y por supuesto, en el método main() podemos ver en la consola que la edad del gato, smudge.age , no ha cambiado. Después de todo, smudge es una variable de referencia que todavía apunta al objeto antiguo y original con 5 años, y no hicimos nada con ese objeto. Todos nuestros cambios de edad se realizaron en el nuevo objeto. Entonces, resulta que los objetos se pasan a los métodos por referencia. Las copias de los objetos nunca se crean automáticamente. Si pasa un objeto gato a un método y cambia su edad, cambiará su edad. ¡Pero las variables de referencia se copian al asignar valores y/o llamar a métodos! Repitamos aquí lo que dijimos sobre pasar primitivas: "Cuando llamamos al método changeInt() y pasamos el intvariable x (=15) , el método no obtiene la variable x en sí, sino una copia de ella. Por lo tanto, cualquier cambio realizado en la copia no afecta a nuestro original xTodavía terminaré discutiendo más de una vez sobre cómo se pasan los argumentos en Java (incluso entre desarrolladores experimentados). Pero, ahora sabes exactamente cómo funciona. ¡Avanza! :) Para reforzar lo que aprendió, le sugerimos que vea una lección en video de nuestro Curso de Java
Comentarios
  • Populares
  • Nuevas
  • Antiguas
Debes iniciar sesión para dejar un comentario
Esta página aún no tiene comentarios