¡Hola! Ya conoces la creación de tus propias clases con campos y métodos. Ahora nos detendremos en los métodos.
Por supuesto, ya hemos hecho esto más de una vez en nuestras lecciones, pero hemos cubierto principalmente generalidades. Hoy vamos a diseccionar métodos y estudiar de qué están hechos, las diversas formas de crearlos y cómo administrarlo todo. :) ¡Vamos!
Declaración de método
Todo el código que define un método se llama declaración de método . La forma general de una declaración de método se puede describir de la siguiente manera:
access modifier, return type, method name (parameter list) {
// method body
}
Como ejemplos, eche un vistazo a las declaraciones de los distintos métodos de la Dog
clase.
public class Dog {
String name;
public Dog(String name) {
this.name = name;
}
public static void main(String[] args) {
Dog max = new Dog("Max");
max.woof();
}
public void woof() {
System.out.println("A dog named " + name + " says \"Woof, woof!\"");
}
public void run(int distanceInFeet) {
System.out.println("A dog named " + name + " ran " + distanceInFeet + " feet!");
}
public String getName() {
return name;
}
}
1. Modificador de acceso
El modificador de acceso siempre se indica primero. Todos losDog
métodos de la clase están marcados con el modificador público . Esto significa que podemos llamarlos desde cualquier otra clase:
public class Main {
public static void main(String[] args) {
Dog butch = new Dog("Butch");
butch.run(100);
}
}
Como puede ver, Dog
se puede acceder fácilmente a los métodos de la clase en la Main
clase. Esto es posible gracias al modificador público . En Java, hay otros modificadores. No todos permiten el uso de métodos en otras clases. Hablaremos de ellos en otras lecciones. Lo principal a recordar es de qué es responsable el modificador: si un método es accesible en otras clases :)
2. palabra clave estática
Uno de losDog
métodos, main()
, está marcado con la palabra clave static . También es parte de la declaración del método, y ya sabemos su significado. No lo mencionamos en la plantilla de declaración de método dada al comienzo de la lección, porque es opcional. Si se especifica, debe ir después del modificador de acceso. ¿Recuerda que en lecciones recientes hablamos sobre variables estáticas (de clase)? Cuando se aplica a métodos, esta palabra clave tiene aproximadamente el mismo significado. Si un método es estático , entonces se puede usar sin una referencia a un objeto específico de la clase. Y, de hecho, no necesita un Dog
objeto para ejecutar el main()
método estático en elDog
clase. Funcionará bien sin uno. Si este método no fuera estático, primero necesitaríamos crear un objeto para poder ejecutarlo.
3. Valor de retorno
Si nuestro método debe devolver algo, entonces especificamos el tipo del valor de retorno. Esto es evidente en el ejemplo delgetName()
captador:
public String getName() {
return name;
}
Devuelve un String
objeto. Si un método no devuelve nada, entonces se usa la palabra clave voidwoof()
en su lugar, como en el método:
public void woof() {
System.out.println("A dog named " + name + " says \"Woof, woof!\"");
}
Métodos con el mismo nombre
Hay situaciones en las que querremos varias formas diferentes 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ñarle 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 consola: Buenas noches, Tony Stark. ¿Cómo estás? ¡Muy bien! Jarvis ahora puede recibir invitados. Eso sí, más a menudo de lo que será su maestro, Tony Stark. ¡Pero qué pasa si no viene solo! Pero nuestro sayHi()
método 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, ¿de acuerdo? :/ 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 consola: Buenas noches, Tony Stark. ¿Cómo estás? Buenas noches, Tony Stark y Capitán América. ¿Cómo estás? Excelente, ambas versiones funcionaron. :) ¡Pero no solucionamos el problema! ¿Qué pasa si hay tres invitados? Por supuesto, podríamos sayHi()
volver a sobrecargar el método 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 número de nombres, sin sobrecargar el sayHi()
método 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 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");
System.out.println();
jarvis.sayHi("Tony Stark", "Captain America");
}
}
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 consola: Buenas noches, Tony Stark. ¿Cómo estás? Buenas noches, Capitán América. ¿Cómo estás? Buenas noches, Viuda Negra. ¿Cómo estás? Buenas noches Hulk. ¿Cómo estás? Dentro del método, iteramos sobre todos los argumentos y mostramos frases formateadas con nombres. Aquí usamos un for-each
bucle simplificado (que has visto antes). Es perfecto aquí, porque la notación ( String... nombres ) en realidad significa que el compilador coloca todos los argumentos pasados en una matriz. Como resultado, podemos trabajar con nombres de variablescomo trabajaríamos con una matriz, incluso iterándola en un bucle. ¡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 ejemplo de sobrecarga de métodos. Démosle a Jarvis un printInfoFromDatabase()
método. Mostrará información sobre una persona de una base de datos. Si la base de datos indica que una persona es un superhéroe o un supervillano, mostraremos esa información:
public class Jarvis {
public void printInfoFromDatabase (String bio) {
System.out.println(bio);
}
public void printInfoFromDatabase(String bio, boolean isEvil, String nickname) {
System.out.println(bio);
if (!isEvil) {
System.out.println("Also known as the superhero " + nickname);
} else {
System.out.println("Also known as the supervillain " + nickname);
}
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.printInfoFromDatabase("Laura Palmer. Date of birth: July 22, 1972. Twin Peaks, Washington");
System.out.println();
jarvis.printInfoFromDatabase("Max Eisenhardt. Height: 15.6 ft. Weight: 189 lbs. ", true, "Magneto");
}
}
Salida: Laura Palmer. Fecha de nacimiento: 22 de julio de 1972. Twin Peaks, Washington Max Eisenhardt. Altura: 15.6 pies. Peso: 189 libras. También conocido como el supervillano Magneto Entonces, el comportamiento de nuestro método depende de los datos que le pasemos. Aquí hay otro punto importante: ¡ el orden de los argumentos importa! 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 Person
de la clase sayYourAge()
toma una cadena y un número como entrada, ¡entonces este es el orden en que estos argumentos deben pasarse al método! Si los pasamos en un orden diferente, entonces 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! :)
Cómo invocar métodos con parámetros similares
Como saben,null
es una palabra clave en Java. Es muy importante entender que null
no es ni un objeto ni un tipo de datos . Imagina que tenemos una Person
clase y un introduce()
método, que anuncia el nombre y la edad de la persona. Además, la edad se puede pasar como texto o como un número.
public class Person {
public void introduce(String name, String age) {
System.out.println("My name is " + name + ". My age is " + age);
}
public void introduce(String name, Integer age) {
System.out.println("My name is " + name + ". My age is " + age);
}
public static void main(String[] args) {
Person alex = new Person();
alex.introduce ("Alex", "twenty-one");
Person mary = new Person();
mary.introduce("Mary", 32);
}
}
Ya estamos familiarizados con la sobrecarga, por lo que sabemos que ambos métodos se comportarán como deberían: Mi nombre es Alex. Mi edad es veintiún Mi nombre es María. Mi edad es 32 Pero, ¿qué sucederá si pasamos null
como segundo parámetro en lugar de una cadena o un número?
public static void main(String[] args) {
Person victor = new Person();
victor.introduce("Victor", null);// Ambiguous method call!
}
¡Obtendremos un error de compilación! ¿Qué causa esto y qué es exactamente la "ambigüedad"? De hecho, todo es muy simple. El problema es que tenemos dos versiones del método: una con a String
como segundo argumento y otra con an Integer
como segundo argumento. ¡ Pero a String
y an Integer
pueden ser ambos null
! Debido a que son tipos de referencia, null
es el valor predeterminado para ambos. Es por eso que en esta situación el compilador no puede averiguar qué versión del método debe llamar. La solución a este problema es bastante simple. Null
se puede convertir explícitamente a un tipo de referencia específico. Por lo tanto, cuando llama a un método, puede indicar entre paréntesis el tipo de datos que desea para el segundo argumento. El compilador entenderá su "pista" y llamará al método correcto:
public class Person {
public void introduce(String name, String age) {
System.out.println("Method with two strings!");
System.out.println("My name is " + name + ". My age is " + age);
}
public void introduce(String name, Integer age) {
System.out.println("Method with a string and a number!");
System.out.println("My name is " + name + ". My age is " + age);
}
public static void main(String[] args) {
Person victor = new Person();
victor.introduce("Victor", (String) null);
}
}
Salida: ¡ Método con dos cadenas! Mi nombre es Víctor. Mi edad es nula Tenga en cuenta que si el parámetro numérico fuera un primitivo int
, en lugar de una instancia del tipo de referencia Integer, no habría habido tal error.
public class Person {
public void introduce(String name, String age) {
System.out.println("Method with two strings!");
System.out.println("My name is " + name + ". My age is " + age);
}
public void introduce(String name, int age) {
System.out.println("Method with a string and a number!!");
System.out.println("My name is " + name + ". My age is " + age);
}
public static void main(String[] args) {
Person victor = new Person();
victor.introduce("Victor", null);
}
}
¿Puedes adivinar por qué? Si adivinaste por qué, ¡bien hecho! :) Porque las primitivas no pueden ser null
. Ahora el compilador solo tiene una opción, es decir, llamar al introduce()
método con dos cadenas. Esta es la versión del método que se ejecutará cada vez que se llame al método.
Más lectura: |
---|
GO TO FULL VERSION