Java es un lenguaje fundamentalmente orientado a objetos. Eso significa que es un lenguaje organizado en clases que podemos instanciar creando así objetos con los que podremos realizar una gran cantidad de acciones.
Documentación de las clases de Java
El lenguaje Java incorpora una enorme cantidad de clases lo que hace imposible recordar todas ellas ni las acciones que se pueden realizar con los objetos que se pueden crear a partir de dichas clases. Por tanto, lo más importante es saber interpretar la documentación que ofrece el lenguaje para saber cómo crear los objetos, usar métodos para realizar acciones con dichos objetos, acceder a sus propiedades, etc.
Las clases ofrecidas por el lenguaje Java se pueden encontrar en la API (Interfaz de Programación de Aplicaciones) del lenguaje que puedes encontrar en esta dirección para la versión 15: https://docs.oracle.com/en/java/javase/15/docs/api/index.html (Si no tienes a mano la dirección puede usar un buscador con "Java API").
Si accedes a dicha API podrás observar que se encuentra organizada en módulos.
Dentro de cada módulo hay una nueva estructuración, en este caso en lo que llama paquetes. Por ejemplo, el módulo java.base contiene paquetes como los siguientes:
Dentro de cada uno de esos paquetes es donde puedes encontrar las clases que ofrece el lenguaje Java. Por ver un caso concreto, el paquete java.time contiene clases como las siguientes:
Al acceder al contenido de una de esas clases es donde podrás encontrar las propiedades (Fields) y métodos (Methods) que se podrían usar con esa clase en concreto. Por ejemplo, en la clase LocalDateTime podrías encontrar:
Además de la búsqueda de clases usando la navegación a través de los módulos y paquetes, pueden encontrar la documentación de una clase determinada usando el buscador que se encuentra en la parte superior derecha:
Creación de objetos con "new"
Aunque no en todas las clases es así, como ya se verá, lo más habitual es que, para poder trabajar con una clase de Java, se tengan que crear objetos de dicha clase.
La manera en que se crean los objetos (también se llaman instancias) de una clase no siempre es igual, por lo que hay consultar la documentación de la clase oportuna o buscar ejemplos, aunque lo más habitual es usar la palabra reservada new. Para ver un ejemplo puedes usar la clase Random, que permite crear generadores de números aleatorios.
Para crear un objeto de la clase Random debes usar la palabra new de la siguiente manera:
new Random();
Ese trozo de código creará una instancia (objeto) de la clase Random el cual podremos utilizar posteriormente para diversas acciones, como generar números aleatorios.
La clase Random no es de las clases fundamentales del lenguaje (las que se encuentran en el paquete java.lang), por lo que esa línea de código reportará un error al escribirla (Cannot find symbol: class Random):
Para solucionarlo este tipo de errores deberás importar la clase que deseas utilizar. Eso puedes hacerlo fácilmente desde NetBeans desde el menú contextual, seleccionando la opción Fix imports.
Eso añadirá una línea import en la parte superior del código indicando en qué paquete de Java se encuentra la clase que estás utilizando:
Pero lo más habitual es guardar dicho objeto en una variable para poder trabajar con él en distintas partes del código, por lo que lo más habitual será hacer algo como:
Random r;
r = new Random();
Los nombres de las variables siempre se acostumbra a empezarlas en minúsculas, mientras que los nombres de las clases se empiezan en mayúsculas para diferenciarlos.
Es decir, se declara una variable a la que se le asigna como tipo de dato el nombre de la clase del objeto que podrá almacenar. A continuación se almacena en dicha variable el objeto que se está creando.
Eso se podrá hacer en muchas ocasiones en una misma línea:
Random r = new Random();
Con esa variable podrás acceder a las propiedades y métodos que ofrezca la clase Random.
Recuerda que el nombre de la variable donde se almacene el objeto puede tener cualquier nombre, aunque se le suele asociar algún nombre que identifique el tipo de información que contiene, por lo que lo habitual es que veas:
Random random = new Random();
Llamadas a métodos
Una vez que se tiene creado un objeto de una determinada clase de Java, podemos utilizar los métodos que tenga implementada dicha clase, con el fin de que se realice una determinada acción asociada al objeto que invoca al método.
Recuerda que con un objeto de una determinada clase sólo puedes usar los métodos que disponga dicha clase, es decir, no puedes hacer una llamada a un método que corresponda a otra clase.
El formato general para hacer una llamada a un método asociado a un objeto es:
objeto.metodo(parametro1, parametro2, ...)
Vamos a verlo con un ejemplo, usando el método nextInt() de la clase Random. Este método permite obtener un número entero de manera aleatoria. Observa que en la documentación de cada método se explica su objetivo.
Llamadas a métodos sin parámetros
Lo más importante al usar un método es observar cómo está declarado para saber si se le debe pasar algún parámetro (es decir, algún valor entre los paréntesis), o no hay que pasarle nada, o de qué tipo deben ser dichos parámetros.
Como se puede observar en la documentación, el método nextInt() está declarado como:
Es decir, no aparece nada entre los paréntesis, por lo que para hacer una llamada a este método se hará sin indicar ningún parámetro:
Random r = new Random();
r.nextInt();
Valores de retorno de la llamada a métodos
Si pruebas ese trozo de código sin más, observarás que no se produce ningún resultado, es decir, no se muestra nada en la consola aunque podríamos esperar que apareciera el número aleatorio que prometía generar el método nextInt(). Hay que tener en cuenta que ese método no dice que vaya a mostrar el número en consola, ni en ninguna otra parte. Sólo se limita a regenerar el número y retornarlo como aparece en la documentación:
Además, si observas la declaración del método, aparece la palabra int delante del método. Con eso está indicando que retorna un valor de tipo int, que en este caso concreto corresponde al número entero aleatorio que genera el método nextInt().
Cuando un método retorna algún tipo de información, deberás almacenarla en una variable del mismo tipo, para usarla posteriormente como se desee, o bien utilizar directamente la llamada al método como un parámetro o dentro de otra expresión compatible con el tipo de dato que retorna.
Siguiendo con el ejemplo, para que se muestre el valor aleatorio generado por el método nextInt() podríamos usar una variable de tipo int que almacene el valor retornado por el método nextInt():
Random r = new Random();
int num = r.nextInt();
System.out.println(num);
O bien, podemos usar directamente el valor retornado dentro del println(), ya que la variable no la necesitamos para nada más:
Random r = new Random();
System.out.println(r.nextInt());
Si ejecutas un código u otro deberías obtener en la consola un valor numérico aleatorio entre los posibles valores enteros que puede almacenar un dato de tipo int (es decir, entre -2147483648 y 2147483647).
Puedes meter la llamada al método nextInt() en un bucle para observar más cómodamente los diferentes valores que se van generando:
Random r = new Random();
for(int i=0; i<100; i++) {
System.out.println(r.nextInt());
}
Obtendrás valores como:
Llamada a métodos sin valores de retorno (void)
Existen también multitud de métodos que no retornan ningún valor como resultado de su ejecución. Simplemente realizan una acción pero sin devolver un resultado. Dichos métodos aparecen con la palabra void en el lugar del tipo de dato que deberían retornar.
Por verlo en un ejemplo de la misma clase Random, podemos observar el método setSeed(). Aunque no nos debe preocupar en este momento cuál es su funcionalidad, este método permite asignar una nueva "semilla" para el generador de números aleatorios. Esa "semilla" es utilizada por Random como referencia a partir de la cual se van a realizar los cálculos para generar los números aleatorios. La declaración de este método aparece como:
Observa que aparece la palabra void como tipo de dato del valor a retornar, por lo que nos está informando que este método no va a retornar ningún valor como resultado de su ejecución, tan sólo se encarga de cambiar la semilla del objeto Random sin que retorne nada.
Así, que para usar los métodos que no retornan nada (void) se realizará la llamada al método sin asignarle el resultado a ninguna variable, ni usarla dentro de ninguna expresión. Por ejemplo:
Random r = new Random();
r.setSeed(1000); // Método sin valor retornado
int num = r.nextInt(); // Método con valor retornado
System.out.println(num);
Llamadas a métodos con parámetros
Hemos visto el caso de una llamada a un método en la que no se usaban parámetros.
Los parámetros son los valores que se indican dentro de los paréntesis en la llamada a un método.
El método nextInt() de la clase Random tiene la particularidad de que tiene 2 modos de uso, como aparece en la API de la clase Random:
Es decir, se puede usar sin parámetros, o bien, usando un parámetro de tipo int.
En la API de cada método puedes ver el tipo de dato que debe usarse como parámetros. Sólo podrás usar como parámetro en la llamada a un método un valor compatible con el tipo indicado en la documentación. Además debes respetar el número de parámetros que se indique.
Por tanto, podemos usar el método nextInt() pasándole un parámetro de tipo int como indica dentro de los paréntesis: int bound
El nombre de los parámetros que aparece en la declaración de los métodos sólo es orientativo. Puedes usar como parámetro una variable con cualquier otro nombre, o directamente un valor correspondiente al tipo de dato admitido.
Si observas la explicación que aparece en la documentación para este método, verás que la funcionalidad es diferente a la que hacía este mismo método cuando no tiene ningún parámetro. Cuando se le asigna un parámetro int, el método nextInt genera un número aleatorio entre 0 y el valor especificado como parámetro (no incluído).
Por tanto, si deseamos obtener valores aleatorios entre 0 y 9 podemos usar la llamada al método como:
int num = r.nextInt(10);
Ahí se está pasando directamente un valor literal de tipo int, pero también puedes indicar una variable, o incluso una expresión siempre que el resultado de la misma sea compatible con el tipo de parámetro que se debe usar:
int limite = 9;
int num = r.nextInt(limite + 1);
Hemos visto un ejemplo de un método que admite un único parámetro, pero pueden encontrarte con método con más de un parámetro y de distintos tipos de datos. Por ejemplo, el método substring() de la clase String permite usar dos parámetros para obtener un trozo de la cadena de caracteres entre las posiciones que se indiquen.
Cuando se usa más de un parámetro se separan con comas cada uno de ellos.
Este método retorna un String con la subcadena extraída entre las posiciones indicadas. Por tanto, observa cómo se puede extraer la palabra Mundo de la cadena ¡Hola Mundo! usando los dos parámetros que marcan el inicio y el fin de la cadena:
String saludo = "¡Hola Mundo!";
System.out.println(saludo.substring(6, 11));
Llamadas a métodos desde NetBeans
Si usas NetBeans como entorno de desarrollo (de manera similar ocurre con otros entornos de desarrollo), podrás observar que tras escribir el punto detrás de un objeto, aparecerá una lista desplegable con los métodos (y su documentación) que puedes emplear con dicho objeto. En este ejemplo se muestra la lista de métodos correspondiente al objeto de tipo String que se ha indicado:
En caso de que ya tuvieras escrita la llamada al método y desees volver a mostrar su documentación, puedes posicionar el cursor sobre el método y usa el menú Source > Complete Code, o bien la combinación de teclas Ctrl+Espacio:
Casos especiales de creación de objetos
Aunque lo habitual sea crear objetos usando la palabra reservada new, hay determinadas clases que requieren una manera especial de crear objetos.
Creación de objetos String
La clase String permite crear objetos usando la palabra new, pero lo más habitual es crearlos directamente usando el operador =. Por tanto, estas sentencias son equivalentes:
String saludo1 = "¡Hola Mundo!";
String saludo2 = new String("¡Hola Mundo!");
Métodos constructores con parámetros
Cuando se emplea la palabra reservada new para la instanciación (creación) de objetos lo que realmente se está realizando es una utilización del método constructor de la clase correspondiente. Como siempre, en la documentación API de la clase se puede obtener información sobre dichos métodos constructores. Para este tipo de métodos se puede encontrar la sección Constructor Summary en la documentación.
Por ejemplo, para la clase Random que se ha usado antes, aparece los siguientes métodos constructores:
Al observar que hay dos métodos constructores (uno sin parámetros y otro con un parámetro de tipo long), podemos crear los objetos random como antes o empleando un parámetro que usa como semilla (seed) la clase Random (en la documentación podrías consultar el uso que le da a la semilla la clase Random):
Random random1 = new Random();
Random random2 = new Random(1000);
También puede haber clases que no ofrezcan un método constructor sin parámetros. Por ejemplo, los constructores de la clase Locale (es una clase para realizar acciones con idiomas) son:
Por tanto, para la clase Locale se puede usar la instanciación de objetos indicando 1, 2 ó 3 valores String para especificar un idioma concreto, pero no se puede usar sin parámetros.
Locale idiomaMal = new Locale(); // Incorrecto
Locale castellano = new Locale("es");
Locale castellanoArgentina = new Locale("es", "AR");
Métodos constructores protegidos
También se da el caso de clases que tienen protegido el método constructor. Eso ocurre, por ejemplo, con la clase NumberFormat, donde puedes ver que en la declaración del método constructor aparece la palabra protected.
Cuando ocurre esto (que el método constructor esté protegido) no puedes usar la manera habitual de crear objetos de esa clase con la palabra new. Si lo intentas, obtendrás un error indicando que la clase NumberFormat es abstracta y no puede ser instanciada.
En estos casos tendrás que observar la documentación de la clase e informarte sobre si es necesario crear objetos para usarla o qué métodos puedes usar para obtener objetos de la clase.
Para el caso concreto de la clase NumberFormat, se dispone de métodos como getInstance(), getCurrencyInstance(), getPercentInstance(), getNumberInstance(), que retornar un objeto NumberFormat. Por ejemplo, la declaración de getCurrencyInstance() es:
Observa que justo al lado izquierdo del nombre del método aparece que va retorna un objeto NumberFormat, por lo que se puede usar un código como este para obtener un objeto de dicha clase:
NumberFormat formatoMoneda = NumberFormat.getCurrencyInstance();
No es objetivo de este artículo aprender a usar la clase NumberFormat, que puede servir para mostrar datos con un determinado formato, pero puedes ver en el siguiente ejemplo que con el método format se puede mostrar un valor numérico en formato moneda (Se muestra el valor 9.99 como: 9,99 €):
NumberFormat formatoMoneda = NumberFormat.getCurrencyInstance();
System.out.println(formatoMoneda.format(9.99));
Métodos estáticos
Otro caso son los métodos estáticos, que son aquellos que tienen la palabra static en su declaración. Los métodos estáticos tienen la particularidad de que para usarlos no se preceden de un objeto de la clase, como es habitual. En este caso se deben preceder del nombre de la clase directamente.
La clase Math es una de las que tiene varios métodos estáticos. Esta clase ofrece varios métodos para realizar operaciones matemáticas más avanzadas de las que se pueden hacer con los operadores aritméticos básicos.
Podemos ver como ejemplo el método floor(), que se encarga de redondear a la baja un valor numérico decimal de tipo double que se indique por parámetro. Esta es su declaración:
En ella se observa que se le debe pasar un valor de tipo double como parámetro (que será el valor a redondear), que va a retornar un valor de tipo double (que será el resultado del redondeado a la baja), y que es un método estático (por aparecer la palabra static). Por último quedaría decir que la palabra public simplemente indica este método puede ser usado desde cualquier otra clase.
Así que al ser un método estático habrá que usarlo precedido del nombre de la clase Math, no de un objeto de la clase Math. Por ejemplo, para redondear a la baja el valor 9.99, obteniendo como resultado 9.0:
System.out.println(Math.floor(9.99));
Propiedades, atributos o fields
Algunas clases ofrecen públicamente una serie de valores que se conocen como propiedades, atributos o fields. Son los que se muestran en el apartado Field Summary de la documentación de cada clase.
Por ejemplo, la clase Math ofrece las propiedades E y PI:
Como se ha comentado antes, estas propiedades se deben usar como simples valores del tipo que indican. En el ejemplo anterior se observa que ambos son valores de tipo double.
Para hacer referencia a una de las propiedades que ofrece una determinada clase, tan sólo se indicar el nombre de la propiedad precedido de un objeto de dicha clase o del nombre de la clase si la propiedad es estática. Es decir, de manera similar a la llamada a un método, pero sin usar paréntesis.
Así, por ejemplo, para mostrar el valor de la propiedad estática PI de la clase Math (se muestra 3.141592653589793):
System.out.println(Math.PI);
Generalmente aparecen en mayúsculas por ser constantes.
En los entornos de desarrollo como NetBeans también se muestran las propiedades al desplegar la lista que aparece al escribir el punto detrás del nombre de la clase o de un objeto: