Fundamentos de Java
Descubre los conceptos esenciales de Java, su máquina virtual (JVM), Programación Orientada a Objetos y cómo dar tus primeros pasos.
☕ ¿Qué es Java?
Definición
Java es un lenguaje de programación de propósito general, concurrente, fuertemente tipado y orientado a objetos, diseñado específicamente para tener tan pocas dependencias de implementación como fuera posible.
Su lema es "Write Once, Run Anywhere" (Escribe una vez, ejecuta donde sea).
Breve Historia
Fue desarrollado por James Gosling en Sun Microsystems (ahora parte de Oracle) y lanzado en 1995. Su sintaxis deriva de C y C++, pero tiene menos utilidades de bajo nivel (como punteros explícitos).
Ecosistema Core
Entender las siglas clave de Java:
- JDK (Java Development Kit): Herramientas para programar (compilador javac, etc).
- JRE (Java Runtime Environment): Entorno para ejecutar programas ya compilados.
- JVM (Java Virtual Machine): Máquina virtual que ejecuta el bytecode.
Ventajas Clave
- 🟠 Independencia de plataforma gracias a la JVM.
- 🟠 Fuerte gestión de memoria (Garbage Collector).
- 🟠 Multihilo (Multi-threading) integrado.
- 🟠 Gran comunidad y ecosistema inmenso (Spring, Maven, Gradle).
- 🟠 Orientado a Objetos desde la base.
📖 Fundamentos del Lenguaje
Tipos de Datos Primitivos
Java es fuertemente tipado, debes declarar el tipo de la variable. Tiene 8 tipos primitivos básicos que no son objetos.
int edad = 25;
double precio = 19.99;
boolean esValido = true;
char letra = 'A';
Condicionales y Bucles
Estructuras clásicas para controlar la lógica del programa.
if (edad >= 18) {
System.out.println("Mayor");
}
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
Funciones / Métodos
En Java, las funciones se llaman métodos porque siempre pertenecen a una clase. Deben definir qué tipo de dato retornan.
public int sumar(int a, int b) {
return a + b;
}
Arrays (Arreglos)
Estructuras de tamaño fijo que almacenan múltiples elementos del mismo tipo en memoria contigua.
int[] numeros = {10, 20, 30};
int primer = numeros[0]; // 10
int tamano = numeros.length; // 3
Manejo de Excepciones
Mecanismo para manejar errores en tiempo de ejecución asegurando que el programa no se detenga abruptamente.
try {
int x = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Error matemático");
}
Paquetes e Imports
Agrupan clases relacionadas para evitar colisiones de nombres y controlar el acceso (funcionan como carpetas).
package com.miapp.util;
import java.util.Scanner;
public class Lector { }
🔍 Explicación Detallada
1. Control de Flujo (Condicionales y Bucles)
Condicionales (if / switch): Permiten tomar decisiones. Usa if-else cuando evalúas condiciones complejas o rangos. Usa switch cuando comparas una única variable contra muchos valores exactos (ideal para menús u opciones cerradas).
int dia = 2;
switch (dia) {
case 1: System.out.println("Lunes"); break;
case 2: System.out.println("Martes"); break; // Imprime esto
default: System.out.println("Otro día");
}
Bucles (for / while): Repiten bloques de código. Usa for cuando sabes exactamente cuántas veces vas a iterar (ej: recorrer un arreglo). Usa while cuando no sabes cuántas veces se ejecutará, sino que depende de una condición (ej: leer datos hasta que el usuario escriba "salir").
// for: Se ejecuta 3 veces exactas
for (int i = 1; i <= 3; i++) {
System.out.println("Iteración: " + i);
}
// while: Se ejecuta mientras la condición sea verdadera
int contador = 5;
while (contador > 0) {
System.out.println(contador);
contador--;
}
2. Tipos de Funciones (Métodos)
Los métodos pueden clasificarse según lo que devuelven y cómo reciben parámetros. Un método con void ejecuta una acción y no devuelve nada. Si tiene un tipo (ej. int, String), debe usar la palabra return. También existen métodos static (se llaman directamente desde la clase) y métodos de instancia (necesitan un objeto creado con new).
// Método que NO retorna valor (void)
public void saludar(String nombre) {
System.out.println("Hola " + nombre);
}
// Método que SÍ retorna valor (int)
public int multiplicar(int a, int b) {
return a * b;
}
3. Cómo recorrer Arrays (Arreglos)
Para recorrer arreglos en Java, lo más común es usar un bucle for clásico (cuando necesitas acceder mediante un número de índice exacto) o un bucle for-each (más limpio y directo cuando necesitas leer todos los elementos secuencialmente sin importar su posición).
String[] frutas = {"Manzana", "Pera", "Uva"};
// Forma clásica (cuando necesitas el índice)
for (int i = 0; i < frutas.length; i++) {
System.out.println(i + ": " + frutas[i]);
}
// Forma for-each (más limpia y recomendada para solo lectura)
for (String f : frutas) {
System.out.println(f);
}
4. Excepciones y Manejo de Errores
Las excepciones ocurren cuando algo sale mal en tiempo de ejecución (ej: un archivo no existe o se divide por cero). En lugar de que el programa "explote", lo "atrapamos" con try-catch. El bloque opcional finally se usa para ejecutar código pase lo que pase (ej: para asegurar que se cierre la conexión a una base de datos).
try {
int[] nums = {1, 2, 3};
System.out.println(nums[5]); // ¡Error! El índice 5 no existe
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Te saliste del límite del arreglo: " + e.getMessage());
} finally {
System.out.println("Esto se imprime SIEMPRE, haya error o no.");
}
5. Paquetes e Importaciones
Para usar funcionalidades o clases de Java que no están en su paquete básico por defecto (java.lang), debes importarlas. Por ejemplo, para leer datos ingresados por el usuario desde el teclado usamos la clase Scanner, la cual vive dentro del paquete java.util.
import java.util.Scanner; // 1. Importar la clase externa
public class Entrada {
public static void main(String[] args) {
// 2. Crear el objeto Scanner leyendo del sistema (teclado)
Scanner sc = new Scanner(System.in);
System.out.print("Escribe tu nombre: ");
String nombre = sc.nextLine(); // Leer línea de texto
System.out.println("Hola, " + nombre);
sc.close(); // Buena práctica: liberar el recurso
}
}
6. Funciones Predeterminadas más Importantes
Java incluye miles de "funciones" (métodos) ya programadas dentro de sus librerías básicas. No necesitas programarlas desde cero, simplemente las usas. Aquí están los 4 grupos más indispensables para el día a día:
Manipulación de Textos (Clase String)
Sirven para transformar o analizar cadenas de texto (letras, palabras, frases).
String texto = "Hola Java";
texto.length(); // 9 (Devuelve la cantidad de caracteres)
texto.toUpperCase(); // "HOLA JAVA" (Convierte todo a mayúsculas)
texto.substring(0, 4); // "Hola" (Extrae un pedazo del texto)
texto.equals("java"); // false (Compara si dos textos son idénticos)
Operaciones Matemáticas (Clase Math)
Funciones listas para realizar cálculos complejos o de probabilidad sin tener que usar fórmulas manualmente.
Math.max(10, 20); // 20 (Devuelve el número mayor)
Math.sqrt(64); // 8.0 (Calcula la raíz cuadrada)
Math.pow(2, 3); // 8.0 (Potencia: 2 elevado a 3)
Math.random(); // 0.741... (Genera un número aleatorio entre 0.0 y 1.0)
Utilidades para Arreglos (Clase Arrays)
Requiere import java.util.Arrays; y te ahorra tener que hacer bucles manuales para ordenar o comparar arreglos.
int[] numeros = {5, 1, 9};
Arrays.sort(numeros); // Ordena el arreglo internamente a: {1, 5, 9}
Arrays.toString(numeros); // Convierte a texto: "[1, 5, 9]" (Muy útil para imprimir)
Arrays.equals(arreglo1, arreglo2); // Devuelve true si ambos arreglos tienen lo mismo
Consola y Sistema (Clase System)
Permite interactuar con el entorno donde corre el programa (como la terminal).
System.out.println("Texto"); // Imprime en consola y hace un salto de línea
System.out.print("Texto"); // Imprime sin salto de línea
System.currentTimeMillis(); // Devuelve el tiempo actual en milisegundos (útil para cronómetros)
System.exit(0); // Apaga y finaliza el programa entero
🧱 Programación Orientada a Objetos (POO)
Clases y Objetos
Una Clase es un molde (plantilla) que define atributos y métodos. Un Objeto es una instancia real creada a partir de esa clase usando la palabra clave new.
Encapsulamiento
Ocultar el estado interno de un objeto y requerir que toda interacción se realice mediante métodos (getters/setters). Protege los datos.
Herencia
Permite crear una nueva clase basada en una existente (padre), heredando sus atributos y métodos, fomentando la reutilización de código.
Polimorfismo
La capacidad de un objeto de tomar muchas formas. Permite tratar a objetos de clases derivadas como si fueran de su clase base, llamando métodos sobreescritos.
Abstracción
Ocultar los detalles de implementación complejos y mostrar solo las características esenciales. Se logra usando clases abstractas o interfaces.
Interfaces
Un contrato de métodos vacíos. Si una clase implementa una interfaz, debe proveer el código para esos métodos. Permite "herencia múltiple" de tipos en Java.
🔍 POO en Acción (Ejemplos)
1. Clases y Objetos
Piensa en la clase como el "plano" de una casa, y en los objetos como "casas reales" construidas a partir de ese plano. La palabra clave new reserva espacio en memoria para instanciar (crear) ese nuevo objeto.
// 1. El plano (Clase)
public class Coche {
String marca;
public void arrancar() {
System.out.println("Brum brum!");
}
}
// 2. Creando la casa real (Objeto)
Coche miAuto = new Coche();
miAuto.marca = "Toyota";
miAuto.arrancar();
2. Encapsulamiento
Ocultamos las variables directamente usando private para que nadie pueda modificarlas con valores inválidos (por ejemplo, poner un saldo negativo en un banco). Usamos métodos public (conocidos como getters y setters) como intermediarios seguros.
public class CuentaBancaria {
private double saldo; // ¡Protegido de modificaciones directas!
public void setSaldo(double cantidad) {
if (cantidad >= 0) {
this.saldo = cantidad;
} else {
System.out.println("Error: El saldo no puede ser negativo");
}
}
public double getSaldo() {
return this.saldo;
}
}
3. Herencia y Polimorfismo
La herencia (extends) permite reutilizar atributos y métodos de una clase padre. El polimorfismo (@Override) permite que una clase hija modifique cómo funciona exactamente un método del padre para adaptarlo a su propia naturaleza.
// Clase Padre
public class Animal {
public void hacerSonido() {
System.out.println("Sonido genérico...");
}
}
// Clase Hija (Aplica Herencia)
public class Perro extends Animal {
// Polimorfismo: Modifico y sobreescribo el comportamiento
@Override
public void hacerSonido() {
System.out.println("¡Guau, Guau!");
}
}
4. Abstracción e Interfaces
Una interface dicta qué debe hacerse, pero no cómo. Es como firmar un contrato. Cualquier clase que la implemente (implements) está obligada a escribir el código exacto de esos métodos vacíos.
// El contrato: Todas las bases de datos deben saber cómo conectarse
public interface ConexionDB {
void conectar();
}
// Cumpliendo el contrato obligatoriamente
public class MySQL implements ConexionDB {
@Override
public void conectar() {
System.out.println("Conectando a base de datos MySQL en el puerto 3306...");
}
}
🗂️ API de Colecciones
Estructuras de datos dinámicas en Java. A diferencia de los Arrays básicos, las colecciones pueden crecer y reducir su tamaño automáticamente.
List (Listas)
Colección ordenada que permite elementos duplicados. El elemento más común es ArrayList.
List<String> lista = new ArrayList<>();
lista.add("Java");
lista.add("Python");
String lenguaje = lista.get(0); // "Java"
Set (Conjuntos)
Colección que NO permite duplicados. HashSet es el más rápido pero no mantiene un orden garantizado.
Set<Integer> numeros = new HashSet<>();
numeros.add(1);
numeros.add(1); // Ignorado
boolean tiene = numeros.contains(1); // true
Map (Mapas / Diccionarios)
Estructura clave-valor. La clave no puede estar duplicada. HashMap es la implementación estrella.
Map<String, Integer> edades = new HashMap<>();
edades.put("Ana", 25);
int edad = edades.get("Ana"); // 25
Streams API (Java 8+)
Procesamiento funcional de colecciones. Permite filtrar, mapear y reducir datos de forma elegante.
lista.stream()
.filter(lang -> lang.startsWith("J"))
.forEach(System.out::println);
💻 Tu Primer Programa (Hello World)
Paso 1: Escribir el código
Crea un archivo llamado HolaMundo.java. Importante: El nombre del archivo debe coincidir exactamente con el nombre de la clase public.
El punto de entrada de todo programa Java es el método public static void main(String[] args).
public class HolaMundo {
public static void main(String[] args) {
// Imprime un mensaje en la consola
System.out.println("¡Hola, Mundo desde Java!");
}
}
Paso 2: Compilar y Ejecutar en Terminal
Compilar transforma tu código humano (.java) en bytecode (.class) que la JVM entiende, usando el comando javac.
Ejecutar arranca la JVM para correr tu archivo .class generado, usando el comando java (sin la extensión).
# 1. Compilar
javac HolaMundo.java
# (Esto generará un archivo HolaMundo.class)
# 2. Ejecutar
java HolaMundo
📋 Copiar