Java Básico
Java Básico
Historia
Línea de tiempo resumida
Java 5 (2004): Generics, anotaciones, autoboxing/unboxing, enums, varargs y for-each.
Java 6 (2006): Mejoras de rendimiento, scripting (JSR-223), API de compilación y actualizaciones en Swing.
Java 7 (2011): try-with-resources, multi-catch, diamond operator (<>), mejoras en NIO.2 y soporte para literales numéricos con guiones bajos.
Java 8 (2014): Lambdas, Streams, Optional, nueva API de fecha y hora (java.time) y métodos default/static en interfaces.
Java 9 (2017): Sistema de módulos, JShell, mejoras en colecciones y API.
Java 10 (2018): Inferencia de tipos con var (variables locales).
Java 11 (2018, LTS): Nuevo cliente HTTP, mejoras en Strings y colecciones, y actualizaciones de rendimiento.
Java 17 (2021, LTS): Sealed classes, mejoras de pattern matching y múltiples optimizaciones.
Java 21 (2023, LTS): Virtual threads, record patterns y mejoras modernas del lenguaje y la JVM.
Principales cosas a saber de Java
Conceptos base del lenguaje
- Compilado a bytecode: El compilador transforma
.javaa bytecode (archivos.class) para que la JVM lo ejecute. - Orientado a objetos (POO): Clases y objetos como unidad central.
- Encapsulación: Control de acceso a datos mediante modificadores y métodos.
- Herencia: Reutilización y extensión de comportamiento.
- Polimorfismo: Un mismo método puede comportarse distinto según el tipo del objeto.
- Abstracción: Ocultar detalles y exponer lo esencial con interfaces y clases abstractas.
- Fuertemente tipado: Cada variable tiene un tipo definido, y los cambios requieren conversión explícita.
Plataforma Java (JVM / JRE / JDK)
- JVM (Java Virtual Machine): Ejecuta el bytecode. Carga clases, verifica, interpreta/compila (JIT) y gestiona memoria (GC).
- JRE (Java Runtime Environment): Runtime para ejecutar apps (JVM + librerías). Hoy se usa menos como “descarga aparte”.
- JDK (Java Development Kit): Para desarrollar. Incluye
javacy herramientas (por ejemplojavadoc,jlink) + runtime. - JIT (Just-In-Time): Compila en ejecución para acelerar código “caliente”.
- GC (Garbage Collector): Recolección automática de objetos no referenciados.
Estandarización y evolución
- JSR (Java Specification Request): Especificaciones del Java Community Process (JCP).
- JEP (JDK Enhancement Proposal): Propuestas de mejoras del JDK.
OpenJDK y distribuciones
- ¿Java es open source?: La implementación más común hoy se basa en OpenJDK.
- ¿Qué es OpenJDK?: Implementación open source de referencia (JDK + JVM + librerías).
- ¿Por qué varias empresas tienen su versión de JDK?: Builds de OpenJDK con soporte, parches y ciclos de release. Ejemplos: Adoptium, Amazon Corretto, Azul Zulu, Oracle JDK.
Build tools y dependencias
- Maven: Build y dependencias con
pom.xml(convención, repositorios, lifecycle). - Gradle: Build con DSL (Groovy/Kotlin), flexible y muy usado en proyectos modernos.
- Repositorios: Maven Central y repos privados (Nexus/Artifactory).
Instalación de Java
- Recomendación: Linux/Mac o Windows con WSL.
- WSL (Windows Subsystem for Linux):
- SDKMAN!: gestor de versiones para herramientas del ecosistema JVM.
- Maven con SDKMAN (ejemplo):
sdk install maven 3.9.12
Primeros programas

Paquetes (package)
¿Qué es un paquete?
- Es una forma de organizar las clases.
- Evita conflictos de nombres.
- Es equivalente a carpetas en el sistema de archivos.
Estructura típica:
src/
com/
example/
Main.java
Buenas prácticas:
- Siempre usar paquetes.
- Convención:
com.empresa.proyecto. - Todo en minúsculas.
- Sin espacios ni caracteres especiales.
Imports
¿Qué es un import?

Si no utilizamos imports, tendríamos que invocar las clases predefinidas de Java o nuestras propias clases con el nombre completo cada vez:

Con imports:

