Semestre 02, 2026
int nota1 = 80;
int nota2 = 75;
int nota3 = 90;
int nota4 = 85;
int nota5 = 70;
int[] notas = {80, 75, 90, 85, 70};
int[] notas = {80, 75, 90, 85, 70};
int[] numeros;
Anuncia que existe una variable capaz de apuntar a un arreglo de enteros. Todavía no hay espacio reservado.
numeros = new int[5];
La palabra new aparta memoria para cinco enteros y entrega la referencia a ese bloque.
int[] numeros = new int[5];
int[] notas = {80, 75, 90, 85, 70};
int[] numeros;
numeros = {1, 2, 3};
Fuera de la declaración, las llaves solas no le dicen a Java de qué tipo es el arreglo que se está construyendo.
int[] numeros;
numeros = new int[] {1, 2, 3};
Al escribir new int[] delante, el tipo queda explícito y la asignación funciona en cualquier punto del programa.
int[] numeros = new int[5];
System.out.println(numeros[0]);
Crear un arreglo no lo deja vacío. Java lo llena con el valor por defecto del tipo, así que se puede leer desde el primer momento.
tipo valor por defecto
int, short, long, byte 0
double, float 0.0
boolean false
char ' '
cualquier objeto (String, Perro, …) null
Un arreglo de objetos arranca lleno de nulos. Esa fila es todo el puente hacia la segunda mitad de la lección.
notas[2] = 90;
System.out.println(notas[2]);
System.out.println(notas.length);
notas[notas.length - 1]
int[] notas = new int[5];
notas[5] = 100;
El índice puede ser cualquier expresión, y su valor solo se conoce al ejecutar. La verificación ocurre en ese momento.
for (int i = 0; i < notas.length; i++) {
System.out.println(notas[i]);
}
for (int nota : notas) {
System.out.println(nota);
}
Para cada nota dentro de notas. La variable nota es una copia del elemento, así que asignarle un valor no toca el arreglo.
for for-each
da el índice sí no
permite escribir sí no
recorre al revés sí no
legibilidad media alta
Un compañero escribe \(i \le notas.length\) en la condición del ciclo. El programa compila sin problema. ¿Qué va a pasar al ejecutarlo?
Las primeras cinco vueltas funcionan. En la sexta el índice vale 5, esa casilla no existe y el programa se detiene con un error de índice fuera de rango.
Scanner teclado = new Scanner(System.in);
int[] notas = new int[5];
for (int i = 0; i < notas.length; i++) {
System.out.print("Nota " + (i + 1) + ": ");
notas[i] = teclado.nextInt();
}
int suma = 0;
for (int nota : notas) {
suma += nota;
}
double promedio = (double) suma / notas.length;
System.out.println(promedio);
400 dividido entre 5 da 80.0
int suma = 0;
for (int nota : notas) {
suma += nota;
}
double promedio = (double) suma / notas.length;
System.out.println(promedio);
El acumulador nace en cero, fuera del ciclo. Si se declarara adentro, volvería a valer cero en cada vuelta y al final quedaría solo la última nota.
int suma = 0;
for (int nota : notas) {
suma += nota;
}
double promedio = (double) suma / notas.length;
System.out.println(promedio);
Solo hace falta leer cada elemento, nunca su posición, así que el for-each es la herramienta correcta. Cada vuelta agrega una nota al total.
int suma = 0;
for (int nota : notas) {
suma += nota;
}
double promedio = (double) suma / notas.length;
System.out.println(promedio);
La conversión es obligatoria. Entre dos enteros Java hace división entera y descarta los decimales, así que un promedio de 80.4 saldría como 80.
int suma = 0;
for (int nota : notas) {
suma += nota;
}
double promedio = (double) suma / notas.length;
System.out.println(promedio);
Con las notas del ejemplo la salida es 80.0. El punto cero confirma que el resultado es un double y que la conversión funcionó.
int[] edades = {18, 20, 22};
double[] precios = {10.5, 20.7, 15.2};
boolean[] estados = {true, false, true};
String[] nombres = {"Ana", "Luis", "Leo"};
Cada arreglo almacena elementos de un solo tipo, y ese tipo se fija al declararlo.
public void imprimir(int[] arreglo) {
for (int valor : arreglo) {
System.out.println(valor);
}
}
Al pasar un arreglo a un método no se copia su contenido: se pasa la referencia. El parámetro y la variable original son un alias del mismo arreglo.
public void modificar(int[] datos) {
datos[0] = 999;
}
int[] valores = {1, 2, 3};
modificar(valores);
System.out.println(valores[0]);
import java.util.Arrays;
int[] original = {1, 2, 3, 4};
int[] copia = Arrays.copyOf(original, original.length);
La copia vive en su propio espacio de memoria. Cambiarla no toca al original, y por eso sirve para pasarle datos a un método sin arriesgarlos.
Antes: variables independientes
Perro perro1 = new Perro("Max", 3);
Perro perro2 = new Perro("Rocky", 5);
Perro perro3 = new Perro("Luna", 2);
Ahora: un arreglo unificado
Perro[] perros = new Perro[3];
Perro[] perros = new Perro[3];
Crear el arreglo reserva tres casillas capaces de apuntar a un Perro, pero no construye ningún Perro. Hay que instanciarlos uno por uno.
perros[0] = new Perro("Max", 3);
perros[1] = new Perro("Rocky", 5);
perros[2] = new Perro("Luna", 2);
Perro[] perros = new Perro[3];
String[] nombres = {"Max", "Rocky", "Luna"};
int[] edades = {3, 5, 2};
for (int i = 0; i < perros.length; i++) {
perros[i] = new Perro(nombres[i], edades[i]);
}
Perro[] perros = new Perro[3];
String[] nombres = {"Max", "Rocky", "Luna"};
int[] edades = {3, 5, 2};
for (int i = 0; i < perros.length; i++) {
perros[i] = new Perro(nombres[i], edades[i]);
}
Quedan tres casillas listas y las tres apuntan a nada. Este es el punto en el que el arreglo existe pero todavía no sirve.
Perro[] perros = new Perro[3];
String[] nombres = {"Max", "Rocky", "Luna"};
int[] edades = {3, 5, 2};
for (int i = 0; i < perros.length; i++) {
perros[i] = new Perro(nombres[i], edades[i]);
}
Dos arreglos de primitivos guardan los datos crudos. Comparten el índice con el arreglo de perros, así que la posición i de los tres se refiere al mismo animal.
Perro[] perros = new Perro[3];
String[] nombres = {"Max", "Rocky", "Luna"};
int[] edades = {3, 5, 2};
for (int i = 0; i < perros.length; i++) {
perros[i] = new Perro(nombres[i], edades[i]);
}
Aquí sí hace falta el índice, porque se va a escribir en el arreglo. El for-each no serviría para esta parte.
Perro[] perros = new Perro[3];
String[] nombres = {"Max", "Rocky", "Luna"};
int[] edades = {3, 5, 2};
for (int i = 0; i < perros.length; i++) {
perros[i] = new Perro(nombres[i], edades[i]);
}
Cada vuelta construye un objeto nuevo en el heap y guarda su referencia en la casilla i. Al terminar el ciclo ya no queda ningún nulo.
1. encuentra la referencia guardada en esa posición
2. ejecuta la acción sobre el objeto apuntado
perros[0].ladrar();
System.out.println(perros[1].getNombre());
perros[2].setEdad(3);
Perro primero = perros[0];
primero.ladrar();
La variable primero y la casilla perros[0] apuntan al mismo lugar. Lo que se cambie con una se ve con la otra.
Ciclo for tradicional
for (int i = 0; i < perros.length; i++) {
System.out.println(perros[i].getNombre());
System.out.println(perros[i].getEdad());
}
Acceso mediante índice explícito.
Ciclo for-each
for (Perro perro : perros) {
perro.mostrarInformacion();
}
La referencia se extrae directo a una variable temporal.
Los dos actúan como puente hacia el mismo objeto en memoria. Ninguno copia al perro.
for (Perro perro : perros) {
perro.setEdad(1);
}
La copia es de la referencia, y esa referencia lleva al mismo objeto que guarda la casilla.
for (Perro perro : perros) {
perro = new Perro("Otro", 0);
}
Aquí solo se cambia hacia dónde apunta la variable temporal. La casilla del arreglo sigue apuntando al perro original.
Perro[] perros = new Perro[3];
perros[0].ladrar();
for (int i = 0; i < perros.length; i++) {
perros[i] = new Perro("Sin nombre", 0);
}
Se separa la fase de construcción de la fase de uso. Es la opción normal.
for (Perro perro : perros) {
if (perro != null) {
perro.ladrar();
}
}
Sirve cuando el arreglo puede quedar parcialmente lleno a propósito.
La casilla no existe. El índice quedó fuera del rango que va de cero a length menos uno.
La casilla existe pero está vacía. Se pidió un método a una referencia que no apunta a ningún objeto.
Scanner teclado = new Scanner(System.in);
Perro[] perros = new Perro[3];
for (int i = 0; i < perros.length; i++) {
System.out.print("Nombre del perro " + (i + 1) + ": ");
String nombre = teclado.nextLine();
System.out.print("Edad de " + nombre + ": ");
int edad = teclado.nextInt();
teclado.nextLine();
perros[i] = new Perro(nombre, edad);
}
for (Perro perro : perros) {
perro.mostrarInformacion();
}
Scanner teclado = new Scanner(System.in);
Perro[] perros = new Perro[3];
for (int i = 0; i < perros.length; i++) {
System.out.print("Nombre del perro " + (i + 1) + ": ");
String nombre = teclado.nextLine();
System.out.print("Edad de " + nombre + ": ");
int edad = teclado.nextInt();
teclado.nextLine();
perros[i] = new Perro(nombre, edad);
}
for (Perro perro : perros) {
perro.mostrarInformacion();
}
El arreglo se crea vacío de objetos. Desde esta línea hasta que termine el primer ciclo, tocar cualquier casilla haría reventar el programa.
Scanner teclado = new Scanner(System.in);
Perro[] perros = new Perro[3];
for (int i = 0; i < perros.length; i++) {
System.out.print("Nombre del perro " + (i + 1) + ": ");
String nombre = teclado.nextLine();
System.out.print("Edad de " + nombre + ": ");
int edad = teclado.nextInt();
teclado.nextLine();
perros[i] = new Perro(nombre, edad);
}
for (Perro perro : perros) {
perro.mostrarInformacion();
}
Se pide el nombre mostrando i más uno, para que el usuario vea perro 1 y no perro 0. El dato se guarda en una variable local antes de construir nada.
Scanner teclado = new Scanner(System.in);
Perro[] perros = new Perro[3];
for (int i = 0; i < perros.length; i++) {
System.out.print("Nombre del perro " + (i + 1) + ": ");
String nombre = teclado.nextLine();
System.out.print("Edad de " + nombre + ": ");
int edad = teclado.nextInt();
teclado.nextLine();
perros[i] = new Perro(nombre, edad);
}
for (Perro perro : perros) {
perro.mostrarInformacion();
}
La llamada suelta a nextLine consume el salto de línea que nextInt deja pendiente. Sin ella, la siguiente lectura de nombre saldría vacía.
Scanner teclado = new Scanner(System.in);
Perro[] perros = new Perro[3];
for (int i = 0; i < perros.length; i++) {
System.out.print("Nombre del perro " + (i + 1) + ": ");
String nombre = teclado.nextLine();
System.out.print("Edad de " + nombre + ": ");
int edad = teclado.nextInt();
teclado.nextLine();
perros[i] = new Perro(nombre, edad);
}
for (Perro perro : perros) {
perro.mostrarInformacion();
}
Aquí desaparece el nulo de la casilla i. El objeto se construye en el heap y la casilla pasa a guardar su dirección.
Scanner teclado = new Scanner(System.in);
Perro[] perros = new Perro[3];
for (int i = 0; i < perros.length; i++) {
System.out.print("Nombre del perro " + (i + 1) + ": ");
String nombre = teclado.nextLine();
System.out.print("Edad de " + nombre + ": ");
int edad = teclado.nextInt();
teclado.nextLine();
perros[i] = new Perro(nombre, edad);
}
for (Perro perro : perros) {
perro.mostrarInformacion();
}
El segundo ciclo solo lee, así que el for-each es suficiente. Separar el llenado del recorrido es lo que garantiza que aquí ya no haya nulos.
public double promedio(int... numeros) {
int suma = 0;
for (int n : numeros) {
suma += n;
}
return (double) suma / numeros.length;
}
promedio(10, 20, 30);
promedio(1, 2, 3, 4, 5, 6);
La sintaxis con puntos suspensivos deja que el método reciba una cantidad distinta de argumentos en cada llamada.
int[][] matriz = new int[3][4];
matriz[0][0] = 10;
System.out.println(matriz[0][0]);
Cada casilla de la primera dimensión guarda la referencia a otro arreglo. En álgebra lineal a esta estructura se le llama matriz.
arreglo de primitivos arreglo de objetos
creación int[] n = new int[5]; Perro[] p = new Perro[3];
cada casilla guarda el valor una referencia
estado inicial 0, 0.0, false null
listo tras new sí no, falta instanciar
acceso n[0] p[0].metodo()
error típico índice fuera de rango referencia nula
El tamaño es fijo y se consulta con length, el primer índice es cero y el último es length menos uno, y los dos funcionan igual con for y con for-each.