Variables en Java — práctica con los errores que todo el mundo comete
Hay un momento en el primer laboratorio de Java que le pasa a casi todo el mundo. Llevas un rato escribiendo código, llegas a una división, ejecutas el programa y el resultado es… 3. No 3,5. No 3,33. Tres. Entero. Y el número que esperabas estaba ahí, perfecto en papel, pero Java decidió truncarlo sin avisar.
Eso es la división entera. Y es solo uno de los tres sustos que te esperan cuando empiezas a mezclar tipos en Java. En esta práctica los vamos a provocar a propósito para que cuando aparezcan en el laboratorio ya los conozcas de antes.
Abre VS Code y crea una carpeta practica_variables. Un fichero .java para cada programa.
Tabla de Contenidos
Variables en Java práctica — Programa 1: Calculadora con tipos mezclados
¿Por qué empezar con una calculadora si ya hicimos una en la práctica de sintaxis? Porque esta es diferente — aquí el objetivo no es el resultado, sino entender qué pasa cuando mezclas int y double sin pensar.
import java.util.Scanner;
public class CalculadoraTipos {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== CALCULADORA CON TIPOS ===");
System.out.println();
System.out.print("Primer número (entero): ");
int a = sc.nextInt();
System.out.print("Segundo número (entero): ");
int b = sc.nextInt();
System.out.println();
System.out.println("--- División: el gran engaño ---");
// División entera — lo que hace Java por defecto
int divEntera = a / b;
System.out.printf("%d / %d = %d ← división ENTERA%n", a, b, divEntera);
// División real — necesitas al menos un double
double divReal1 = (double) a / b;
System.out.printf("%d / %d = %.4f ← cast antes de dividir%n",
a, b, divReal1);
double divReal2 = a / (double) b;
System.out.printf("%d / %d = %.4f ← cast en el divisor%n",
a, b, divReal2);
double divReal3 = (double)(a / b);
System.out.printf("%d / %d = %.4f ← cast DESPUÉS (¡trampa!)%n",
a, b, divReal3);
System.out.println();
System.out.println("--- Desbordamiento de int ---");
int limite = Integer.MAX_VALUE;
System.out.printf("Máximo int: %,d%n", limite);
System.out.printf("Máximo int + 1: %,d ← overflow%n", limite + 1);
long limiteGrande = Integer.MAX_VALUE + 1L;
System.out.printf("Con long: %,d ← correcto%n", limiteGrande);
System.out.println();
System.out.println("--- Widening automático ---");
int entero = 42;
long grande = entero; // automático
double decimal = entero; // automático — 42.0
System.out.printf("int: %d%n", entero);
System.out.printf("long: %d ← widening automático%n", grande);
System.out.printf("double: %.1f ← widening automático%n", decimal);
sc.close();
}
}
Ejecuta con a = 7 y b = 2 y mira la cuarta línea de resultados:
7 / 2 = 3 ← división ENTERA 7 / 2 = 3,5000 ← cast antes de dividir 7 / 2 = 3,5000 ← cast en el divisor 7 / 2 = 3,0000 ← cast DESPUÉS (¡trampa!)
La última línea es la trampa que más gente no ve venir. (double)(a / b) convierte el resultado a double, pero la división ya ocurrió como entera — el daño está hecho. El cast tiene que ir antes de la operación, no después.
Y si alguna vez ves un número negativo enorme donde esperabas un número positivo grande — es overflow. Integer.MAX_VALUE + 1 da -2147483648 porque el entero da la vuelta. La solución es usar long.
Variables en Java práctica — Programa 2: Conversor de temperatura con casting
Las temperaturas son perfectas para practicar casting porque las fórmulas mezclan enteros y decimales constantemente. Además, aquí aparece una restricción física real: no puedes bajar del cero absoluto.
import java.util.Scanner;
public class ConversorTemperatura {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== CONVERSOR DE TEMPERATURA ===");
System.out.println();
System.out.println("¿De qué unidad parto?");
System.out.println("1. Celsius (°C)");
System.out.println("2. Fahrenheit (°F)");
System.out.println("3. Kelvin (K)");
System.out.print("Opción: ");
int opcion = sc.nextInt();
System.out.print("Temperatura: ");
double temp = sc.nextDouble();
// Convertir primero a Celsius
double celsius;
String unidadOrigen;
switch (opcion) {
case 1:
celsius = temp;
unidadOrigen = "°C";
break;
case 2:
celsius = (temp - 32) * 5.0 / 9.0;
unidadOrigen = "°F";
break;
case 3:
celsius = temp - 273.15;
unidadOrigen = "K";
break;
default:
System.out.println("Opción no válida");
sc.close();
return;
}
// Cero absoluto: -273.15°C
if (celsius < -273.15) {
System.out.println("Temperatura por debajo del cero absoluto — imposible");
sc.close();
return;
}
// Convertir a las otras dos
double fahrenheit = celsius * 9.0 / 5.0 + 32;
double kelvin = celsius + 273.15;
// Versión entera — truncada, no redondeada
int celsiusInt = (int) celsius;
int fahrenheitInt = (int) fahrenheit;
int kelvinInt = (int) kelvin;
System.out.println();
System.out.printf("%.2f %s equivale a:%n", temp, unidadOrigen);
System.out.println();
System.out.printf(" Celsius: %8.2f °C%n", celsius);
System.out.printf(" Fahrenheit: %8.2f °F%n", fahrenheit);
System.out.printf(" Kelvin: %8.2f K%n", kelvin);
System.out.println();
System.out.println("--- En entero (casting a int — trunca, no redondea) ---");
System.out.printf(" Celsius: %d °C%n", celsiusInt);
System.out.printf(" Fahrenheit: %d °F%n", fahrenheitInt);
System.out.printf(" Kelvin: %d K%n", kelvinInt);
// Datos curiosos
System.out.println();
System.out.println("--- Temperaturas de referencia ---");
System.out.printf(" Cero absoluto: -273.15 °C = %.2f °F = 0 K%n",
-273.15 * 9.0 / 5.0 + 32);
System.out.printf(" Agua congela: 0.00 °C = 32.00 °F = 273.15 K%n");
System.out.printf(" Agua hierve: 100.00 °C = 212.00 °F = 373.15 K%n");
System.out.printf(" Cuerpo humano: 37.00 °C = %.2f °F = %.2f K%n",
37.0 * 9.0 / 5.0 + 32, 37.0 + 273.15);
sc.close();
}
}
Pruébalo con 100 Celsius — deberías obtener exactamente 212 Fahrenheit y 373,15 Kelvin. Si los números no cuadran, comprueba que las fórmulas usan 5.0 y 9.0 y no 5 y 9. ¿Por qué? Porque 5/9 en Java es 0 — división entera otra vez. El punto decimal lo cambia todo.
Variables en Java práctica — Programa 3: Ficha de producto con String
Aquí entra el tercer susto: == vs .equals(). Este programa trabaja con Strings de verdad — los coge del usuario, los compara, los manipula — y en algún momento vas a ver por qué comparar Strings con == es una de esas cosas que parece que funciona… hasta que no.
import java.util.Scanner;
public class FichaProducto {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== FICHA DE PRODUCTO ===");
System.out.println();
System.out.print("Nombre del producto: ");
String nombre = sc.nextLine();
System.out.print("Categoría (electronica/ropa/hogar): ");
String categoria = sc.nextLine();
System.out.print("Precio (€): ");
double precio = sc.nextDouble();
System.out.print("Stock disponible: ");
int stock = sc.nextInt();
sc.nextLine();
System.out.print("Código de producto (ej. PROD-001): ");
String codigo = sc.nextLine();
// Cálculos con tipos
double precioConIVA = precio * 1.21;
double precioOferta = precio * 0.85; // 15% descuento
boolean disponible = stock > 0;
boolean bajoStock = stock > 0 && stock < 5;
// Operaciones con String
String nombreMayus = nombre.toUpperCase();
String codigoLimpio = codigo.trim().toUpperCase();
int longNombre = nombre.length();
char primeraLetra = nombre.charAt(0);
String categoriaFmt = categoria.trim().toLowerCase();
// Clasificación por categoría
String icono;
if (categoriaFmt.equals("electronica")) {
icono = "💻";
} else if (categoriaFmt.equals("ropa")) {
icono = "👕";
} else if (categoriaFmt.equals("hogar")) {
icono = "🏠";
} else {
icono = "📦";
}
// Mostrar ficha
System.out.println();
System.out.println("╔══════════════════════════════╗");
System.out.printf( "║ %s %-24s║%n", icono, nombreMayus);
System.out.println("╠══════════════════════════════╣");
System.out.printf( "║ Código: %-17s║%n", codigoLimpio);
System.out.printf( "║ Categoría: %-17s║%n", categoriaFmt);
System.out.printf( "║ Precio: %8.2f € ║%n", precio);
System.out.printf( "║ Con IVA: %8.2f € ║%n", precioConIVA);
System.out.printf( "║ Oferta: %8.2f € ║%n", precioOferta);
System.out.printf( "║ Stock: %-17d║%n", stock);
System.out.println("╠══════════════════════════════╣");
System.out.printf( "║ Disponible: %-15s║%n", disponible ? "SÍ ✓" : "NO ✗");
System.out.printf( "║ Bajo stock: %-15s║%n", bajoStock ? "AVISO ⚠" : "---");
System.out.println("╚══════════════════════════════╝");
System.out.println();
System.out.println("--- Análisis del nombre ---");
System.out.printf("Original: %s%n", nombre);
System.out.printf("Mayúsculas: %s%n", nombreMayus);
System.out.printf("Longitud: %d caracteres%n", longNombre);
System.out.printf("Primera letra: %c%n", primeraLetra);
// La trampa del ==
System.out.println();
System.out.println("--- La trampa del == con Strings ---");
String cat1 = "electronica";
String cat2 = categoria.trim().toLowerCase();
System.out.printf("cat1 == cat2: %b ← puede fallar%n", cat1 == cat2);
System.out.printf("cat1.equals(cat2): %b ← siempre correcto%n",
cat1.equals(cat2));
sc.close();
}
}
Pruébalo con «Portátil Gaming», «electronica», 899.99, 3 y «prod-001». Fíjate en la última sección — según cómo Java gestione la memoria internamente, == puede devolver true o false para el mismo contenido. No es predecible. .equals() siempre funciona. No hay debate.
Visualízalo con Python Tutor
Selecciona Java en el desplegable y pega en pythontutor.com:
public class TiposDemo {
public static void main(String[] args) {
// División entera vs real
int a = 7, b = 2;
int divEntera = a / b;
double divReal = (double) a / b;
System.out.println("Entera: " + divEntera);
System.out.println("Real: " + divReal);
// Casting
double precio = 9.99;
int precioEntero = (int) precio;
System.out.println("Precio: " + precio);
System.out.println("Precio (int): " + precioEntero);
// String y equals
String s1 = "hola";
String s2 = new String("hola");
System.out.println("== : " + (s1 == s2));
System.out.println("equals(): " + s1.equals(s2));
}
}
Ejecuta paso a paso. Cuando llegues a (double) a / b observa cómo a se convierte temporalmente a 7.0 antes de dividir — el valor original no cambia, el cast solo afecta a esa operación. Cuando llegues a (int) precio verás que 9.99 se convierte en 9 — truncado, no redondeado. Y cuando llegues al == con los Strings, Python Tutor te muestra las flechas de memoria: s1 y s2 apuntan a objetos distintos aunque tengan el mismo texto, de ahí que == sea false.
Resumen y siguiente paso
Tres programas, tres sustos resueltos. La división entera ocurre cuando ambos operandos son int — pon el cast antes de la operación. El casting a int trunca, no redondea — si necesitas redondear usa Math.round(). Y los Strings se comparan siempre con .equals(), nunca con ==.
En el siguiente artículo tienes ejercicios para resolver por tu cuenta.
Siguiente paso: ejerciciosVariables en Java — ejercicios para dominar tipos, casting y Strings
Un comentario