- El import no copia código. Solo le indica al compilador dónde encontrar clases.
Clases
¿Qué es una clase?

Una clase se puede ver como:
- Una plantilla.
- Un molde.
- La unidad básica de organización en Java.
Todo en Java vive dentro de una clase.
Palabras reservadas (keywords)
Java tiene palabras que no pueden usarse como nombres de variables o clases. Son instrucciones especiales que el compilador reconoce.
Algunos ejemplos:
public,private,protectedclass,interface,enumstatic,final,void,newint,double,boolean,charif,else,switch,case,for,while,returnpackage,importyield(enswitchmodernos)
Punto de entrada del programa (main)

Leyendo el código (de forma general):
public: accesible desde cualquier lugar.static: pertenece a la clase, no a un objeto.void: el método no retorna valor.String[] args: arreglo de strings con argumentos de la línea de comandos.
¿Cómo sabe la JVM dónde empezar?
- Cuando ejecuta
java Main, la JVM busca la claseMainy el métodopublic static void main(String[] args). - Si no lo encuentra, verás un error indicando que falta el método
main.
Tipos de datos primitivos
- Enteros:
byte,short,int,long - Decimales:
float,double - Booleano:
boolean - Carácter:
char
| Tipo | Tamaño | Rango aproximado | Ejemplo |
|---|---|---|---|
| byte | 8 bits | -128 a 127 | byte b = 10; |
| short | 16 bits | -32,768 a 32,767 | short s = 3000; |
| int | 32 bits | -2.1B a 2.1B | int n = 42; |
| long | 64 bits | Muy grande | long l = 9_000_000_000L; |
| float | 32 bits | Precisión ~7 dígitos | float f = 3.14f; |
| double | 64 bits | Precisión ~15-16 dígitos | double d = 3.14159; |
| boolean | Depende de la JVM | true o false | boolean ok = true; |
| char | 16 bits | 0 a 65,535 (UTF-16) | char c = 'A'; |
Basicos
Variables y operadores
- Declaración e inicialización:
int edad = 20;,var nombre = "Alejandro";. - Scope (alcance): dónde “vive” una variable y desde qué partes del código se puede usar.
- 1) Variables locales (dentro de un método o bloque)
-
Solo existen dentro del bloque
{ ... }donde se declaran. -
Se crean al entrar al bloque y “mueren” al salir.
-
Ejemplo (bloque
if):public class Demo { public static void main(String[] args) { int x = 10; // local de main if (x > 5) { int y = 20; // local del bloque if System.out.println(x + y); // OK } // System.out.println(y); // ERROR: y no existe aquí } } -
Ejemplo (for):
for (int i = 0; i < 3; i++) { System.out.println(i); } // System.out.println(i); // ERROR: i era del for -
Nota:
var(Java 10+) solo se puede usar en variables locales:var nombre = "Alejandro"; // OK (local) // var edad; // ERROR: debe inicializarse
-
- 2) Parámetros de método (también son locales al método)
-
Solo se pueden usar dentro del método.
-
Ejemplo:
static int sumar(int a, int b) { return a + b; // a y b no existen fuera de sumar }
-
- 3) Campos de instancia (variables de clase, pero NO
static)-
Pertenecen a cada objeto.
-
Se acceden desde cualquier método de la clase (según el modificador:
private,public, etc.). -
Tienen valor por defecto si no se inicializan (por ejemplo
0,false,null). -
Ejemplo:
public class Cuenta { private int saldo; // campo de instancia public void depositar(int monto) { saldo += monto; // usa el campo } public int verSaldo() { return saldo; } }
-
- 4) Campos estáticos (de clase,
static)-
Pertenecen a la clase, no a un objeto.
-
Hay un solo valor compartido.
-
Ejemplo:
public class Contador { static int total = 0; // compartido int id; // por objeto public Contador() { total++; id = total; } }
-
- 5) Variables “sombreadas” (shadowing): local vs campo
-
Si una variable local tiene el mismo nombre que un campo, la local “tapa” al campo.
-
Se usa
this.para referirse al campo. -
Ejemplo:
public class Persona { private String nombre; public void setNombre(String nombre) { this.nombre = nombre; // this.nombre = campo, nombre = parámetro } }
-
- Tip rápido: si se necesita que una variable se recuerde entre llamadas a métodos, normalmente debe ser un campo (instancia o
static). Si solo sirve para un cálculo puntual, debe ser local.
- 1) Variables locales (dentro de un método o bloque)
- Conversión de tipos (casting): implícito y explícito
-
Objetivo: pasar un valor de un tipo a otro (por ejemplo de
intadouble). -
Regla general:
- Widening (implícita / segura): de un tipo “más pequeño” a uno “más grande” (no se pierde información).
- Narrowing (explícita / con riesgo): de un tipo “más grande” a uno “más pequeño” (puede haber pérdida de información).
-
Casting implícito (widening): el compilador lo hace automáticamente.
int n = 10; double d = n; // 10.0 long l = n; // 10 float f = l; // 10.0f -
Casting explícito (narrowing): debes indicar el tipo con
(tipo).double d = 9.99; int n = (int) d; // 9 (pierde decimales) int x = 130; byte b = (byte) x; // -126 (overflow) -
Cuidado con:
-
Pérdida de decimales:
double/float -> int/longtrunca, no redondea. -
Overflow/underflow: al convertir a
byte/short/intpuede “dar la vuelta”. -
chary números:chares numérico (UTF-16), se puede convertir aint.char c = 'A'; int code = c; // 65
-
-
Tabla rápida de conversiones (primitivos numéricos):
De A byte short char int long float double byte — Implícita Explícita Implícita Implícita Implícita Implícita short Explícita — Explícita Implícita Implícita Implícita Implícita char Explícita Explícita — Implícita Implícita Implícita Implícita int Explícita Explícita Explícita — Implícita Implícita Implícita long Explícita Explícita Explícita Explícita — Implícita Implícita float Explícita Explícita Explícita Explícita Explícita — Implícita double Explícita Explícita Explícita Explícita Explícita Explícita — -
Extra (autoboxing/unboxing): entre primitivos y wrappers.
Integer a = 10; // autoboxing (int -> Integer) int b = a; // unboxing (Integer -> int)
-
- Operadores: aritméticos (
+ - * / %), comparación (== != < > <= >=), lógicos (&& || !), asignación (= +=), ternario (cond ? a : b).
Control de flujo (if / switch / loops)
El control de flujo define qué se ejecuta, cuándo, y cuántas veces.
- Selección:
ifyswitch - Iteración:
for,while,do-while,for-each - Control:
break,continue,return
if / else if / else
- Se usa cuando la decisión depende de condiciones booleanas.
- Puedes encadenar varias condiciones con
else if. - Consejo: si hay muchos
else if, a veces unswitcho una estructura de datos (por ejemploMap) es más clara.
int edad = 20;
if (edad < 18) {
System.out.println("Menor de edad");
} else if (edad < 65) {
System.out.println("Adulto");
} else {
System.out.println("Adulto mayor");
}Detalles útiles:
- Usar llaves
{ }siempre. Evita errores al agregar líneas después. &&y||son cortocircuito: si ya se sabe el resultado, no evalúa lo demás.
if (user != null && user.isActive()) {
// isActive() solo se evalúa si user != null
}switch (clásico)
- Se usa cuando se elige entre casos discretos (valores específicos).
- Funciona con
int,char,String,enum(y más tipos según versión). - En el
switchclásico es común usarbreakpara evitar el fall-through
int dia = 3;
switch (dia) {
case 1:
System.out.println("Lunes");
break;
case 2:
System.out.println("Martes");
break;
case 3:
System.out.println("Miércoles");
break;
default:
System.out.println("Día inválido");
}switch moderno (Java 14+)
- Usa
->y no necesitabreaken cada caso. - Puede ser expresión, es decir, puede devolver un valor.
- Para devolver un valor en un bloque con varias líneas, se usa
yield.
String tipo = "A";
String mensaje = switch (tipo) {
case "A" -> "Excelente";
case "B" -> "Bien";
case "C" -> {
String base = "Regular";
yield base + " (puede mejorar)";
}
default -> "Desconocido";
};
System.out.println(mensaje);Bucles
for (clásico): cuando sabes cuántas iteraciones necesitas.
for (int i = 0; i < 5; i++) {
System.out.println(i);
}while: cuando repites mientras se cumpla una condición (no sabes el número exacto).
int n = 3;
while (n > 0) {
System.out.println(n);
n--;
}do-while: igual que while, pero garantiza al menos una ejecución.
int intento = 0;
do {
intento++;
System.out.println("Intento " + intento);
} while (intento < 3);for-each: para recorrer colecciones o arrays de forma simple.
int[] nums = {1, 2, 3};
for (int x : nums) {
System.out.println(x);
}break y continue
break: sale del bucle (o delswitch).continue: salta a la siguiente iteración del bucle.
for (int i = 1; i <= 10; i++) {
if (i == 5) {
continue; // se salta el 5
}
if (i == 9) {
break; // termina en 8
}
System.out.println(i);
}Métodos
Un método es una unidad de código reutilizable que recibe datos (parámetros), hace una tarea, y opcionalmente retorna un resultado.
Modificadores y palabras clave muy comunes (static, final, etc.)
static: pertenece a la clase, no al objeto.- En campos: un solo valor compartido por todas las instancias.
- En métodos: se puede llamar sin crear un objeto.
final: “no se puede cambiar” (según el contexto).- Variable/atributo final: no se puede reasignar.
- Método final: no se puede sobreescribir.
- Clase final: no se puede heredar.
- Modificadores de acceso:
public: accesible desde cualquier lugar.protected: accesible desde el paquete y desde subclases.- (sin keyword) (package-private): accesible solo dentro del paquete.
private: accesible solo dentro de la clase.
this: referencia al objeto actual.super: referencia al “padre” (clase base), útil para llamar constructor o métodos del padre.null: ausencia de referencia. Acceder a miembros sobrenullproduceNullPointerException.
Firma de un método
La firma incluye:
- Nombre del método
- Lista de parámetros (tipo + orden)
- El tipo de retorno no distingue una sobrecarga por sí solo, pero sí hace parte de la declaración.
static int sumar(int a, int b) {
return a + b;
}return y void
- Si el retorno no es
void, se debe retornar un valor en todos los caminos posibles. return;también sirve para salir temprano en métodosvoid.
static void imprimirSiPositivo(int n) {
if (n <= 0) {
return;
}
System.out.println(n);
}Parámetros por valor (pass-by-value)
En Java siempre se pasa por valor:
- Para primitivos, se copia el valor.
- Para objetos, se copia la referencia (la dirección), no el objeto.
Esto significa que:
- Puedes modificar el estado interno del objeto recibido.
- No puedes “reemplazar” el objeto del llamador reasignando el parámetro.
static void cambiarNumero(int x) {
x = 99; // no afecta al original
}
static void cambiarNombre(StringBuilder sb) {
sb.append("!" ); // sí afecta al mismo objeto
sb = new StringBuilder("nuevo"); // no cambia la referencia afuera
}Sobrecarga (overloading)
Puedes tener varios métodos con el mismo nombre si cambian los parámetros (cantidad o tipos).
static int max(int a, int b) { return a > b ? a : b; }
static double max(double a, double b) { return a > b ? a : b; }Buenas prácticas
- Nombres claros:
calcularTotal,validarEmail. - Métodos pequeños, una responsabilidad.
- Evita demasiados parámetros. Si hay muchos, considera un objeto de configuración.
Arrays y Strings
Arrays
- Tamaño fijo.
- Índices desde
0hastalength - 1.
int[] a = new int[3];
a[0] = 10;
a[1] = 20;
a[2] = 30;
System.out.println(a.length); // 3Iteración:
for (int i = 0; i < a.length; i++) {
System.out.println("a[" + i + "] = " + a[i]);
}
for (int x : a) {
System.out.println(x);
}String
- Es inmutable: cualquier “cambio” crea un nuevo
String. - Concatenar con
+está bien para pocas uniones.
String s = "Hola";
s = s + " mundo"; // crea un nuevo StringStringBuilder (concatenación eficiente)
En bucles o muchas concatenaciones, usa StringBuilder.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 3; i++) {
sb.append(i).append(",");
}
String out = sb.toString();Comparación: equals() vs ==
==compara referencias en objetos (si es el mismo objeto).equals()compara contenido (según la implementación).
String a1 = new String("hola");
String a2 = new String("hola");
System.out.println(a1 == a2); // false
System.out.println(a1.equals(a2)); // trueTip: para evitar NullPointerException:
String rol = null;
if ("ADMIN".equals(rol)) {
// seguro incluso si rol es null
}