====== 02.2 - Elementos básicos de Java ====== Todo programa informático, en su nivel más fundamental, consiste en procesar información: recibir datos del exterior, guardarlos temporalmente en la memoria, transformarlos mediante operaciones lógicas o matemáticas y devolver un resultado. En este tema estudiaremos las herramientas esenciales que ofrece Java para realizar este ciclo. Aprenderemos cómo clasifica el lenguaje la información (tipado), cómo guardar datos en memoria (variables y constantes), los operadores para trabajar con ellos y los mecanismos para comunicarnos con el usuario a través de la consola. ===== 1. Tipado de lenguajes ===== Los lenguajes de programación se clasifican según cómo gestionan los tipos de sus datos: * **Estaticidad:** * **Tipado estático:** Exige declarar el tipo de dato de cada variable. Este tipo se verifica en tiempo de compilación y no puede cambiar en ejecución (salvo conversiones explícitas o *casting*). Ejemplos: Java, C++, C#. * **Tipado dinámico:** No requiere indicar el tipo de variable al declararla; el lenguaje lo determina en tiempo de ejecución y la variable puede cambiar de tipo libremente. Ejemplos: Python, JavaScript. * **Fortaleza:** * **Tipado fuerte:** No permite realizar operaciones entre tipos incompatibles ni conversiones implícitas no seguras. * **Tipado débil:** Realiza conversiones de tipo automáticas ante ciertas operaciones. **Java es un lenguaje de tipado estático y fuertemente tipado** (aunque realiza pequeñas conversiones implícitas seguras, como concatenar números a cadenas de texto). public class Tipado { static void main() { int a = 5; // a = "Hola"; // ERROR de compilación: No se puede asignar un String a una variable int. String b = "Texto: "; IO.println(b + a); // Concatenación implícita: convierte 'a' a String ("Texto: 5"). } } ===== 2. Definición y tipos de datos ===== Una variable es una posición de memoria con un nombre simbólico asignado donde se almacena un valor susceptible de cambiar a lo largo del programa. Una constante, por el contrario, mantiene un valor fijo e inmutable durante toda la ejecución. ==== Declaración e inicialización ==== Para utilizar una variable en Java debemos especificar su **tipo de dato** seguido de su **nombre** (identificador). Podemos reservar el espacio en memoria (declarar) y asignarle un valor (inicializar) en pasos separados o en una sola línea: static void main() { // 1. Declaración (reserva espacio en memoria, sin valor inicial) int edad; // 2. Inicialización (asignación del primer valor) edad = 25; // 3. Declaración e inicialización simultánea (lo más habitual) double precio = 19.99; boolean activo = true; } En Java, las **variables locales deben inicializarse antes de ser utilizadas**. Intentar leer o imprimir el valor de una variable que no ha sido inicializada provocará un error de compilación. ==== Tipos primitivos ==== Java maneja 8 tipos de datos primitivos que representan valores simples (enteros, decimales, caracteres o booleanos). ^ Tipo ^ Tamaño (bits) ^ Descripción ^ Valor por defecto ^ | ''byte'' | 8 | Entero muy pequeño con signo $[-128, 127]$ | $0$ | | ''short'' | 16 | Entero corto con signo $[-32768, 32767]$ | $0$ | | ''int'' | 32 | Entero estándar $[-2^{31}, 2^{31}-1]$ | $0$ | | ''long'' | 64 | Entero largo $[-2^{63}, 2^{63}-1]$ | $0L$ | | ''float'' | 32 | Decimal en coma flotante de precisión simple | $0.0f$ | | ''double'' | 64 | Decimal en coma flotante de precisión doble | $0.0d$ | | ''char'' | 16 | Carácter individual en formato Unicode | $'\u0000'$ | | ''boolean'' | 1 | Valor lógico (''true'' o ''false'') | ''false'' | ==== Cadenas de texto: Clase String ==== El tipo ''String'' no es un tipo primitivo, sino una clase que representa secuencias de caracteres delimitadas por comillas dobles (''"''...''"''). En Java, las instancias de ''String'' son **inmutables**: cualquier modificación sobre un ''String'' genera un objeto nuevo en memoria. ==== Inferencia de tipos (var) ==== Desde Java 10, es posible omitir la declaración explícita del tipo en variables locales utilizando la palabra reservada ''var''. El compilador deducirá el tipo basándose en el valor asignado: var edad = 25; // Compila como int var sueldo = 1250.50; // Compila como double var texto = "Hola"; // Compila como String Por defecto, Java interpreta los literales enteros como ''int'' y los decimales como ''double''. Si necesitas asignar un valor de tipo ''float'' o ''long'', debes añadir un sufijo al literal: float pi = 3.1416f; // Requiere 'f' para no ser tratado como double long distancia = 3000000000L; // Requiere 'L' ==== Conversión de tipos (Cast) ==== Cuando necesitamos convertir el valor de un tipo primitivo a otro, utilizamos la conversión explícita mediante el operador de **cast**: ''(tipo) expresion''. public class Cast { static void main() { // Cast directo (truncamiento) double precioDouble = 19.99; int precioEntero = (int) precioDouble; // Pierde los decimales -> 19 // Evitar división entera no deseada int a = 9; int b = 2; float resultadoIncorrecto = (float) (a / b); // Divide como int (4) y lo convierte a float -> 4.0f float resultadoCorrecto = (float) a / b; // Convierte 'a' a float (9.0f) y divide -> 4.5f } } El operador ''(tipo)'' solo funciona entre tipos primitivos compatibles. Para convertir de ''String'' a un tipo numérico, debemos usar los métodos ''parse'' de sus respectivas clases envoltorio (*wrapper classes*): String textoNumero = "42"; int numero = Integer.parseInt(textoNumero); double decimal = Double.parseDouble("3.14"); ==== Nombres y reglas de estilo ==== === Reglas de sintaxis === * Un identificador puede contener letras, dígitos, guion bajo (''_'') y el símbolo de dólar (''$''). * Debe comenzar obligatoriamente por una letra, ''_'' o ''$''. Nunca por un número. * No se pueden utilizar **palabras reservadas** del lenguaje (''int'', ''class'', ''final'', ''public'', ''if'', etc.). === Buenas prácticas === * **Nombres autoexplicativos:** El nombre de la variable debe reflejar su propósito. Es preferible ''distanciaKilometros'' antes que ''d''. * **Estilo camelCase:** En Java, por convención, las variables se escriben en minúscula inicial y con las subsecuentes palabras en mayúscula (''alturaEdificio''). * **Inglés como estándar:** Se recomienda escribir el código en inglés para mantener un estándar internacional. ===== 3. Constantes ===== Las constantes almacenan información que no debe cambiar durante la ejecución. Se definen anteponiendo la palabra reservada ''final''. Por convención, sus nombres se escriben en **MAYÚSCULAS_CON_GUION_BAJO**. public class Constantes { static void main() { final double VELOCIDAD_LUZ = 299792.458; // en km/s final float PI = 3.1416f; // VELOCIDAD_LUZ = 300000.0; // ERROR de compilación: No se puede reasignar una variable final } } ===== 4. Operadores ===== ==== Operador de asignación y caracteres de escape ==== El operador principal de asignación es el signo igual (''=''). Según el tipo de dato asignado, debemos considerar ciertas reglas sintácticas: * Los valores de tipo ''char'' utilizan comillas simples ('''a'''). * Los valores de tipo ''String'' utilizan comillas dobles (''"Hola"''). * Para incluir caracteres especiales (como comillas dobles) dentro de un ''String'', se utiliza la barra invertida (''\'') como carácter de escape. satic void main() { char letra = 'A'; boolean activo = true; String frase = "Dijo: \"Hola mundo\""; // Carácter de escape \" } ==== Operadores aritméticos y de asignación compuesta ==== Java ofrece operadores aritméticos básicos: suma (''+''), resta (''-''), multiplicación (''*''), división (''/'') y módulo o resto entero (''%''). Pueden combinarse con el operador de asignación para acortar instrucciones: ^ Operador ^ Ejemplo ^ Equivalencia ^ | ''+='' | ''a += b;'' | ''a = a + b;'' | | ''-='' | ''a -= b;'' | ''a = a - b;'' | | ''*='' | ''a *= b;'' | ''a = a * b;'' | | ''/='' | ''a /= b;'' | ''a = a / b;'' | | ''%='' | ''a %= b;'' | ''a = a % b;'' | ==== Operadores unarios ==== Operan sobre un único valor para modificar su signo, incrementarlo, decrementarlo o negarlo: * **Signo (''+'', ''-''):** Cambia o mantiene el signo del valor evaluado. * **Incremento y decremento (''++'', ''--''):** * **Post-incremento (''a++''):** Utiliza el valor actual de la variable en la expresión y **después** la incrementa en 1. * **Pre-incremento (''++a''):** Incrementa la variable en 1 **antes** de evaluar la expresión. * **Negación lógica (''!''):** Invierte un valor booleano (''!true'' es ''false''). public class OperadoresUnarios { static void main() { int a = 3; IO.println("Post-incremento (a++): " + a++); // Muestra 3, 'a' pasa a ser 4 IO.println("Valor tras a++: " + a); // Muestra 4 a = 3; IO.println("Pre-incremento (++a): " + ++a); // 'a' pasa a ser 4, Muestra 4 } } ==== Operadores relacionales ==== Comparan dos operandos y devuelven un valor booleano (''true'' o ''false''): ''=='' (igual a), ''!='' (distinto de), ''<'' (menor que), ''>'' (mayor que), ''<='' (menor o igual) y ''>='' (mayor o igual). Un error muy frecuente es confundir la asignación (''='') con la comparación de igualdad (''==''): int a = 5; int b = 2; // IO.println(a = b); // Asigna 2 a 'a' e imprime 2. ¡Sobrescribe la variable! IO.println(a == b); // Compara si 'a' es igual a 'b' e imprime false. ==== Operadores lógicos ==== Permiten combinar múltiples condiciones booleanas: * ''&&'' (AND): Devuelve ''true'' solo si ambas condiciones son verdaderas. * ''||'' (OR): Devuelve ''true'' si al menos una de las condiciones es verdadera. * ''!'' (NOT): Niega la condición evaluada. static void main() { int edad = 20; boolean tieneCarnet = true; boolean puedeConducir = edad >= 18 && tieneCarnet; // true } ===== 5. Entrada y Salida de datos con la clase IO ===== En Java 25 utilizamos la clase ''IO'' para interactuar con la consola sin necesidad de realizar importaciones adicionales. ==== Salida por consola ==== * ''IO.println(...)'': Imprime el mensaje introducido y añade un salto de línea final. * ''IO.print(...)'': Imprime el mensaje manteniendo el cursor en la misma línea. ==== Entrada por teclado ==== El método ''IO.readln()'' pausa la ejecución hasta que el usuario escribe un texto y pulsa ''Intro''. Siempre retorna los datos en forma de cadena (''String''). Si se requiere un valor numérico, debemos realizar el parseo correspondiente: public class EntradaSalida { static void main() { String nombre = IO.readln("Introduce tu nombre: "); int edad = Integer.parseInt(IO.readln("Introduce tu edad: ")); IO.println("Hola " + nombre + ", tienes " + edad + " años."); } } ===== 6. Utilidades frecuentes: Métodos de String y Math ===== ==== Métodos principales de la clase String ==== Las cadenas de texto cuentan con métodos integrados para consultar y manipular su contenido: * ''length()'': Devuelve el número de caracteres de la cadena. * ''charAt(int index)'': Devuelve el carácter ubicado en el índice indicado (empezando en $0$). * ''substring(int beginIndex, int endIndex)'': Extrae una subcadena desde ''beginIndex'' hasta ''endIndex - 1''. * ''indexOf(String str)'': Retorna la posición de la primera ocurrencia del texto buscado (o $-1$ si no existe). * ''toUpperCase()'' / ''toLowerCase()'': Convierte el texto a mayúsculas o minúsculas. * ''trim()'' / ''strip()'': Elimina los espacios en blanco iniciales y finales. * ''equals(String str)'': Compara si dos cadenas tienen el mismo contenido. Nunca se debe usar ''=='' para comparar el texto de dos ''String''. static void main() { String texto = " Hola Mundo "; IO.println(texto.length()); // 14 IO.println(texto.trim().toUpperCase()); // "HOLA MUNDO" IO.println(texto.contains("Mundo")); // true } ==== Métodos matemáticos (Clase Math y Random) ==== La biblioteca estándar proporciona la clase ''Math'' con utilidades matemáticas estáticas de uso directo: * ''Math.sqrt(double a)'': Calcula la raíz cuadrada. * ''Math.pow(double a, double b)'': Eleva la base ''a'' al exponente ''b''. * ''Math.abs(int a)'': Devuelve el valor absoluto. Para generar números aleatorios se puede emplear ''Math.random()'' (retorna un ''double'' entre $0.0$ e $1.0$) o la clase ''java.util.Random'': static void main() { double raiz = Math.sqrt(16); // 4.0 double potencia = Math.pow(2, 3); // 8.0 // Aleatorio entre 0 y 9 con Math.random() int aleatorio = (int) (Math.random() * 10); } ===== Ejercicios ===== === Ejercicio 1.a === Crea un programa que calcule el área de un triángulo con base $5$ y altura $10$ ($\text{Área} = \frac{\text{base} \cdot \text{altura}}{2}$). La base y la altura deben ser constantes de tipo entero (''int'') y el área una variable del mismo tipo. === Ejercicio 1.b === Modifica el tipo de la variable área a ''float'' y la altura a $9$. Comprueba si el resultado coincide con el cálculo manual. Haz las modificaciones necesarias en la operación **sin cambiar el tipo de las constantes** para obtener el resultado decimal exacto. === Ejercicio 1.c === Modifica las constantes del Ejercicio 1.a a tipo decimal (''float'' o ''double'') para obtener la solución exacta directamente. === Ejercicio 1.d === Haz que la base y la altura sean introducidas dinámicamente por el usuario a través de teclado mediante ''IO.readln()''. === Ejercicio 2.a === Escribe un programa que solicite dos números decimales (''float'') al usuario e imprima su suma, resta, multiplicación, división y módulo (resto). === Ejercicio 2.b === Modifica el programa anterior para que los resultados de las operaciones se muestren convertidos a entero (''int'') mediante *casting*, sin cambiar el tipo original de las variables de entrada. === Ejercicio 2.c === Utiliza el método de formateo ''String.format("%.2f", valor)'' para mostrar el resultado de la división con exactamente dos decimales. === Ejercicio 3.a === Crea un programa que solicite un número al usuario y calcule su raíz cuadrada empleando el método adecuado de la clase ''Math''. === Ejercicio 3.b === Aplica formato a la salida del ejercicio anterior para presentar la raíz cuadrada con tres decimales. === Ejercicio 4 === Escribe un programa que solicite por teclado una base y un exponente (números enteros) y muestre por pantalla el resultado de elevar la base a dicho exponente empleando la clase ''Math''. Muestra el resultado formateado a 2 decimales. === Ejercicio 5 === Dado el siguiente literal de cadena con espacios superfluos: ''String mensaje = " hola mundo ";'', crea un programa que imprima dicho mensaje completamente en mayúsculas y habiendo eliminado los espacios sobrantes de los extremos. === Ejercicio 6.a === Utiliza la clase ''java.util.Random'' o ''Math.random()'' para generar y mostrar por pantalla un número entero aleatorio entre $0$ y $9$. === Ejercicio 6.b === Modifica el ejercicio anterior para que el usuario introduzca por teclado el límite mínimo y máximo entre los cuales se generará el entero aleatorio.