Semana 1 — De C a Java · Objetos como estado y comportamiento
Objetivos
- Conocer cómo funciona el curso, el proyecto Bodega y el entorno de trabajo.
- Explicar qué cambia al pasar de C a Java: bytecode, JVM y JIT; tipos primitivos y referencias;
Stringy arreglos; garbage collector. - Compilar y ejecutar programas con
javac,javayjshell, incluidos los archivos fuente compactos de Java 25. - Explicar por qué conviene juntar estado y comportamiento en objetos, y escribir una primera clase con campos, constructor y métodos.
- Dejar listo el entorno de trabajo para todo el semestre.
Apuntes de la semana: notes/week-01.md · Código: code/week-01
Sesión A — Presentación del curso · De C a Java
Lecturas (Eck, Introduction to Programming Using Java, versión 9):
- Prefacio (opcional)
- Sec. 1.3 The Java Virtual Machine
- Sec. 2.1 The Basic Java Application
- Sec. 2.2 Variables and the Primitive Types
- Sec. 2.3 Strings, Classes, Objects, and Subroutines (2.3.1 a 2.3.3)
- Sec. 2.6 Programming Environments: 2.6.1 Getting a JDK, 2.6.2 Command Line Environment y 2.6.6 About jshell
- Sec. 3.8 Introduction to Arrays (3.8.1 y 3.8.2, opcional si ya dominan los arreglos en C)
El libro cubre Java 17 y usa su propia clase TextIO para la entrada y la
salida; nosotros usamos IO y archivos fuente compactos, que son de Java 25.
Para eso:
- JEP 512: Compact Source Files and Instance Main Methods (secciones Summary y Motivation)
- dev.java: Getting Started with Java y JShell, the Java Shell Tool
Temas:
- Programa, proyecto Bodega (P0–P5), exámenes, políticas y entorno (SYLLABUS).
- Compilar a bytecode vs. a código máquina. La JVM: intérprete y compilador JIT. “Escribir una vez, ejecutar en cualquier parte”.
- Las herramientas del JDK:
javac,java(también con un archivo fuente directamente),jshell,javap. - Archivos fuente compactos:
void main()eIO.println. - Tipos primitivos de tamaño fijo;
booleanno es un número. Tipos de referencia:String(inmutable, con métodos) y arreglos (conlengthy verificación de índices). - Sin punteros ni
free:newy el garbage collector.
Sesión B — Objetos como estado + comportamiento
Lecturas:
- Sec. 1.5 Objects and Object-oriented Programming
- Sec. 5.1 Objects, Instance Methods, and Instance Variables (5.1.1 y 5.1.2)
- Sec. 5.2 Constructors and Object Initialization (5.2.1 a 5.2.3)
Temas:
- El problema de los datos sueltos: un
structy funciones aparte; nada protege las reglas de los datos. - Objeto = estado (campos) + comportamiento (métodos). Mensaje y método.
- Clase e instancia. Una primera clase:
TransitCard, con campos, constructor y métodos. newpaso a paso: reservar, construir, devolver la referencia.- Cada objeto tiene su propio estado y su propia identidad (
==entre referencias).
Laboratorio — Entorno de trabajo
Guía: labs/README.md
- Instalar Docker y levantar el contenedor del curso (
env/run.sh). Comprobar la versión conjava -version. jshell: evaluar expresiones con enteros,double,Stringy arreglos; provocar unArrayIndexOutOfBoundsExceptiony leer el mensaje.- Escribir un archivo compacto propio y ejecutarlo de las dos maneras:
java Archivo.java, yjavac -d buildseguido dejava -cp build. - En
code/week-01:make,make testymake clean. Leer elMakefile(compila el código Java conjavacy la versión en C de la tarjeta congcc) y la salida de JUnit. - Leer el enunciado de P0 y preparar su carpeta de trabajo dentro del contenedor.
Entregas
- P0 publicado: Calentamiento: programas cortos en Java y la clase
Product(producto) como primera clase del proyecto Bodega (proyectos). Entrega en semana 3.
Preguntas de repaso
- ¿Qué hay dentro de un archivo
.class? ¿Por qué el mismo.classcorre en Linux, Windows y macOS, y un ejecutable de C no? - Si la JVM interpreta bytecode, ¿por qué un programa Java que corre varios segundos puede ser casi tan rápido como uno en C? ¿Qué significa mixed mode en
java -version? - ¿Qué guarda una variable
inty qué guarda una variableString? ¿En qué se parece una referencia a un puntero de C y en qué no? - En C,
if (n)compila connentero. ¿Qué pasa en Java y por qué el lenguaje lo decidió así? - ¿Qué tres cosas hace
new TransitCard("A-001"), y en qué orden? - Dos tarjetas creadas con
newtienen el mismo código y el mismo saldo. ¿Esa == bverdadero o falso? ¿Por qué? - Den un ejemplo, distinto de la tarjeta, en el que tener los datos sueltos y las funciones aparte haga difícil encontrar un error.
Código de la semana
Compilar y probar dentro del contenedor del curso con make y make test.
Ejemplos (6)Pruebas (1)Compilación (1)
Ejemplos
Los programas que usan los apuntes y la clase.
// Usa la clase TransitCard: crear objetos con new y enviarles mensajes.
void main() {
TransitCard alice = new TransitCard("A-001");
TransitCard bob = new TransitCard("A-002");
alice.recharge(1000);
boolean paid = alice.pay(250);
IO.println(alice.id() + ": pagó " + paid + ", saldo " + alice.balance());
// bob tiene su propio estado: el pasaje de alice no lo toca.
paid = bob.pay(250);
IO.println(bob.id() + ": pagó " + paid + ", saldo " + bob.balance());
// Identidad: dos new crean dos objetos distintos.
TransitCard same = alice;
IO.println("alice == bob: " + (alice == bob));
IO.println("alice == same: " + (alice == same));
}// Lo que cambia al pasar de C a Java: tipos con tamaño fijo, String como
// objeto y arreglos que conocen su longitud.
void main() {
// Tipos primitivos: el tamaño no depende de la máquina.
int n = 2_147_483_647; // int siempre tiene 32 bits
long big = n + 1L; // long siempre tiene 64 bits
IO.println("n + 1 como int: " + (n + 1));
IO.println("n + 1 como long: " + big);
// boolean no es un número: if (1) no compila en Java.
boolean ready = n > 0;
IO.println("ready = " + ready);
// String es un objeto con métodos, no un char* terminado en '\0'.
String name = "Ada Lovelace";
IO.println(name.length() + " caracteres, en mayúsculas: " + name.toUpperCase());
// Un arreglo es un objeto que sabe cuántos elementos tiene.
int[] marks = new int[4]; // los elementos empiezan en 0
marks[0] = 15;
marks[3] = 18;
int sum = 0;
for (int i = 0; i < marks.length; i++) {
sum += marks[i];
}
IO.println("marks.length = " + marks.length + ", suma = " + sum);
}// El programa más corto en Java 25: un archivo fuente compacto.
// Se ejecuta directamente con: java Hello.java
void main() {
IO.println("Hola, Java");
}// La tarjeta de transporte escrita "al estilo C": un registro de datos
// sueltos y funciones aparte que reciben ese registro como parámetro.
class CardData {
String id;
int balance; // saldo en céntimos
}
void recharge(CardData card, int amount) {
card.balance += amount;
}
boolean pay(CardData card, int fare) {
if (card.balance < fare) {
return false;
}
card.balance -= fare;
return true;
}
void main() {
CardData card = new CardData();
card.id = "A-001";
recharge(card, 1000);
pay(card, 250);
IO.println(card.id + ": " + card.balance + " céntimos");
// Nada impide que cualquier parte del programa rompa los datos.
card.balance = -500;
IO.println(card.id + ": " + card.balance + " céntimos");
}/*
* La tarjeta de transporte en C: un struct con los datos y funciones aparte
* que reciben un puntero al struct. Es el punto de partida para comparar con
* la clase TransitCard.
*/
#include <stdio.h>
struct card {
char id[8];
int balance; /* saldo en céntimos */
};
void card_recharge(struct card *c, int amount) {
c->balance += amount;
}
int card_pay(struct card *c, int fare) {
if (c->balance < fare)
return 0; /* no alcanza el saldo */
c->balance -= fare;
return 1;
}
int main(void) {
struct card c = { "A-001", 0 };
card_recharge(&c, 1000);
card_pay(&c, 250);
printf("%s: %d céntimos\n", c.id, c.balance);
c.balance = -500; /* nada lo impide */
printf("%s: %d céntimos\n", c.id, c.balance);
return 0;
}/**
* Una tarjeta de transporte: su estado (código y saldo) y las operaciones
* que lo cambian viven juntos en una clase.
*/
public class TransitCard {
private final String id;
private int balance; // saldo en céntimos
/** Crea una tarjeta con el código dado y saldo cero. */
public TransitCard(String id) {
this.id = id;
this.balance = 0;
}
/** Agrega saldo a la tarjeta. */
public void recharge(int amount) {
balance += amount;
}
/** Cobra un pasaje si alcanza el saldo; devuelve si se pudo cobrar. */
public boolean pay(int fare) {
if (balance < fare) {
return false;
}
balance -= fare;
return true;
}
public String id() {
return id;
}
public int balance() {
return balance;
}
}Pruebas
Comprueban lo que afirman los apuntes; se ejecutan con make test.
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
// Prueba mínima de muestra: comprueba que el entorno corre JUnit.
// Los unit tests se ven en detalle en la semana 3.
class TransitCardTest {
@Test
void newCardStartsEmpty() {
TransitCard card = new TransitCard("A-001");
assertEquals(0, card.balance());
}
@Test
void payWithEnoughBalance() {
TransitCard card = new TransitCard("A-001");
card.recharge(1000);
assertTrue(card.pay(250));
assertEquals(750, card.balance());
}
@Test
void payWithoutBalanceChangesNothing() {
TransitCard card = new TransitCard("A-001");
assertFalse(card.pay(250));
assertEquals(0, card.balance());
}
}Compilación
Cómo se compilan y ejecutan los ejemplos.
# Semana 1: de C a Java y una primera clase.
# make compila todo a build/ (Java con javac; la versión en C con gcc)
# make test corre las demostraciones y la prueba JUnit de muestra
# make clean borra build/
JAVAC = javac
JFLAGS = -Xlint:all -Werror
SRC = $(wildcard *.java)
DEMOS = Hello FromC StructStyle CardDemo
CC = gcc
CFLAGS = -Wall -Wextra -Werror -O1
all: build/.stamp build/transit_card
build/transit_card: transit_card.c
mkdir -p build
$(CC) $(CFLAGS) -o $@ $<
build/.stamp: $(SRC)
mkdir -p build
$(JAVAC) $(JFLAGS) -cp $(JUNIT_JAR) -d build $(SRC)
touch $@
test: all
@echo "== transit_card (C)"; ./build/transit_card
@for d in $(DEMOS); do echo "== $$d"; java -cp build $$d || exit 1; done
java -jar $(JUNIT_JAR) execute --class-path build --scan-class-path \
--disable-banner --disable-ansi-colors --details=tree
clean:
rm -rf build
.PHONY: all test clean