Un programa es, en esencia, datos que se transforman. Las variables son los recipientes donde guardas esos datos y los tipos son las reglas que determinan qué cabe en cada recipiente y qué operaciones tienen sentido con él. En Java estas reglas se comprueban antes de ejecutar nada, y eso convierte al sistema de tipos en tu primera red de seguridad: mucho de lo que en otros lenguajes explota en producción, aquí ni siquiera compila. En esta lección aprenderás los ocho tipos primitivos, la diferencia crucial entre primitivos y referencias, el comportamiento especial de String, las conversiones de tipo, las constantes y la inferencia con var. Al terminar habrás modelado con variables el primer libro del catálogo de BiblioTech.
Contenido
- Declaración, inicialización y asignación
- Los ocho tipos primitivos
- Literales: cómo se escriben los valores
- Primitivos frente a referencias: qué guarda cada variable
String: el tipo especial- Conversiones de tipo
- Envoltorios, autoboxing y conversión desde texto
finaly constantes- Inferencia de tipos con
var - Modelando un libro de BiblioTech
- Errores Comunes y Consejos
- Ejercicios
- Declaración, inicialización y asignación
Tres operaciones que conviene distinguir desde el principio:
int anioPublicacion; // 1. DECLARACION: reservamos el nombre y fijamos el tipo
anioPublicacion = 2018; // 2. ASIGNACION: le damos un valor
int diasRetraso = 12; // 3. DECLARACION + INICIALIZACION en una sola linea- Declarar es anunciar al compilador: "existirá una variable llamada
anioPublicacionque contendrá enteros". A partir de ahí, el compilador vigila que no le metas otra cosa. - Inicializar es darle su primer valor.
- Asignar es darle un valor (el primero o cualquier otro posterior). El símbolo
=no significa igualdad matemática, sino "guarda a la derecha en la variable de la izquierda".
Una regla que Java impone y que conviene celebrar: no puedes leer una variable local antes de asignarle un valor.
int diasRetraso;
System.out.println(diasRetraso); // ERROR de compilacion: variable diasRetraso might not have been initializedOtros lenguajes te devolverían basura o undefined; Java se niega a compilar. Eso elimina toda una familia de errores sutiles.
Puedes declarar varias variables del mismo tipo en una línea, aunque por legibilidad se prefiere una por línea:
- Los ocho tipos primitivos
Java tiene exactamente ocho tipos primitivos. No son objetos: son valores puros que la JVM manipula de forma directa y eficiente.
| Tipo | Categoría | Tamaño | Rango | Valor por defecto | Uso típico |
|---|---|---|---|---|---|
byte |
Entero | 8 bits | −128 a 127 | 0 |
Datos binarios, ahorro de memoria |
short |
Entero | 16 bits | −32.768 a 32.767 | 0 |
Poco usado |
int |
Entero | 32 bits | −2.147.483.648 a 2.147.483.647 | 0 |
El entero por defecto |
long |
Entero | 64 bits | ±9,22 × 10¹⁸ | 0L |
Marcas de tiempo, identificadores, cifras grandes |
float |
Decimal | 32 bits | ~7 dígitos significativos | 0.0f |
Poco usado; precisión insuficiente |
double |
Decimal | 64 bits | ~15 dígitos significativos | 0.0d |
El decimal por defecto |
char |
Carácter | 16 bits | 0 a 65.535 (un carácter Unicode) | '�' |
Un único carácter |
boolean |
Lógico | JVM-dependiente | true o false |
false |
Condiciones, banderas |
Notas importantes sobre esta tabla:
- La columna "valor por defecto" solo aplica a los campos de una clase (módulo 3), no a las variables locales dentro de
main, que como acabamos de ver deben inicializarse explícitamente. - En la práctica usarás
int,double,booleanycharel 95 % del tiempo.byte,shortyfloatson casos especiales. longes imprescindible cuandointse queda corto. El límite deint(unos 2.147 millones) parece enorme hasta que cuentas milisegundos: el número de milisegundos desde 1970 desbordóinten 1970 + 24 días.charno es unStringde un carácter: se escribe con comillas simples ('A') y es un tipo numérico por debajo.booleanen Java no es un número. No existe la equivalencia "0 es falso, 1 es verdadero" de C:if (1)no compila.
byte codigoSeccion = 3; // secciones de la biblioteca: 1..12
short ejemplaresTotales = 850; // libros en el catalogo de Nexus Software
int anioPublicacion = 2018;
long identificadorPrestamo = 100000000045L; // la L es obligatoria: no cabe en un int
float pesoLibroKg = 0.68f; // la f es obligatoria
double multa = 3.75;
char inicialSeccion = 'J'; // comillas SIMPLES
boolean disponible = true;
- Literales: cómo se escriben los valores
Un literal es un valor escrito directamente en el código. Java admite varias notaciones:
Literales enteros
int decimal = 2018; // base 10, lo normal
int hexadecimal = 0x7E2; // base 16, prefijo 0x -> 2018
int binario = 0b11111100010; // base 2, prefijo 0b -> 2018 (desde Java 7)
int octal = 03742; // base 8, prefijo 0 -> 2018 (evitar: confunde)
long codigoLargo = 9788498750102L; // sufijo L obligatorio si supera el rango de intCuidado con el octal: int x = 010; vale 8, no 10. Es una fuente clásica de errores; evita los ceros a la izquierda.
Guiones bajos como separadores
Desde Java 7 puedes usar _ para hacer legibles los números largos. El compilador los ignora por completo:
int presupuestoAnual = 1_250_000; // se lee mucho mejor que 1250000
long isbnNumerico = 978_000_000_0001L;
int mascara = 0b1010_0101_1100_0011;Restricciones: no pueden ir al principio, al final, ni junto al punto decimal.
Literales decimales
double multa = 3.75;
double tarifa = 0.25d; // la d es opcional: double es el tipo por defecto
float peso = 0.68f; // la f SI es obligatoria
double notacionCientifica = 1.5e3; // 1500.0Regla que causa muchos errores: un literal decimal sin sufijo es double. Por eso float peso = 0.68; no compila: estás intentando meter un double en un float, que es más pequeño. Hay que escribir 0.68f.
Literales de carácter y booleanos
char letra = 'J';
char codigo = 74; // char es numerico por debajo: 74 es la 'J' en Unicode
char salto = '\n'; // secuencia de escape
boolean disponible = true;
boolean prestado = false;Secuencias de escape más usadas:
| Secuencia | Significado |
|---|---|
\n |
Salto de línea |
\t |
Tabulador |
\" |
Comilla doble dentro de un String |
\' |
Comilla simple dentro de un char |
\\ |
Barra invertida |
- Primitivos frente a referencias: qué guarda cada variable
Esta es una de las ideas más importantes del módulo, y la que explica muchos comportamientos que de otro modo parecen arbitrarios.
Java divide los tipos en dos familias:
- Tipos primitivos (los ocho anteriores): la variable contiene el valor directamente.
- Tipos por referencia (
String, arrays, y todas las clases): la variable contiene una referencia (una dirección) a un objeto que vive en otra zona de memoria.
La memoria de un programa Java se organiza, de forma simplificada, en dos zonas:
- La pila (stack): rápida y pequeña, guarda las variables locales de los métodos.
- El montículo (heap): grande, guarda los objetos. Es donde actúa el recolector de basura.
flowchart LR
subgraph Pila["Pila (variables locales de main)"]
A["anioPublicacion<br/><b>2018</b>"]
B["disponible<br/><b>true</b>"]
C["titulo<br/><b>ref → #a1b2</b>"]
D["autor<br/><b>ref → #c3d4</b>"]
end
subgraph Heap["Montículo (objetos)"]
E["#a1b2<br/>String: 'Java Efectivo'"]
F["#c3d4<br/>String: 'Joshua Bloch'"]
end
C --> E
D --> F
Fíjate en la diferencia: anioPublicacion es 2018; titulo no es el texto, sino una flecha que apunta a él.
Consecuencias prácticas inmediatas:
// Con primitivos: se copia el VALOR
int diasA = 12;
int diasB = diasA; // diasB recibe una copia del numero
diasA = 20;
System.out.println(diasB); // 12 -> diasB no se ha visto afectado
// Con referencias: se copia la REFERENCIA
String tituloA = "Java Efectivo";
String tituloB = tituloA; // ambas apuntan al MISMO objetoUna variable de referencia puede además valer null, que significa "no apunta a ningún objeto". Los primitivos nunca pueden ser null.
String editorial = null; // valido: la referencia no apunta a nada
// int paginas = null; // ERROR: un int siempre tiene un numeroIntentar usar una referencia null produce el error de ejecución más famoso de Java, NullPointerException. Lo tratarás formalmente en el módulo 6.
String: el tipo especial
String: el tipo especialString no es un primitivo, es una clase. Pero recibe un trato tan privilegiado del lenguaje que se comporta a medio camino.
Creación
String titulo = "Java Efectivo"; // forma normal, con literal
String autor = new String("Joshua Bloch"); // funciona, pero NO se usaString es la única clase que se puede crear con un literal, sin new. Usar new String(...) es un antipatrón: crea un objeto extra sin ninguna ventaja.
Inmutabilidad
Un String no se puede modificar nunca. Todos los métodos que "cambian" una cadena devuelven en realidad una cadena nueva:
String titulo = "Java Efectivo";
titulo.toUpperCase(); // calcula "JAVA EFECTIVO"... y lo tira
System.out.println(titulo); // sigue imprimiendo "Java Efectivo"
titulo = titulo.toUpperCase(); // CORRECTO: guardamos el resultado
System.out.println(titulo); // "JAVA EFECTIVO"Este es uno de los errores más frecuentes de quien empieza. Si un método de String no parece hacer nada, casi seguro que has olvidado guardar el resultado.
¿Por qué son inmutables? Por seguridad (una cadena no puede cambiar bajo tus pies), por eficiencia (permite compartir cadenas idénticas en el pool de cadenas) y porque las hace seguras entre hilos sin coste alguno (módulo 8).
Concatenación
String titulo = "Java Efectivo";
int anioPublicacion = 2018;
String ficha = titulo + " (" + anioPublicacion + ")";
System.out.println(ficha); // Java Efectivo (2018)El operador + concatena. Cuando uno de los operandos es un String, Java convierte automáticamente el otro a texto. Esto también significa que "Total: " + 2 + 3 produce "Total: 23" y no "Total: 5": se evalúa de izquierda a derecha, y en cuanto hay un String todo lo demás se pega como texto. Se corrige con paréntesis: "Total: " + (2 + 3).
Métodos esenciales
Partimos de:
| Método | Qué hace | Ejemplo | Resultado |
|---|---|---|---|
length() |
Número de caracteres | "Java Efectivo".length() |
13 |
trim() |
Elimina espacios de los extremos | titulo.trim() |
"Java Efectivo" |
strip() |
Como trim pero Unicode-aware (Java 11+) |
titulo.strip() |
"Java Efectivo" |
toUpperCase() |
Todo a mayúsculas | "java".toUpperCase() |
"JAVA" |
toLowerCase() |
Todo a minúsculas | "JAVA".toLowerCase() |
"java" |
substring(i) |
Desde el índice i hasta el final |
"Java Efectivo".substring(5) |
"Efectivo" |
substring(i, j) |
Del índice i al j (sin incluir j) |
"Java Efectivo".substring(0, 4) |
"Java" |
equals(otro) |
¿Contenido idéntico? | "java".equals("Java") |
false |
equalsIgnoreCase(otro) |
Idéntico ignorando mayúsculas | "java".equalsIgnoreCase("Java") |
true |
isEmpty() |
¿Longitud cero? | "".isEmpty() |
true |
isBlank() |
¿Vacía o solo espacios? (Java 11+) | " ".isBlank() |
true |
contains(txt) |
¿Contiene ese fragmento? | "Java Efectivo".contains("Efec") |
true |
replace(a, b) |
Sustituye | "Java".replace('a', 'o') |
"Jovo" |
charAt(i) |
Carácter en la posición i |
"Java".charAt(0) |
'J' |
indexOf(txt) |
Posición de la primera aparición (−1 si no está) | "Java Efectivo".indexOf("E") |
5 |
Los índices empiezan en 0, y substring(i, j) incluye i pero excluye j. Es la convención de todo Java; interiorízala ya.
Ejemplo aplicado a BiblioTech:
String isbn = "978-0000000001";
System.out.println("ISBN completo: " + isbn);
System.out.println("Prefijo GS1: " + isbn.substring(0, 3)); // "978"
System.out.println("Codigo: " + isbn.substring(4)); // "0000000001"
System.out.println("Longitud: " + isbn.length()); // 14Text blocks (Java 15+)
Para textos de varias líneas existe una sintaxis con triple comilla que evita los \n y las concatenaciones:
String cabecera = """
============================================
BiblioTech - Nexus Software
Sistema de gestion de la biblioteca
============================================
""";
System.out.println(cabecera);Detalles: la triple comilla de apertura debe ir seguida de un salto de línea, y la indentación se calcula respecto a la línea de cierre, de modo que puedes indentar el bloque dentro del código sin que esos espacios aparezcan en la salida. Es enormemente cómodo para menús, plantillas o fragmentos de JSON y SQL.
- Conversiones de tipo
Cuando mezclas tipos numéricos, Java aplica reglas estrictas.
Conversión ensanchante (widening): automática
Va de un tipo pequeño a uno mayor. No se pierde información, así que Java la hace sola:
int diasRetraso = 12;
double diasComoDecimal = diasRetraso; // automatico: 12.0
System.out.println(diasComoDecimal); // 12.0Esto explica por qué 12 * 0.25 da 3.0: el int se convierte a double antes de multiplicar.
Conversión estrechante (narrowing): requiere cast explícito
Va de un tipo mayor a uno menor. Puede perder información, así que Java te obliga a pedirla explícitamente con un cast, que es tu firma de "sé lo que hago":
double multaExacta = 3.75;
int multaEntera = (int) multaExacta; // cast obligatorio
System.out.println(multaEntera); // 3 <- se TRUNCA, no se redondeaPuntos críticos:
- El cast a entero trunca, no redondea.
(int) 3.99es3. Para redondear se usaMath.round(3.99), que da4. - Si el valor no cabe, el resultado es basura silenciosa:
int grande = 200;
byte pequeno = (byte) grande;
System.out.println(pequeno); // -56 <- desbordamiento silenciosoAquí no hay error ni aviso: el compilador asume que sabías lo que hacías. Por eso los casts deben usarse con conocimiento de causa.
Promoción en expresiones
En una operación entre tipos distintos, Java promociona al mayor de los dos:
int diasRetraso = 12;
double tarifa = 0.25;
double multa = diasRetraso * tarifa; // int se promociona a double -> 3.0Y la trampa clásica, que veremos a fondo en la lección de operadores:
La división se hace entre enteros (dando 2) y solo después se convierte a double. La solución es forzar antes: (double) total / partes.
- Envoltorios, autoboxing y conversión desde texto
Cada primitivo tiene una clase envoltorio (wrapper) que lo representa como objeto:
| Primitivo | Envoltorio |
|---|---|
byte |
Byte |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
char |
Character |
boolean |
Boolean |
¿Para qué sirven? Por dos motivos:
- Las colecciones (módulo 5) solo admiten objetos, no primitivos. No puedes tener una lista de
int, pero sí deInteger. - Pueden ser
null, lo que permite representar "sin valor" (un año de publicación desconocido, por ejemplo).
Autoboxing y unboxing
Desde Java 5, la conversión entre primitivo y envoltorio es automática:
Integer anioObjeto = 2018; // autoboxing: int -> Integer
int anioPrimitivo = anioObjeto; // unboxing: Integer -> intEs cómodo, pero tiene dos costes que conviene conocer: consume más memoria y, sobre todo, un unboxing sobre una referencia null lanza NullPointerException. Regla práctica: usa primitivos salvo que necesites null o una colección.
Métodos estáticos útiles de los envoltorios
Aquí está su utilidad más inmediata en este módulo: convertir texto a número. Recuerda que los argumentos de línea de comandos y lo que se lee por consola llegan siempre como String.
String textoAnio = "2018";
int anioPublicacion = Integer.parseInt(textoAnio); // 2018 como numero
String textoMulta = "3.75";
double multa = Double.parseDouble(textoMulta); // 3.75 como numero
// Constantes utiles
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
// Conversion inversa: numero -> texto
String comoTexto = String.valueOf(2018);Si el texto no representa un número válido (Integer.parseInt("dos mil")), el programa falla en ejecución con NumberFormatException. Cómo capturar y tratar ese fallo se estudia en el módulo 6; por ahora basta con saber que existe y con introducir datos correctos.
final y constantes
final y constantesLa palabra final aplicada a una variable significa que su valor no puede cambiar después de asignarse:
final double TARIFA_DIARIA = 0.25;
TARIFA_DIARIA = 0.30; // ERROR de compilacion: cannot assign a value to final variablePor qué usarlas:
- Comunican intención. Quien lee el código sabe que ese valor es una regla de negocio, no un dato variable.
- Evitan errores. Un valor que no debe cambiar, no puede cambiar por accidente.
- Eliminan los "números mágicos". Comparar
0.25disperso por veinte sitios con una únicaTARIFA_DIARIAes la diferencia entre poder cambiar la tarifa en un minuto o en una tarde.
Las constantes se escriben en MAYUSCULAS_CON_GUION_BAJO, como vimos en la lección anterior:
final double TARIFA_DIARIA = 0.25; // euros por dia de retraso
final int DIAS_PRESTAMO = 15; // duracion estandar del prestamo
final double MULTA_MAXIMA = 20.0; // tope de multa por prestamo
final String NOMBRE_EMPRESA = "Nexus Software";Un matiz importante para más adelante: en una variable de referencia, final impide reasignar la referencia, no modificar el objeto apuntado. Con String no se nota porque son inmutables, pero con objetos mutables (módulo 3) sí.
- Inferencia de tipos con
var
varDesde Java 10 puedes omitir el tipo de una variable local y dejar que el compilador lo deduzca del valor asignado:
var titulo = "Java Efectivo"; // el compilador infiere String
var anioPublicacion = 2018; // infiere int
var multa = 3.75; // infiere double
var disponible = true; // infiere booleanEs crucial entender que var no convierte Java en un lenguaje de tipado dinámico. El tipo se fija en compilación y es tan estricto como siempre:
Cuándo sí y cuándo no
| Situación | Recomendación | Ejemplo |
|---|---|---|
| El tipo es evidente por el valor | Usa var |
var scanner = new Scanner(System.in); |
| El tipo es largo y repetitivo | Usa var |
var catalogo = new HashMap<String, Libro>(); |
| El tipo no se deduce leyendo | Evita var |
var resultado = procesar(datos); |
| Quieres un tipo concreto distinto del inferido | No uses var |
double tarifa = 1; (con var sería int) |
| Literales numéricos simples | Discutible; el tipo explícito suele ser más claro | int diasRetraso = 12; |
Restricciones de var:
- Solo para variables locales (dentro de métodos). No vale para campos de clase ni parámetros.
- Obliga a inicializar en la misma línea:
var x;no compila. - No admite
nullcomo valor inicial:var x = null;no compila, porque no hay tipo que inferir.
Este curso usa tipos explícitos en el módulo 1 (para que veas siempre qué tipo hay en juego) y var a partir del módulo 5, donde los tipos genéricos lo hacen realmente útil.
- Modelando un libro de BiblioTech
Apliquemos todo lo aprendido. El catálogo de Nexus Software necesita registrar, para cada libro: título, autor, ISBN, año de publicación y disponibilidad. Con lo que sabes hoy, eso se traduce en variables sueltas:
public class CatalogoBiblioTech {
public static void main(String[] args) {
// --- Constantes de negocio de BiblioTech ---
final String NOMBRE_EMPRESA = "Nexus Software";
final double TARIFA_DIARIA = 0.25; // euros por dia de retraso
final int DIAS_PRESTAMO = 15; // duracion estandar del prestamo
// --- Datos del primer libro del catalogo ---
String titulo = "Java Efectivo";
String autor = "Joshua Bloch";
String isbn = "978-0000000001";
int anioPublicacion = 2018;
boolean disponible = true;
// --- Datos de un prestamo en curso ---
String empleado = "Marta Ruiz";
int diasTranscurridos = 27;
int diasRetraso = diasTranscurridos - DIAS_PRESTAMO; // 12
double multa = diasRetraso * TARIFA_DIARIA; // int * double -> double
// --- Salida ---
System.out.println("=== " + NOMBRE_EMPRESA + " - BiblioTech ===");
System.out.println();
System.out.println("Titulo: " + titulo);
System.out.println("Autor: " + autor);
System.out.println("ISBN: " + isbn);
System.out.println("Publicacion: " + anioPublicacion);
System.out.println("Disponible: " + disponible);
System.out.println();
System.out.println("Prestado a: " + empleado);
System.out.println("Dias de retraso: " + diasRetraso);
System.out.println("Multa acumulada: " + multa + " EUR");
}
}Salida:
=== Nexus Software - BiblioTech === Titulo: Java Efectivo Autor: Joshua Bloch ISBN: 978-0000000001 Publicacion: 2018 Disponible: true Prestado a: Marta Ruiz Dias de retraso: 12 Multa acumulada: 3.0 EUR
La limitación que ya se nota
Este enfoque funciona para un libro. Pero Nexus Software tiene cientos. Con variables sueltas necesitarías titulo1, titulo2, titulo3… y nada garantizaría que autor2 corresponde realmente a titulo2. Los datos que forman una unidad conceptual están desperdigados.
Esa es exactamente la carencia que resuelve la programación orientada a objetos: en el módulo 3 crearás una clase Libro que agrupe estas cinco variables en un único tipo, y en el módulo 5 guardarás cientos de esos objetos en una colección. Fíjate en que los nombres que estás usando ahora (titulo, autor, isbn, anioPublicacion, disponible) serán literalmente los campos de esa clase. Estás sentando la base.
Errores Comunes y Consejos
- Olvidar guardar el resultado de un método de
String.titulo.toUpperCase();no cambia nada. Debe sertitulo = titulo.toUpperCase();. float x = 3.75;no compila. Los literales decimales sondouble; hay que escribir3.75f.long x = 10000000000;no compila. El literal se interpreta comointy desborda. Hay que escribir10000000000L.- Confundir
'A'con"A". Comillas simples eschar, dobles esString. No son intercambiables. - Esperar que
(int) 3.99sea 4. El cast trunca. Para redondear,Math.round(). - Usar
==para compararString. Compara referencias, no contenido. Se usaequals(). Es tan importante que la próxima lección le dedica un apartado completo. - Declarar variables sin inicializar y leerlas. El compilador lo impide en variables locales; agradécelo.
- Abusar de
var.var resultado = calcular();obliga al lector a ir a buscar la firma del método. Úsalo solo cuando el tipo sea evidente. - Consejo: declara
finaltodo lo que no vaya a cambiar. Es gratis y convierte un error potencial en un error de compilación. - Consejo: usa nombres que digan qué contiene la variable, no de qué tipo es.
diasRetrasoes mejor quenumeroEntero1. - Consejo: cuando dudes de un método de
String, ábrelo en JShell y pruébalo. Cinco segundos frente a diez minutos de suposiciones.
Ejercicios
Ejercicio 1: Predecir la salida
Sin ejecutar el código, escribe qué imprime cada línea y justifica por qué. Después compruébalo en JShell o compilándolo.
public class PruebaTipos {
public static void main(String[] args) {
int a = 7;
int b = 2;
System.out.println(a / b);
System.out.println((double) a / b);
System.out.println((int) 3.99);
System.out.println(Math.round(3.99));
String titulo = "Java Efectivo";
titulo.toUpperCase();
System.out.println(titulo);
System.out.println(titulo.substring(0, 4));
System.out.println(titulo.length());
System.out.println("Total: " + 2 + 3);
System.out.println("Total: " + (2 + 3));
byte pequeno = (byte) 300;
System.out.println(pequeno);
}
}Ejercicio 2: Ficha completa de un libro
Escribe la clase FichaCompleta que declare las variables necesarias para el libro "Patrones de Diseño" (ISBN 978-0000000002, año 1994, autor "Erich Gamma y otros", disponible) y calcule y muestre:
- Los años de antigüedad del libro respecto a 2026.
- El ISBN sin el prefijo
978-. - El título en mayúsculas.
- Si el título tiene más de 10 caracteres (usa una variable
booleany calcula el valor con una comparación, sinif).
Usa constantes final donde corresponda y respeta las convenciones de nomenclatura.
Ejercicio 3: Corregir los errores de tipos
El siguiente código tiene seis errores de compilación relacionados con tipos. Encuéntralos, explica cada uno y escribe la versión corregida.
public class ErroresTipos {
public static void main(String[] args) {
float tarifaDiaria = 0.25;
long identificador = 100000000045;
char seccion = "J";
int multa = 3.75;
final int DIAS_PRESTAMO = 15;
DIAS_PRESTAMO = 20;
int paginas;
System.out.println(paginas);
}
}Soluciones
Solución 1
Justificación línea a línea:
a / b→3. Ambos sonint, así que se hace división entera: el resultado 3,5 se trunca a 3. Es el error más clásico de Java.(double) a / b→3.5. El cast se aplica aaantes de dividir, así que la operación es7.0 / 2y por promoción da3.5.(int) 3.99→3. El cast a entero trunca la parte decimal; no redondea.Math.round(3.99)→4. Este sí redondea al entero más cercano.titulo→Java Efectivo.toUpperCase()devuelve una cadena nueva que se descarta, porque no se ha asignado. LosStringson inmutables.substring(0, 4)→Java. Desde el índice 0 incluido hasta el 4 excluido: caracteres 0, 1, 2 y 3.length()→13. "Java Efectivo" tiene 4 + 1 espacio + 8 = 13 caracteres."Total: " + 2 + 3→Total: 23. Se evalúa de izquierda a derecha:"Total: " + 2da"Total: 2", y a esa cadena se le pega el 3."Total: " + (2 + 3)→Total: 5. Los paréntesis fuerzan la suma numérica primero.(byte) 300→44. Unbytesolo llega a 127. El valor desborda y se conservan únicamente los 8 bits bajos de 300 (100101100→00101100= 44). No hay ningún aviso: es una pérdida silenciosa.
Solución 2
public class FichaCompleta {
public static void main(String[] args) {
// Constantes: valores que no cambian durante la ejecucion
final String NOMBRE_EMPRESA = "Nexus Software";
final int ANIO_ACTUAL = 2026;
final int LONGITUD_TITULO_LARGO = 10;
final String PREFIJO_ISBN = "978-";
// Datos del libro
String titulo = "Patrones de Diseno";
String autor = "Erich Gamma y otros";
String isbn = "978-0000000002";
int anioPublicacion = 1994;
boolean disponible = true;
// 1. Antiguedad: resta de enteros
int antiguedad = ANIO_ACTUAL - anioPublicacion;
// 2. ISBN sin prefijo. PREFIJO_ISBN.length() vale 4, asi que
// substring(4) devuelve todo a partir del quinto caracter.
String isbnSinPrefijo = isbn.substring(PREFIJO_ISBN.length());
// 3. Titulo en mayusculas. Guardamos el resultado: los String son inmutables.
String tituloMayusculas = titulo.toUpperCase();
// 4. Una comparacion produce directamente un boolean, sin necesidad de if.
boolean tituloLargo = titulo.length() > LONGITUD_TITULO_LARGO;
// --- Salida ---
System.out.println("=== " + NOMBRE_EMPRESA + " - BiblioTech ===");
System.out.println("Titulo: " + titulo);
System.out.println("Autor: " + autor);
System.out.println("ISBN: " + isbn);
System.out.println("Publicacion: " + anioPublicacion);
System.out.println("Disponible: " + disponible);
System.out.println("Antiguedad: " + antiguedad + " anios");
System.out.println("ISBN sin prefijo: " + isbnSinPrefijo);
System.out.println("Titulo mayusculas: " + tituloMayusculas);
System.out.println("Titulo largo: " + tituloLargo);
}
}Salida:
=== Nexus Software - BiblioTech === Titulo: Patrones de Diseno Autor: Erich Gamma y otros ISBN: 978-0000000002 Publicacion: 1994 Disponible: true Antiguedad: 32 anios ISBN sin prefijo: 0000000002 Titulo mayusculas: PATRONES DE DISENO Titulo largo: true
La idea clave del punto 4: una comparación como titulo.length() > 10 es una expresión booleana. No hace falta un if para obtener true o false; el if sirve para decidir qué hacer con ese valor, y eso llega en el módulo 2.
Solución 3
Los seis errores:
float tarifaDiaria = 0.25;— el literal0.25esdouble; no cabe en unfloatsin sufijo. Solución:0.25f(o mejor, usardouble).long identificador = 100000000045;— el literal se interpreta comointy desborda su rango. Falta el sufijoL.char seccion = "J";— las comillas dobles crean unString. Uncharnecesita comillas simples:'J'.int multa = 3.75;— asignar undoublea unintes una conversión estrechante y requiere cast explícito (o, mejor, declararmultacomodouble, que es lo correcto para dinero).DIAS_PRESTAMO = 20;— la variable esfinal; no puede reasignarse.System.out.println(paginas);—paginasse ha declarado pero nunca inicializado, y las variables locales deben tener valor antes de leerse.
Versión corregida:
public class ErroresTipos {
public static void main(String[] args) {
double tarifaDiaria = 0.25; // 1. double es el tipo natural para decimales
long identificador = 100000000045L; // 2. sufijo L para literales long
char seccion = 'J'; // 3. comillas simples para char
double multa = 3.75; // 4. el importe es decimal, no entero
final int DIAS_PRESTAMO = 15; // 5. constante: se asigna una sola vez
int paginas = 416; // 6. inicializada antes de usarse
System.out.println("Tarifa diaria: " + tarifaDiaria);
System.out.println("Identificador: " + identificador);
System.out.println("Seccion: " + seccion);
System.out.println("Multa: " + multa);
System.out.println("Dias prestamo: " + DIAS_PRESTAMO);
System.out.println("Paginas: " + paginas);
}
}Conclusión
Ya sabes declarar, inicializar y asignar variables; conoces los ocho tipos primitivos con sus rangos y cuáles usarás de verdad; escribes literales en cualquier base y con sufijos correctos; distingues los primitivos (que guardan el valor) de las referencias (que guardan una flecha al montículo); dominas String, su inmutabilidad y sus métodos esenciales, incluidos los text blocks; conviertes entre tipos entendiendo cuándo la conversión es automática y cuándo trunca; usas envoltorios y Integer.parseInt para transformar texto en número; proteges tus reglas de negocio con final; y sabes cuándo var ayuda y cuándo estorba. Con todo ello has modelado el primer libro de BiblioTech.
En la siguiente lección, Operadores, pondremos esos datos en movimiento: aritmética (incluida la trampa de la división entera y el módulo), asignación compuesta, incremento y decremento, comparaciones, operadores lógicos con evaluación de cortocircuito, el operador ternario, operaciones a nivel de bit, precedencia, y el error clásico de comparar cadenas con == en lugar de equals. El hilo será el cálculo de la multa por retraso de un préstamo de BiblioTech.
Curso de Programación en Java
Módulo 1: Introducción a Java
- Introducción a Java
- Configuración del Entorno de Desarrollo
- Sintaxis y Estructura Básica
- Variables y Tipos de Datos
- Operadores
- Entrada y Salida por Consola
- Tu Primer Programa Completo: BiblioTech
Módulo 2: Flujo de Control
- Sentencias Condicionales
- Bucles
- Sentencias Switch
- Break y Continue
- Depuración y Trazas de Ejecución
- Proyecto: Menú Interactivo de BiblioTech
Módulo 3: Programación Orientada a Objetos
- Introducción a la POO
- Clases y Objetos
- Métodos
- Constructores
- Herencia
- Polimorfismo
- Encapsulamiento
- Abstracción
- La Clase Object: equals, hashCode y toString
Módulo 4: Programación Orientada a Objetos Avanzada
- Interfaces
- Clases Abstractas
- Clases Internas
- Clases Anónimas
- Expresiones Lambda
- Interfaces Funcionales y Referencias a Métodos
- Enumeraciones y Registros
Módulo 5: Estructuras de Datos y Colecciones
- Arreglos
- El Framework de Colecciones
- ArrayList
- LinkedList
- HashMap
- HashSet
- Cola y Deque
- Pila
- Ordenación y Búsqueda en Colecciones
Módulo 6: Manejo de Excepciones
- Introducción a las Excepciones
- Bloque Try-Catch
- Throw y Throws
- Excepciones Personalizadas
- Bloque Finally
- Try-with-resources y AutoCloseable
- Estrategias de Manejo de Errores y Logging
Módulo 7: Entrada/Salida de Archivos
- Lectura de Archivos
- Escritura de Archivos
- Flujos de Archivos
- BufferedReader y BufferedWriter
- Serialización
- La API NIO.2: Path y Files
- Formatos de Intercambio: CSV y Properties
Módulo 8: Multihilo y Concurrencia
- Introducción al Multihilo
- Creación de Hilos
- Ciclo de Vida de un Hilo
- Sincronización
- Utilidades de Concurrencia
- Colecciones Concurrentes y Variables Atómicas
- Tareas Asíncronas con CompletableFuture
Módulo 9: Redes
- Introducción a las Redes
- Sockets
- ServerSocket
- DatagramSocket y DatagramPacket
- URL y HttpURLConnection
- El Cliente HTTP Moderno
Módulo 10: Temas Avanzados
- Genéricos
- Anotaciones
- Reflexión
- Características de Java 8: Streams y Optional
- Fechas y Horas con java.time
- Java 9 y Más Allá
- Memoria, Recolección de Basura y Rendimiento
Módulo 11: Frameworks y Librerías de Java
- Introducción a los Frameworks de Java
- Spring Framework
- Hibernate
- JUnit
- Maven
- Pruebas Avanzadas con Mockito
- Librerías Esenciales del Ecosistema
