Métodos en Java — desmontando el public static que tanto asusta al principio
La primera vez que vi un método en Java me acuerdo de quedarme mirando la primera línea antes incluso de entender qué hacía el método: public static int calcularMedia(int a, int b). En Python, una función empieza con def y ya está. Aquí había cuatro palabras antes de siquiera llegar al nombre, y cada una parecía tener su propio significado que nadie me explicaba de golpe. Si a ti te pasa lo mismo, tranquilo — vamos a desmontar esa línea palabra por palabra, porque una vez que sabes qué hace cada pieza, dejan de dar miedo.
Tabla de Contenidos
De función a método
En Python defines una función suelta, sin más contexto:
def calcular_media(a, b):
return (a + b) / 2
print(calcular_media(7, 9))
En Java esto no existe. No hay funciones libres — todo lo que en Python sería una función, en Java tiene que vivir dentro de una clase, y se llama método. Por ahora, mientras no hemos visto clases en profundidad, vas a escribir todos tus métodos dentro de la misma clase donde está tu main, así:
public class Calculadora {
public static double calcularMedia(int a, int b) {
return (a + b) / 2.0;
}
public static void main(String[] args) {
System.out.println(calcularMedia(7, 9));
}
}
Fíjate en algo: calcularMedia está fuera de main, al mismo nivel, dentro de la clase Calculadora. Eso es clave — un método nunca va dentro de otro método.
Anatomía de un método
Vamos a coger esa primera línea que tanto me costó y separarla en sus piezas:
public static double calcularMedia(int a, int b) {
| Pieza | Qué es |
|---|---|
public | Modificador de acceso — quién puede usar este método |
static | Por ahora: «así se hace» — lo explicamos bien cuando lleguemos a clases |
double | Tipo de dato que devuelve el método |
calcularMedia | El nombre del método |
(int a, int b) | Los parámetros, con su tipo obligatorio |
Vamos una por una.
El modificador de acceso: public y private
En Python, técnicamente todo es accesible desde cualquier parte — si acaso, usas un guion bajo delante (_variable) como convención para decir «esto es interno, no lo toques», pero nada te lo impide de verdad. Java sí que lo impide, y lo hace con modificadores de acceso.
Los dos que vas a usar más al principio son:
public static void saludar() {
// Cualquier clase de tu programa puede llamar a este método
}
private static int calcularDescuento(double precio) {
// Solo se puede llamar desde dentro de esta misma clase
}
public: el método es visible desde cualquier otra clase de tu programa. Es lo que necesitas para que algo se pueda usar «desde fuera».private: el método solo se puede llamar desde dentro de la misma clase donde está escrito. Si otra clase intenta llamarlo, no compila.
Poner private a un método y luego intentar llamarlo desde main en otra clase, y quedarse mirando el error de compilación sin entender por qué. Si tu método necesita usarse «desde fuera», tiene que ser public. private es para métodos auxiliares que solo tienen sentido dentro de su propia clase, como un cálculo intermedio que nadie más necesita ver.
Es habitual preguntarse: ¿y si no pongo ningún modificador? Existe un tercer nivel de visibilidad (el llamado «de paquete», sin palabra clave) que verás con detalle cuando lleguemos a clases y visibilidad. Por ahora, usa siempre public o private explícitamente — así no dependes del valor por defecto.
static: por ahora, «así se hace»
static es la pieza que más preguntas suele levantar, y con razón: no la vas a entender del todo hasta que veamos clases y objetos, porque tiene que ver con la diferencia entre un método que pertenece a la clase en general y uno que pertenece a cada objeto concreto que crees de esa clase.
Por ahora quédate con esto: mientras todo tu código viva dentro de una sola clase con un main, todos tus métodos van a ser static. Es lo que le permite a main — que también es static — llamarlos directamente, sin tener que crear antes un objeto de la clase. Cuando lleguemos al tema de clases y objetos, vas a ver métodos sin static y vas a entender exactamente cuándo usar cada uno.
El tipo de retorno: lo que Python no te obligaba a decir
En Python, una función puede devolver lo que le dé la gana sin avisar de antemano:
def procesar(x):
if x > 0:
return x * 2
return "negativo" # ¡un tipo totalmente distinto, y Python no dice nada!
En Java esto es imposible. Un método declara, antes de su nombre, el tipo exacto de lo que va a devolver, y está obligado a cumplirlo siempre:
public static int duplicar(int x) {
return x * 2; // tiene que devolver un int, exactamente eso
}
Si el método no devuelve nada, se usa la palabra void en el sitio del tipo de retorno:
public static void mostrarSaludo(String nombre) {
System.out.println("Hola, " + nombre);
// no hay return, o como mucho un "return;" vacío para cortar antes de tiempo
}
void no es «no devuelve nada por ahora» — es una promesa que el compilador vigila. Si un método declara void e intentas hacer return 5; dentro, no compila. Y al revés: si declaras int y en algún camino del método se te olvida un return, tampoco compila. Java no te deja «olvidarte» de devolver algo como sí podrías en Python.
Los parámetros: también tienen que llevar tipo
Cada parámetro de un método en Java lleva su tipo declarado delante, uno por uno:
public static double calcularPrecio(double base, int cantidad, boolean conIva) {
double total = base * cantidad;
if (conIva) {
total *= 1.21;
}
return total;
}
No puedes escribir calcularPrecio(base, cantidad, conIva) sin tipos, como harías en Python. Cada parámetro es, en la práctica, una variable local que solo existe dentro del método, con su tipo fijado desde el principio.
Llamar a un método
Llamar a un método propio es igual que llamar a cualquier función que ya conoces, como System.out.println():
public class Notas {
public static String clasificar(double nota) {
if (nota >= 9) {
return "Excelente";
} else if (nota >= 7) {
return "Notable";
} else if (nota >= 5) {
return "Aprobado";
}
return "Suspenso";
}
public static void main(String[] args) {
double miNota = 8.5;
// Llamamos al método y guardamos lo que devuelve en una variable
String resultado = clasificar(miNota);
System.out.println("Clasificación: " + resultado);
// También se puede usar directamente dentro de otra expresión
System.out.println("La nota " + 6.0 + " es: " + clasificar(6.0));
}
}
Es habitual preguntarse: ¿puedo tener dos métodos con el mismo nombre? Sí, siempre que se puedan distinguir por sus parámetros — distinto número de parámetros, o parámetros de distinto tipo. Esto se llama sobrecarga de métodos (overloading):
public static int sumar(int a, int b) {
return a + b;
}
public static double sumar(double a, double b) {
return a + b;
}
public static int sumar(int a, int b, int c) {
return a + b + c;
}
Cuando llamas a sumar(3, 4), Java mira los tipos que le pasas y decide sola cuál de las tres versiones usar. No existe esto en Python de la misma forma — allí, si defines dos funciones con el mismo nombre, la segunda simplemente sustituye a la primera.
Un uso muy práctico de la sobrecarga es dar valores «por defecto» simulados. Java no tiene parámetros con valor por defecto como Python (def fun(x, y=10)), así que en su lugar se sobrecarga el método:
public static double calcularPrecio(double base, int cantidad) {
return calcularPrecio(base, cantidad, false); // llama a la versión de abajo
}
public static double calcularPrecio(double base, int cantidad, boolean conIva) {
double total = base * cantidad;
if (conIva) {
total *= 1.21;
}
return total;
}
Ver los métodos en acción
Vamos a juntar todo en un ejemplo completo, con un caso típico: comprobar si un número de identificación de estudiante es válido antes de procesarlo, algo parecido a lo que hace cualquier formulario de la universidad por debajo.
public class ValidadorAlumno {
// private: es un cálculo interno, nadie desde fuera necesita llamarlo directamente
private static boolean tieneLongitudCorrecta(String id) {
return id.length() == 8;
}
// public: este sí lo necesitamos poder llamar desde main
public static boolean esIdValido(String id) {
if (!tieneLongitudCorrecta(id)) {
return false; // cortamos aquí — no hace falta comprobar nada más
}
// comprobamos que todos los caracteres sean dígitos
for (int i = 0; i < id.length(); i++) {
if (!Character.isDigit(id.charAt(i))) {
return false;
}
}
return true;
}
public static void main(String[] args) {
String[] pruebas = {"12345678", "123", "1234567a"};
for (String id : pruebas) {
System.out.println(id + " → " + (esIdValido(id) ? "válido" : "no válido"));
}
}
}
esIdValido es public porque es el que se usa desde fuera; tieneLongitudCorrecta es private porque es un paso intermedio que solo tiene sentido dentro de esta clase. Es exactamente el tipo de decisión que vas a tomar constantemente: ¿esto lo necesita alguien de fuera, o es un detalle interno?
Visualízalo con Python Tutor
Selecciona Java en el desplegable y pega esto en pythontutor.com:
public class Demo {
public static int duplicar(int x) {
return x * 2;
}
public static int sumarTresVeces(int x) {
int resultado = duplicar(x) + x;
return resultado;
}
public static void main(String[] args) {
int valor = sumarTresVeces(4);
System.out.println(valor);
}
}
Ejecuta paso a paso y fíjate en la pila de llamadas: cuando main llama a sumarTresVeces(4), se abre un nuevo marco solo para esa llamada, con su propia variable x. Dentro de él, la llamada a duplicar(x) abre otro marco encima, con su propia copia de x — distinta de la de sumarTresVeces, aunque se llame igual. Cuando duplicar termina con su return, ese marco desaparece y el resultado vuelve al punto exacto donde se le llamó, para seguir el cálculo de resultado. Cada llamada a un método tiene su propio espacio, aislado de los demás, aunque reutilicen nombres de variable.
Resumen
- En Java no hay funciones libres — todo vive dentro de una clase, y se llama método
publichace que el método se pueda llamar desde fuera de la clase;private, solo desde dentrostatices, por ahora, «así se hace» — lo entenderás del todo con clases y objetos- El tipo de retorno es obligatorio y Java lo vigila: si dice
int, tiene que devolver uninten todos sus caminos; si no devuelve nada, se declaravoid - Los parámetros llevan siempre su tipo declarado, uno por uno
- Puedes tener varios métodos con el mismo nombre (sobrecarga) siempre que se distingan por el número o tipo de sus parámetros
¿Te ha servido este artículo? Así puedes apoyar SergioLearns →

Un comentario