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

  1. Declaración, inicialización y asignación
  2. Los ocho tipos primitivos
  3. Literales: cómo se escriben los valores
  4. Primitivos frente a referencias: qué guarda cada variable
  5. String: el tipo especial
  6. Conversiones de tipo
  7. Envoltorios, autoboxing y conversión desde texto
  8. final y constantes
  9. Inferencia de tipos con var
  10. Modelando un libro de BiblioTech
  11. Errores Comunes y Consejos
  12. Ejercicios

  1. 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 anioPublicacion que 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 initialized

Otros 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:

int diasPrestamo = 15, diasRetraso = 12;   // valido, pero poco legible

  1. 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, boolean y char el 95 % del tiempo. byte, short y float son casos especiales.
  • long es imprescindible cuando int se queda corto. El límite de int (unos 2.147 millones) parece enorme hasta que cuentas milisegundos: el número de milisegundos desde 1970 desbordó int en 1970 + 24 días.
  • char no es un String de un carácter: se escribe con comillas simples ('A') y es un tipo numérico por debajo.
  • boolean en 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;

  1. 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 int

Cuidado 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.0

Regla 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

  1. 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 objeto

Una 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 numero

Intentar 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.

  1. String: el tipo especial

String 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 usa

String 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:

String titulo = "  Java Efectivo  ";
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());           // 14

Text 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.

  1. 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:

byte → short → int → long → float → double
        char ↗
int diasRetraso = 12;
double diasComoDecimal = diasRetraso;   // automatico: 12.0
System.out.println(diasComoDecimal);    // 12.0

Esto 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 redondea

Puntos críticos:

  • El cast a entero trunca, no redondea. (int) 3.99 es 3. Para redondear se usa Math.round(3.99), que da 4.
  • Si el valor no cabe, el resultado es basura silenciosa:
int grande = 200;
byte pequeno = (byte) grande;
System.out.println(pequeno);   // -56  <- desbordamiento silencioso

Aquí 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.0

Y la trampa clásica, que veremos a fondo en la lección de operadores:

int total = 5;
int partes = 2;
double resultado = total / partes;      // 2.0, NO 2.5

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.

  1. 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:

  1. Las colecciones (módulo 5) solo admiten objetos, no primitivos. No puedes tener una lista de int, pero sí de Integer.
  2. 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 -> int

Es 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.

  1. final y constantes

La 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 variable

Por 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.25 disperso por veinte sitios con una única TARIFA_DIARIA es 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í.

  1. Inferencia de tipos con var

Desde 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 boolean

Es 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:

var titulo = "Java Efectivo";
titulo = 2018;    // ERROR: titulo es String para 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 null como 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.

  1. 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 ser titulo = titulo.toUpperCase();.
  • float x = 3.75; no compila. Los literales decimales son double; hay que escribir 3.75f.
  • long x = 10000000000; no compila. El literal se interpreta como int y desborda. Hay que escribir 10000000000L.
  • Confundir 'A' con "A". Comillas simples es char, dobles es String. No son intercambiables.
  • Esperar que (int) 3.99 sea 4. El cast trunca. Para redondear, Math.round().
  • Usar == para comparar String. Compara referencias, no contenido. Se usa equals(). 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 final todo 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. diasRetraso es mejor que numeroEntero1.
  • 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:

  1. Los años de antigüedad del libro respecto a 2026.
  2. El ISBN sin el prefijo 978-.
  3. El título en mayúsculas.
  4. Si el título tiene más de 10 caracteres (usa una variable boolean y calcula el valor con una comparación, sin if).

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

3
3.5
3
4
Java Efectivo
Java
13
Total: 23
Total: 5
44

Justificación línea a línea:

  • a / b3. Ambos son int, 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 / b3.5. El cast se aplica a a antes de dividir, así que la operación es 7.0 / 2 y por promoción da 3.5.
  • (int) 3.993. El cast a entero trunca la parte decimal; no redondea.
  • Math.round(3.99)4. Este sí redondea al entero más cercano.
  • tituloJava Efectivo. toUpperCase() devuelve una cadena nueva que se descarta, porque no se ha asignado. Los String son 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 + 3Total: 23. Se evalúa de izquierda a derecha: "Total: " + 2 da "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) 30044. Un byte solo llega a 127. El valor desborda y se conservan únicamente los 8 bits bajos de 300 (10010110000101100 = 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:

  1. float tarifaDiaria = 0.25; — el literal 0.25 es double; no cabe en un float sin sufijo. Solución: 0.25f (o mejor, usar double).
  2. long identificador = 100000000045; — el literal se interpreta como int y desborda su rango. Falta el sufijo L.
  3. char seccion = "J"; — las comillas dobles crean un String. Un char necesita comillas simples: 'J'.
  4. int multa = 3.75; — asignar un double a un int es una conversión estrechante y requiere cast explícito (o, mejor, declarar multa como double, que es lo correcto para dinero).
  5. DIAS_PRESTAMO = 20; — la variable es final; no puede reasignarse.
  6. System.out.println(paginas);paginas se 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

Módulo 2: Flujo de Control

Módulo 3: Programación Orientada a Objetos

Módulo 4: Programación Orientada a Objetos Avanzada

Módulo 5: Estructuras de Datos y Colecciones

Módulo 6: Manejo de Excepciones

Módulo 7: Entrada/Salida de Archivos

Módulo 8: Multihilo y Concurrencia

Módulo 9: Redes

Módulo 10: Temas Avanzados

Módulo 11: Frameworks y Librerías de Java

Módulo 12: Construcción de Aplicaciones del Mundo Real

© Copyright 2026. Todos los derechos reservados