Nivel: A1/A2 · AGE · CCAA · Universidades · Entidades Locales
Elaborado a partir de: temario base + preguntas reales de examen + análisis de tribunal
Un lenguaje de programación es un conjunto de reglas sintácticas (cómo se escribe) y semánticas (qué significa) que permiten expresar instrucciones que una máquina puede interpretar o ejecutar. Actúan como puente entre el pensamiento humano y la operación de la máquina.
Para la oposición: Un lenguaje de programación define tanto la forma (sintaxis) como el significado (semántica) de las instrucciones. Sin semántica, la sintaxis correcta no garantiza un comportamiento correcto.
| Nivel | Tipo | Ejemplo |
|---|---|---|
| Bajo nivel | Lenguaje máquina (binario) | 10110000 01100001 |
| Bajo nivel | Ensamblador (Assembly) | MOV AL, 61h |
| Alto nivel | Lenguajes estructurados/OOP | C, Java, Python, Pascal |
Lenguaje máquina: Único que entiende la CPU directamente. Consiste en secuencias de bits (0 y 1). Absolutamente dependiente del hardware.
Ensamblador (Assembly): Usa mnemónicos simbólicos (MOV, ADD, JMP) en lugar de bits. Necesita un ensamblador para traducirlo a código máquina. Depende de la arquitectura del procesador (x86, ARM...).
Alto nivel: Independientes del hardware. Más legibles y portables.
| Paradigma | Descripción | Ejemplos |
|---|---|---|
| Imperativo | El programador especifica cómo se hace paso a paso | C, Pascal, Ada |
| Declarativo | El programador especifica qué se quiere obtener | SQL, Prolog |
| Orientado a Objetos | Organiza el código en objetos con estado y comportamiento | Java, C++, Python |
| Funcional | Basado en funciones matemáticas puras, sin efectos secundarios | Haskell, Lisp, Erlang |
| Lógico | Basado en lógica formal y reglas de inferencia | Prolog |
| Concurrente | Diseñado para ejecución paralela y sincronización de procesos | Erlang, Go |
| Orientado a aspectos | Separa las preocupaciones transversales (logs, seguridad) del código | AspectJ |
Nota de oposición: Python es multiparadigma: soporta OOP, imperativo y funcional. Java es principalmente OOP aunque también imperativo. SQL es declarativo puro.
| Generación | Descripción | Ejemplo |
|---|---|---|
| 1ª GL | Lenguaje máquina | Binario |
| 2ª GL | Ensamblador | Assembly |
| 3ª GL | Lenguajes procedurales de alto nivel | C, Pascal, COBOL |
| 4ª GL | Orientados a aplicaciones/bases de datos | SQL, ABAP |
| 5ª GL | Inteligencia artificial y lógica | Prolog, Mercury |
Los traductores convierten código escrito en un lenguaje a otro (normalmente a código máquina o a un lenguaje de nivel inferior).
javac (Java → bytecode).javac compila a bytecode (.class), que la JVM interpreta/compila en tiempo de ejecución (JIT).Diferencia clave para oposición: El compilador produce un ejecutable independiente; el intérprete necesita estar presente en tiempo de ejecución. Java combina ambos: compila a bytecode y la JVM lo interpreta/JIT-compila.
Código fuente
↓
[Análisis Léxico] → Tokens (palabras reservadas, identificadores, operadores)
↓
[Análisis Sintáctico] → Árbol de Análisis Sintáctico (AST)
↓
[Análisis Semántico] → Comprobación de tipos, tabla de símbolos
↓
[Generación de Código Intermedio] → Código independiente de la máquina
↓
[Optimización] → Mejora eficiencia sin cambiar comportamiento
↓
[Generación de Código Máquina]
↓
Ejecutable (.exe / binario)
| Fase | Descripción |
|---|---|
| Análisis léxico | Divide el código en tokens. El componente se llama léxer o scanner |
| Análisis sintáctico | Verifica que los tokens siguen la gramática. Genera el AST |
| Análisis semántico | Comprueba coherencia de tipos, declaraciones. Construye tabla de símbolos |
| Generación intermedia | Produce código portable (p.ej. código de 3 direcciones) |
| Optimización | Elimina código muerto, pliega constantes, reorganiza instrucciones |
| Generación código final | Produce ensamblador o código máquina para la arquitectura destino |
Un tipo de dato define:
1. El conjunto de valores que puede tomar una variable.
2. Las operaciones que pueden realizarse sobre ella.
3. La representación interna en memoria.
Tipado estático vs dinámico:
- Estático: el tipo se declara en tiempo de compilación y no cambia (C, Java, Pascal).
- Dinámico: el tipo se determina en tiempo de ejecución (Python, JavaScript, Ruby).
Tipado fuerte vs débil:
- Fuerte: no se hacen conversiones implícitas entre tipos incompatibles (Java, Python).
- Débil: permite conversiones implícitas aunque pierdan información (JavaScript, C en algunos casos).
Representa números sin parte decimal.
| Tipo | Bits | Rango (sin signo) | Ejemplo Java |
|---|---|---|---|
byte |
8 | 0 a 255 | byte b = 200; |
short |
16 | -32.768 a 32.767 | short s = 1000; |
int |
32 | -2.147M a 2.147M | int i = 42; |
long |
64 | -9.2×10¹⁸ a 9.2×10¹⁸ | long l = 9999999999L; |
Representación interna: Complemento a Dos [MUY PREGUNTADO]
El complemento a dos permite representar números negativos en binario:
Ejemplo: -5 en 8 bits (complemento a 2)
5 en binario = 00000101
Invertir bits = 11111010
Sumar 1 = 11111011 → Esto es -5
Sistemas de numeración relacionados:
| Base | Nombre | Dígitos | Prefijo en C/Java |
|---|---|---|---|
| 2 | Binario | 0, 1 | 0b (Java 7+) |
| 8 | Octal | 0-7 | 0 (cero inicial) |
| 10 | Decimal | 0-9 | (ninguno) |
| 16 | Hexadecimal | 0-9, A-F | 0x |
Representa números con parte decimal. Estándar IEEE 754.
| Tipo | Bits | Precisión |
|---|---|---|
float |
32 | ~7 dígitos decimales |
double |
64 | ~15 dígitos decimales |
Estructura IEEE 754 (float, 32 bits):
[1 bit signo | 8 bits exponente | 23 bits mantisa]
Valor = (-1)^signo × 1.mantisa × 2^(exponente - 127)
Importante para examen: Los números reales en coma flotante NO son exactos. Ejemplo:
0.1 + 0.2 ≠ 0.3en la mayoría de lenguajes debido a la representación binaria. Para comparar flotantes nunca usar==, sinoMath.abs(a - b) < epsilon.
Desbordamiento (overflow) y subdesbordamiento (underflow):
- Overflow: el valor supera el máximo representable.
- Underflow: el valor es tan pequeño que se redondea a cero.
- NaN (Not a Number): resultado de operaciones inválidas como 0.0/0.0.
- Infinity: resultado de dividir un número distinto de cero entre cero.
Representa un único carácter.
| Codificación | Bits | Caracteres |
|---|---|---|
| ASCII | 7/8 bits | 128/256 caracteres |
| Unicode | Variable | Más de 1 millón de caracteres |
| UTF-8 | 1 a 4 bytes | Compatible con ASCII |
| UTF-16 | 2 o 4 bytes | Usado internamente en Java |
ASCII: 'A' = 65, 'a' = 97, '0' = 48, espacio = 32
Char en C: char c = 'A'; // almacena el valor 65
Solo dos valores: true (verdadero) o false (falso). Internamente se representa con 1 bit (o 1 byte por eficiencia de alineación de memoria).
boolean activo = true;
boolean terminado = false;
| Tipo | Descripción |
|---|---|
| Array/Vector | Colección de elementos del mismo tipo |
| Registro/Struct | Colección de elementos de tipos diferentes |
| Cadena (String) | Secuencia de caracteres |
| Enumerado (Enum) | Conjunto finito de constantes con nombre |
// Enum en C
enum DiaSemana { LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO };
enum DiaSemana hoy = MIERCOLES; // hoy vale 2 (empieza en 0)
// Enum en Java (más potente que en C)
enum Estado { PENDIENTE, ACEPTADO, RECHAZADO }
Estado e = Estado.ACEPTADO;
| Tipo | Descripción |
|---|---|
| Puntero | Almacena una dirección de memoria. Fundamental en C/C++ |
| Referencia | Alias de una variable (Java, C++) |
| Nulo/Void | Ausencia de valor o tipo |
// Puntero en C
int x = 10;
int *ptr = &x; // ptr apunta a la dirección de x
printf("%d", *ptr); // imprime 10 (desreferencia)
printf("%p", ptr); // imprime la dirección de memoria
Para la oposición: Java no tiene punteros explícitos como C, pero usa referencias. Cuando se pasa un objeto a un método en Java, se pasa la referencia (no el objeto completo), lo que permite modificar el objeto pero no reasignarlo fuera del método.
Automática, sin pérdida de datos. Siempre de tipo menor a tipo mayor.
byte → short → int → long → float → double
int i = 100;
long l = i; // automático: int → long
double d = i; // automático: int → double
Manual, puede haber pérdida de datos o truncamiento.
double d = 9.99;
int i = (int) d; // i = 9 (se trunca la parte decimal, NO se redondea)
long l = 12345678901L;
int j = (int) l; // pérdida de bits significativos
| Operador | Operación | Ejemplo | Resultado |
|---|---|---|---|
+ |
Suma | 5 + 3 |
8 |
- |
Resta | 5 - 3 |
2 |
* |
Multiplicación | 5 * 3 |
15 |
/ |
División | 7 / 2 |
3 (enteros) / 3.5 (reales) |
% |
Módulo (resto) | 7 % 3 |
1 |
** o ^ |
Potencia | 2 ** 3 |
8 |
Importante para oposición: En división entera,
7 / 2 = 3(se trunca hacia cero). Para obtener 3.5 hay que usar7.0 / 2o hacer casting:(double) 7 / 2.
Devuelven un valor booleano (true/false).
| Operador | Significado | Ejemplo | Resultado |
|---|---|---|---|
== |
Igual a | 5 == 5 |
true |
!= |
Distinto de | 5 != 3 |
true |
> |
Mayor que | 5 > 3 |
true |
< |
Menor que | 3 < 5 |
true |
>= |
Mayor o igual | 5 >= 5 |
true |
<= |
Menor o igual | 3 <= 4 |
true |
Truco de examen: En Java,
==sobre objetos compara referencias (si son el mismo objeto en memoria), no el contenido. Para comparar contenido se usa.equals(). Ejemplo:"hola" == "hola"puede serfalsesi son objetos distintos.
| Operador | Operación | Descripción |
|---|---|---|
&& / AND |
Conjunción | true solo si ambos son true |
\|\| / OR |
Disyunción | true si al menos uno es true |
! / NOT |
Negación | Invierte el valor booleano |
XOR |
Disyunción exclusiva | true si exactamente uno es true |
Tablas de verdad:
AND: OR: NOT: XOR:
A B A&&B A B A||B A !A A B A^B
T T T T T T T F T T F
T F F T F T F T T F T
F T F F T T F T T
F F F F F F F F F
| Operador | Equivale a | Ejemplo |
|---|---|---|
= |
Asignación simple | x = 5 |
+= |
x = x + n |
x += 3 |
-= |
x = x - n |
x -= 3 |
*= |
x = x * n |
x *= 2 |
/= |
x = x / n |
x /= 2 |
%= |
x = x % n |
x %= 3 |
int x = 5;
x++; // Post-incremento: usa x (=5) luego suma 1 → x=6
++x; // Pre-incremento: suma 1 primero → x=7, usa x (=7)
x--; // Post-decremento
--x; // Pre-decremento
Para examen:
-y = x++→ primero asigna x a y, luego incrementa x.
-y = ++x→ primero incrementa x, luego asigna x a y.
| Operador | Operación | Ejemplo (4 bits) |
|---|---|---|
& |
AND bit a bit | 1010 & 1100 = 1000 |
\| |
OR bit a bit | 1010 \| 1100 = 1110 |
^ |
XOR bit a bit | 1010 ^ 1100 = 0110 |
~ |
NOT bit a bit | ~1010 = 0101 |
<< |
Desplazamiento izquierda | 0001 << 2 = 0100 (×4) |
>> |
Desplazamiento derecha | 1000 >> 2 = 0010 (÷4) |
Para examen: Desplazar n bits a la izquierda equivale a multiplicar por 2^n. Desplazar n bits a la derecha equivale a dividir por 2^n (para enteros sin signo).
1. () → Paréntesis (máxima prioridad)
2. ! ~ ++ -- → Unarios
3. * / % → Multiplicativos
4. + - → Aditivos
5. << >> → Desplazamiento de bits
6. < <= > >= → Relacionales
7. == != → Igualdad
8. & → AND bit a bit
9. ^ → XOR bit a bit
10. | → OR bit a bit
11. && → AND lógico
12. || → OR lógico
13. ?: → Ternario
14. = += -= *= /= → Asignación (mínima prioridad)
Regla mnemotécnica: PEMDAS ampliado: Paréntesis → Unarios → Multiplicativos → Aditivos → Bits → Relacionales → Igualdad → AND → XOR → OR → Lógicos → Ternario → Asignación.
Las instrucciones condicionales permiten alterar el flujo de ejecución del programa en función de si una condición es verdadera o falsa. Son la base del control de flujo no secuencial.
Pseudocódigo:
SI condición ENTONCES
instrucciones
SINO SI condición2 ENTONCES
instrucciones
SINO
instrucciones
FIN SI
En Java/C:
int nota = 7;
if (nota >= 9) {
System.out.println("Sobresaliente");
} else if (nota >= 7) {
System.out.println("Notable");
} else if (nota >= 5) {
System.out.println("Aprobado");
} else {
System.out.println("Suspenso");
}
// Salida: Notable
En Python:
nota = 7
if nota >= 9:
print("Sobresaliente")
elif nota >= 7:
print("Notable")
elif nota >= 5:
print("Aprobado")
else:
print("Suspenso")
Alternativa al if-else encadenado cuando se compara una variable contra múltiples valores constantes.
// Java
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("Otro día");
}
// Salida: Miércoles
IMPORTANTE para oposición: Sin
break, el flujo "cae" al siguiente caso (fall-through). Esto es un error frecuente y fuente de preguntas de examen.
Pseudocódigo:
SEGÚN variable HACER
CASO valor1: instrucciones
CASO valor2: instrucciones
POR DEFECTO: instrucciones
FIN SEGÚN
Switch expressions en Java 14+ (informativo):
String resultado = switch (dia) {
case 1 -> "Lunes";
case 2 -> "Martes";
default -> "Otro";
};
Forma compacta de un if-else simple:
// condicion ? valor_si_true : valor_si_false
int max = (a > b) ? a : b;
String estado = (activo) ? "Activo" : "Inactivo";
Para examen: El operador ternario es una expresión (devuelve valor), no una sentencia. Se puede usar donde se espere un valor.
Los operadores && y || usan evaluación en cortocircuito (short-circuit evaluation):
// Si (a > 0) es false, NO se evalúa (b / a) → evita división por cero
if (a > 0 && b / a > 2) { ... }
// Si (x != null) es false, NO se evalúa x.length() → evita NullPointerException
if (x != null && x.length() > 0) { ... }
A && B: Si A es false, B no se evalúa (el resultado ya es false).A || B: Si A es true, B no se evalúa (el resultado ya es true).Un bucle (o ciclo) permite ejecutar un bloque de instrucciones repetidamente mientras se cumpla una condición.
Elementos de un bucle:
1. Inicialización: valor de partida del contador/variable de control.
2. Condición: expresión booleana que determina si el bucle continúa.
3. Actualización: modificación de la variable de control en cada iteración.
4. Cuerpo: instrucciones que se repiten.
Se comprueba la condición antes de ejecutar el cuerpo. Puede que no se ejecute ninguna vez si la condición es false desde el inicio.
// Java
int i = 0;
while (i < 5) {
System.out.println("Iteración: " + i);
i++;
}
// Imprime 0, 1, 2, 3, 4
Pseudocódigo:
MIENTRAS condicion HACER
instrucciones
FIN MIENTRAS
Se ejecuta el cuerpo al menos una vez, y luego se comprueba la condición.
int i = 0;
do {
System.out.println("Iteración: " + i);
i++;
} while (i < 5);
Pseudocódigo:
HACER
instrucciones
MIENTRAS condicion
Diferencia clave para oposición:
whilepuede ejecutarse 0 veces;do-whilese ejecuta al menos 1 vez.
Ideal cuando se conoce el número de iteraciones de antemano. Integra en una sola línea la inicialización, condición y actualización.
// Java — sintaxis clásica
for (int i = 0; i < 5; i++) {
System.out.println("i = " + i);
}
// For mejorado (for-each) para colecciones/arrays
int[] numeros = {10, 20, 30, 40};
for (int n : numeros) {
System.out.println(n);
}
# Python
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 10, 2): # 2, 4, 6, 8
print(i)
Pseudocódigo:
PARA i DESDE 1 HASTA 10 PASO 1 HACER
instrucciones
FIN PARA
| Instrucción | Acción |
|---|---|
break |
Sale inmediatamente del bucle |
continue |
Salta a la siguiente iteración |
return |
Sale del método/función completo |
for (int i = 0; i < 10; i++) {
if (i == 3) continue; // Salta el 3
if (i == 7) break; // Sale del bucle al llegar a 7
System.out.print(i + " "); // Imprime: 0 1 2 4 5 6
}
La recursividad es una técnica en la que una función se llama a sí misma para resolver un problema, dividiéndolo en subproblemas más pequeños del mismo tipo.
Requisitos para que sea correcta:
1. Caso base: condición que detiene la recursión (sin él → bucle infinito / desbordamiento de pila).
2. Caso recursivo: la función se llama a sí misma con un argumento que se acerca al caso base.
n! = n × (n-1) × (n-2) × ... × 1
0! = 1 (caso base)
// Java - Recursivo
int factorial(int n) {
if (n == 0) return 1; // Caso base
return n * factorial(n - 1); // Caso recursivo
}
// factorial(5) = 5 × 4 × 3 × 2 × 1 = 120
// Java - Iterativo (equivalente)
int factorialIterativo(int n) {
int resultado = 1;
for (int i = 1; i <= n; i++) {
resultado *= i;
}
return resultado;
}
F(0) = 0, F(1) = 1
F(n) = F(n-1) + F(n-2)
int fibonacci(int n) {
if (n <= 1) return n; // Casos base
return fibonacci(n - 1) + fibonacci(n - 2); // Caso recursivo
}
// fibonacci(6) → secuencia: 0,1,1,2,3,5,8 → resultado: 8
factorial(4)
→ 4 * factorial(3)
→ 3 * factorial(2)
→ 2 * factorial(1)
→ 1 * factorial(0)
→ 1 (caso base)
→ 1 * 1 = 1
→ 2 * 1 = 2
→ 3 * 2 = 6
→ 4 * 6 = 24
| Aspecto | Recursión | Iteración |
|---|---|---|
| Legibilidad | Alta (problemas divisibles) | Alta (secuencial) |
| Memoria | Mayor (pila de llamadas) | Menor |
| Riesgo | Stack Overflow | Bucle infinito |
| Rendimiento | Menor (overhead de llamadas) | Mayor |
| Uso ideal | Árboles, grafos, divide y vencerás | Cálculos simples |
| Tipo | Descripción |
|---|---|
| Directa | La función se llama a sí misma directamente |
| Indirecta | A llama a B y B llama a A (mutua) |
| De cola | La llamada recursiva es la última operación → el compilador puede optimizarla como bucle |
| Múltiple | La función se llama a sí misma más de una vez (Fibonacci) |
| Anidada | El argumento de la llamada recursiva es también una llamada recursiva |
Un subprograma (procedimiento o función) es un bloque de código con nombre que realiza una tarea específica y puede ser invocado desde cualquier parte del programa.
Ventajas:
- Reutilización: escribir una vez, usar muchas.
- Modularidad: dividir el problema en partes manejables.
- Abstracción: ocultar detalles de implementación.
- Mantenimiento: cambios localizados.
| Característica | Procedimiento | Función |
|---|---|---|
| Devuelve valor | No | Sí |
| Palabra clave | void / procedure |
function / tipo de retorno |
| Propósito | Realizar una acción | Calcular y devolver un resultado |
// Procedimiento (no devuelve nada)
void mostrarBienvenida(String nombre) {
System.out.println("Bienvenido, " + nombre + "!");
}
// Función (devuelve un valor)
int sumar(int a, int b) {
return a + b;
}
// Uso
mostrarBienvenida("Ana"); // Llama al procedimiento
int resultado = sumar(3, 5); // Llama a la función → resultado = 8
int a, int b).sumar(3, 5)).Se copia el valor. Cambios en la función NO afectan a la variable original.
void duplicar(int x) {
x = x * 2; // Solo modifica la copia local
System.out.println("Dentro: " + x); // 10
}
int num = 5;
duplicar(num);
System.out.println("Fuera: " + num); // Sigue siendo 5
Se pasa la dirección de memoria. Cambios en la función SÍ afectan a la variable original.
// En C, se simula con punteros
void duplicar(int *x) {
*x = *x * 2; // Modifica el valor en la dirección apuntada
}
int num = 5;
duplicar(&num);
printf("%d", num); // num ahora es 10
// En Java: los objetos se pasan por referencia de valor
// (se pasa la referencia, no el objeto completo)
void modificar(int[] arr) {
arr[0] = 99; // Sí modifica el array original
}
La expresión del argumento se evalúa cada vez que se usa el parámetro dentro de la función. Usado en ALGOL. Poco común hoy. Ejemplo histórico relevante en oposiciones.
Resumen para oposición: En Java, los tipos primitivos se pasan por valor; los objetos y arrays se pasan por referencia (técnicamente, la referencia por valor — se puede modificar el objeto pero no reasignar la variable).
| Tipo de variable | Declaración | Accesible desde |
|---|---|---|
| Local | Dentro de una función/bloque | Solo en ese bloque |
| Global | Fuera de todas las funciones | Todo el programa |
| De clase | Como atributo de clase | Toda la clase (en OOP) |
| De instancia | Atributo de un objeto | El objeto concreto (en OOP) |
int global = 100; // Variable global
void ejemplo() {
int local = 50; // Variable local
System.out.println(global); // OK: accede a la global
System.out.println(local); // OK: accede a la local
}
// Aquí NO se puede acceder a 'local'
Tiempo de vida vs ámbito:
- Ámbito: dónde es visible la variable (espacial).
- Tiempo de vida: cuánto tiempo existe en memoria (temporal).
Cada llamada recursiva crea un nuevo marco de pila (stack frame) con sus propias variables locales.
Pila de llamadas para factorial(3):
┌─────────────────┐
│ factorial(0)=1 │ ← cima (último en entrar)
├─────────────────┤
│ factorial(1)=1 │
├─────────────────┤
│ factorial(2)=2 │
├─────────────────┤
│ factorial(3)=6 │ ← base
└─────────────────┘
Stack Overflow: Si la recursión no tiene caso base o nunca converge al caso base, la pila se llena y el programa lanza un error
StackOverflowError(Java) oSegmentation Fault(C).
Mismo nombre de función, diferente número o tipo de parámetros. El compilador determina cuál llamar en tiempo de compilación (dispatch estático).
int sumar(int a, int b) { return a + b; }
double sumar(double a, double b) { return a + b; }
int sumar(int a, int b, int c) { return a + b + c; }
sumar(1, 2); // llama a la primera
sumar(1.5, 2.5); // llama a la segunda
sumar(1, 2, 3); // llama a la tercera
Sobrecarga vs Sobreescritura (Override): La sobrecarga (overloading) ocurre en la misma clase y se resuelve en tiempo de compilación. La sobreescritura (overriding) ocurre en herencia y se resuelve en tiempo de ejecución (polimorfismo).
Un vector (o array / tabla) es una estructura de datos que almacena un conjunto de elementos del mismo tipo en posiciones de memoria contiguas, accesibles mediante un índice.
// Java
int[] notas = new int[5]; // Vector de 5 enteros (sin inicializar → todos 0)
int[] pares = {2, 4, 6, 8, 10}; // Con inicialización directa
pares[0] = 2; // Primer elemento
pares[4] = 10; // Último elemento
// pares[5] → ArrayIndexOutOfBoundsException (fuera de rango)
// C
int notas[5]; // Declara 5 enteros
int pares[] = {2, 4, 6, 8, 10}; // Con inicialización
notas[0] = 7; // Acceso
# Python (listas dinámicas)
notas = [0] * 5 # Lista de 5 ceros
pares = [2, 4, 6, 8, 10]
print(pares[2]) # 6
int[] v = {5, 3, 8, 1, 9};
// Recorrido con for clásico
for (int i = 0; i < v.length; i++) {
System.out.print(v[i] + " "); // 5 3 8 1 9
}
// Recorrido con for-each
for (int elem : v) {
System.out.print(elem + " ");
}
// Búsqueda lineal: O(n) — no requiere ordenación
int buscarLineal(int[] v, int objetivo) {
for (int i = 0; i < v.length; i++) {
if (v[i] == objetivo) return i; // Devuelve el índice
}
return -1; // No encontrado
}
// Búsqueda binaria (el vector DEBE estar ORDENADO): O(log n)
int buscarBinaria(int[] v, int objetivo) {
int izq = 0, der = v.length - 1;
while (izq <= der) {
int medio = (izq + der) / 2;
if (v[medio] == objetivo) return medio;
else if (v[medio] < objetivo) izq = medio + 1;
else der = medio - 1;
}
return -1;
}
| Algoritmo de búsqueda | Complejidad | Requisito |
|---|---|---|
| Lineal (secuencial) | O(n) | Ninguno |
| Binaria | O(log n) | Array ordenado |
Burbuja (Bubble Sort): O(n²)
void burbuja(int[] v) {
int n = v.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (v[j] > v[j + 1]) {
// Intercambio
int temp = v[j];
v[j] = v[j + 1];
v[j + 1] = temp;
}
}
}
}
Comparativa de algoritmos de ordenación:
| Algoritmo | Caso mejor | Caso medio | Caso peor | Estable |
|---|---|---|---|---|
| Burbuja | O(n) | O(n²) | O(n²) | Sí |
| Selección | O(n²) | O(n²) | O(n²) | No |
| Inserción | O(n) | O(n²) | O(n²) | Sí |
| QuickSort | O(n log n) | O(n log n) | O(n²) | No |
| MergeSort | O(n log n) | O(n log n) | O(n log n) | Sí |
| HeapSort | O(n log n) | O(n log n) | O(n log n) | No |
// Matriz 3×3 en Java
int[][] matriz = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Acceso: matriz[fila][columna]
System.out.println(matriz[1][2]); // 6 (fila 1, columna 2)
// Recorrido
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(matriz[i][j] + " ");
}
System.out.println();
}
Un registro (struct en C, record en Pascal) es una estructura de datos que agrupa variables de distintos tipos bajo un mismo nombre. Equivale a un objeto simple (sin métodos).
// Definición del tipo registro
struct Alumno {
char nombre[50];
int edad;
float nota;
};
// Uso
struct Alumno a1;
strcpy(a1.nombre, "María García");
a1.edad = 22;
a1.nota = 8.5;
// Acceso a campos con el operador punto (.)
printf("Nombre: %s\n", a1.nombre);
printf("Nota: %.1f\n", a1.nota);
TYPE
TAlumno = RECORD
nombre : STRING[50];
edad : INTEGER;
nota : REAL;
END;
VAR
alumno1 : TAlumno;
BEGIN
alumno1.nombre := 'María';
alumno1.edad := 22;
alumno1.nota := 8.5;
END.
class Alumno {
String nombre;
int edad;
double nota;
}
Alumno a = new Alumno();
a.nombre = "María García";
a.edad = 22;
a.nota = 8.5;
Combinación potente: lista de registros.
struct Alumno clase[30]; // Array de 30 alumnos
// Inicializar el primero
strcpy(clase[0].nombre, "Ana López");
clase[0].edad = 20;
clase[0].nota = 7.5;
// Recorrer y mostrar todos
for (int i = 0; i < 30; i++) {
printf("%s - %d años - %.1f\n",
clase[i].nombre, clase[i].edad, clase[i].nota);
}
| Característica | Vector (Array) | Registro (Struct) |
|---|---|---|
| Tipos de datos | Homogéneo (mismo tipo) | Heterogéneo (distintos tipos) |
| Acceso | Por índice numérico | Por nombre de campo |
| Tamaño | Fijo en declaración | Definido en la estructura |
| Uso típico | Colecciones del mismo tipo | Representar una entidad |
Todo programa tiene al menos cuatro partes conceptuales:
┌─────────────────────────────┐
│ CABECERA │ Nombre, metadatos, imports, includes
├─────────────────────────────┤
│ DECLARACIONES GLOBALES │ Constantes, tipos, variables globales
├─────────────────────────────┤
│ SUBPROGRAMAS │ Funciones y procedimientos
├─────────────────────────────┤
│ PROGRAMA PRINCIPAL │ Punto de entrada (main)
└─────────────────────────────┘
PROGRAMA nombre_del_programa
CONSTANTES
PI = 3.14159
MAX = 100
TIPOS
TAlumno = REGISTRO
nombre: CADENA
nota: REAL
FIN REGISTRO
VARIABLES
edad: ENTERO
nombre: CADENA
FUNCIÓN calcularArea(radio: REAL): REAL
INICIO
DEVOLVER PI * radio * radio
FIN FUNCIÓN
PROCEDIMIENTO mostrar(texto: CADENA)
INICIO
ESCRIBIR(texto)
FIN PROCEDIMIENTO
INICIO // Programa principal
nombre ← "Ana"
edad ← 25
mostrar("Hola, " + nombre)
ESCRIBIR(calcularArea(5.0))
FIN
/* ====== Cabecera ====== */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ====== Constantes ====== */
#define MAX 100
#define PI 3.14159
/* ====== Tipos definidos por el usuario ====== */
typedef struct {
char nombre[50];
int edad;
float nota;
} Alumno;
/* ====== Variables globales ====== */
int contador = 0;
/* ====== Declaración de funciones ====== */
float calcularMedia(float notas[], int n);
void mostrarAlumno(Alumno a);
/* ====== Función principal ====== */
int main() {
float notas[] = {7.5, 8.0, 6.5, 9.0};
Alumno a1;
strcpy(a1.nombre, "Carlos Ruiz");
a1.edad = 21;
a1.nota = calcularMedia(notas, 4);
mostrarAlumno(a1);
return 0; // 0 indica ejecución exitosa
}
/* ====== Implementación de funciones ====== */
float calcularMedia(float notas[], int n) {
float suma = 0;
for (int i = 0; i < n; i++) suma += notas[i];
return suma / n;
}
void mostrarAlumno(Alumno a) {
printf("Nombre: %s\nEdad: %d\nNota: %.2f\n",
a.nombre, a.edad, a.nota);
}
/* ====== Paquete e imports ====== */
package com.ejemplo;
import java.util.Scanner;
/* ====== Clase principal ====== */
public class GestionAlumnos {
/* ====== Constantes de clase ====== */
static final int MAX_ALUMNOS = 30;
/* ====== Atributos de clase ====== */
static int totalAlumnos = 0;
/* ====== Método principal ====== */
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Introduce una nota: ");
double nota = sc.nextDouble();
String calificacion = obtenerCalificacion(nota);
System.out.println("Calificación: " + calificacion);
sc.close();
}
/* ====== Métodos auxiliares ====== */
static String obtenerCalificacion(double nota) {
if (nota >= 9) return "Sobresaliente";
else if (nota >= 7) return "Notable";
else if (nota >= 5) return "Aprobado";
else return "Suspenso";
}
static double calcularMedia(double[] notas) {
double suma = 0;
for (double n : notas) suma += n;
return suma / notas.length;
}
}
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Módulo de gestión de alumnos
"""
# ====== Imports ======
import sys
# ====== Constantes ======
MAX_ALUMNOS = 30
PI = 3.14159
# ====== Funciones ======
def calcular_media(notas: list) -> float:
"""Calcula la media de una lista de notas."""
if not notas:
return 0.0
return sum(notas) / len(notas)
def obtener_calificacion(nota: float) -> str:
"""Devuelve la calificación textual de una nota."""
if nota >= 9:
return "Sobresaliente"
elif nota >= 7:
return "Notable"
elif nota >= 5:
return "Aprobado"
else:
return "Suspenso"
# ====== Programa principal ======
def main():
notas = [7.5, 8.0, 9.5, 6.0, 5.5]
media = calcular_media(notas)
calificacion = obtener_calificacion(media)
print(f"Media: {media:.2f}")
print(f"Calificación: {calificacion}")
if __name__ == "__main__":
main()
1. ESCRITURA → El programador escribe el código fuente (.c, .java, .py)
2. COMPILACIÓN → El compilador traduce a código objeto / bytecode
3. ENLAZADO → El linker une código objeto con bibliotecas → ejecutable
4. CARGA → El SO carga el ejecutable en memoria RAM
5. EJECUCIÓN → La CPU ejecuta las instrucciones
6. FINALIZACIÓN → El programa libera recursos y devuelve el control al SO
El enlazador (Linker):
- Une el código objeto del programa con las bibliotecas (librerías).
- Resuelve referencias externas (llamadas a funciones de otras unidades de compilación).
- Produce el ejecutable final.
Enlazado estático vs dinámico:
- Estático: las librerías se incluyen dentro del ejecutable. Ejecutable mayor pero autónomo.
- Dinámico: las librerías (.dll, .so) se cargan en tiempo de ejecución. Ejecutable menor pero dependiente.
┌──────────────────────────────┐ Dirección alta
│ PILA (Stack) │ Variables locales, marcos de función
│ (crece hacia abajo) │
├──────────────────────────────┤
│ │
│ MONTÓN (Heap) │ Memoria dinámica (new, malloc)
│ (crece hacia arriba) │
│ │
├──────────────────────────────┤
│ SEGMENTO DE DATOS (.data) │ Variables globales y estáticas
├──────────────────────────────┤
│ SEGMENTO DE CÓDIGO (.text) │ Instrucciones del programa
└──────────────────────────────┘ Dirección baja
| Área | Contenido | Gestión |
|---|---|---|
| Stack (Pila) | Variables locales, parámetros, retornos | Automática (LIFO) |
| Heap (Montón) | Objetos creados con new/malloc |
Manual o GC |
| Data segment | Variables globales y estáticas | Automática |
| Code segment | Instrucciones del programa | Solo lectura |
Garbage Collector (GC): En Java y otros lenguajes modernos, la liberación de la memoria del Heap es automática. En C/C++ es manual (
free/delete). Si no se libera → memory leak (fuga de memoria).
Esta sección es directamente derivada de las preguntas del examen real (preguntas 1 y 2 del TXT).
| Concepto | Definición |
|---|---|
| Clase | Plantilla/molde que define atributos y métodos de un tipo de objetos |
| Objeto | Instancia concreta de una clase, con sus propios valores |
| Encapsulación | Ocultar el estado interno y exponer solo lo necesario mediante interfaz |
| Herencia | Una clase hija reutiliza y extiende los atributos/métodos de una clase padre |
| Polimorfismo | Un mismo mensaje puede comportarse distinto según el objeto receptor |
| Abstracción | Modelar solo las características relevantes de una entidad real |
La herencia es un mecanismo por el cual una clase (clase hija o subclase) adquiere los atributos y métodos de otra clase (clase padre o superclase), pudiendo añadir nuevos o modificar los existentes.
Ventajas:
- Reutilización de código.
- Jerarquía de clases que modela el mundo real.
- Base del polimorfismo.
Tipos de herencia:
- Simple: una clase hereda de una sola clase padre (Java, PHP).
- Múltiple: una clase puede heredar de varias clases padre (C++, Python). Java lo emula con interfaces.
Ejemplo con el modelo de datos del examen (Voto por Correo):
// Clase padre (superclase)
public class Persona {
protected String dni;
protected String nrp;
protected String nombre;
protected String apellidos;
public Persona(String dni, String nrp, String nombre, String apellidos) {
this.dni = dni;
this.nrp = nrp;
this.nombre = nombre;
this.apellidos = apellidos;
}
public String getDni() { return dni; }
public String getNrp() { return nrp; }
public String getNombre() { return nombre; }
public String getApellidos() { return apellidos; }
@Override
public String toString() {
return nombre + " " + apellidos + " (DNI: " + dni + ")";
}
}
// Clase hija que hereda de Persona
public class Trabajador extends Persona {
private String categoria;
private String centro;
private String mesa;
public Trabajador(String dni, String nrp, String nombre,
String apellidos, String categoria, String centro) {
super(dni, nrp, nombre, apellidos); // Llama al constructor del padre
this.categoria = categoria;
this.centro = centro;
}
public String getCategoria() { return categoria; }
public String getCentro() { return centro; }
public String getMesa() { return mesa; }
public void setMesa(String mesa) { this.mesa = mesa; }
}
Justificación de las entidades elegidas: Se elige Persona como clase padre porque contiene los datos comunes (DNI, NRP, nombre, apellidos). Trabajador hereda de Persona y añade los datos laborales (categoría, centro, mesa), evitando duplicar los atributos comunes.
Conjunto de clases para gestión del voto por correo (Pregunta 2 del examen):
import java.time.LocalDate;
// Gestiona toda la información de votación de un trabajador
public class GestorVotoPorCorreo {
private String dni;
private LocalDate fechaSolicitud;
private String estadoSolicitud; // "espera", "aceptado", "rechazado"
private LocalDate fechaRecepcion;
private LocalDate fechaEntrega;
private String mesaEntrega;
public GestorVotoPorCorreo(String dni) {
this.dni = dni;
}
// a) ¿Ha solicitado el voto por correo?
public boolean haSolicitadoVotoPorCorreo() {
return fechaSolicitud != null;
}
// b) ¿Se le ha concedido el voto por correo?
public boolean leConcedieronVotoPorCorreo() {
return "aceptado".equalsIgnoreCase(estadoSolicitud);
}
// c) ¿Ha sido recibido el voto por correo?
public boolean fueRecibidoElVoto() {
return fechaRecepcion != null;
}
// d) ¿Se ha entregado el voto a la mesa?
public boolean fueEntregadoALaMesa() {
return fechaEntrega != null && mesaEntrega != null;
}
// Setters
public void registrarSolicitud(LocalDate fecha) {
this.fechaSolicitud = fecha;
this.estadoSolicitud = "espera";
}
public void actualizarEstado(String estado) {
this.estadoSolicitud = estado;
}
public void registrarRecepcion(LocalDate fecha) {
this.fechaRecepcion = fecha;
}
public void registrarEntrega(String mesa, LocalDate fecha) {
this.mesaEntrega = mesa;
this.fechaEntrega = fecha;
}
}
Aplicación que usa las clases (consola):
public class AplicacionVoto {
public static void main(String[] args) {
GestorVotoPorCorreo gestor = new GestorVotoPorCorreo("12345678A");
// Simulamos el proceso completo
gestor.registrarSolicitud(LocalDate.of(2024, 5, 10));
gestor.actualizarEstado("aceptado");
gestor.registrarRecepcion(LocalDate.of(2024, 6, 1));
gestor.registrarEntrega("Mesa 3 - Centro Norte", LocalDate.of(2024, 6, 5));
// Consultas
System.out.println("¿Ha solicitado voto por correo? " +
gestor.haSolicitadoVotoPorCorreo());
System.out.println("¿Le fue concedido el voto? " +
gestor.leConcedieronVotoPorCorreo());
System.out.println("¿Fue recibido el voto? " +
gestor.fueRecibidoElVoto());
System.out.println("¿Fue entregado a la mesa? " +
gestor.fueEntregadoALaMesa());
}
}
Modelo de datos ampliado para el escrutinio (Pregunta 3 del examen):
Persona (DNI, NRP, Nombre, Apellidos)
DatosLaborales (NRP, Categoria, Centro)
DatosVotacion (NRP, Mesa, Centro)
SolicitudesVotoPorCorreo (DNI, Fecha, Estado)
RecibidosVotosPorCorreo (DNI, Fecha)
EntregadosVotosPorCorreo (DNI, Mesa, Fecha)
-- AMPLIACIÓN PARA ESCRUTINIO --
Urna (ID_Urna, Mesa, Categoria, VotosCandidata1, VotosCandidata2, VotosBlanco, VotosNulo)
Mesa (ID_Mesa, Centro, NumUrnas)
ResultadoEscrutinio (ID_Mesa, VotosPonderados, FechaCalculo)
Ponderaciones del voto por categoría:
| Categoría laboral | Ponderación |
|---|---|
| Profesores doctores con vinculación permanente | 51% |
| Resto del profesorado y personal investigador | 16% |
| Estudiantes | 24% |
| Personal de administración y servicios | 9% |
Implementación del escrutinio ponderado (Pregunta 4 del examen):
public class Urna {
private String idUrna;
private String mesa;
private String categoria;
private int votosTotal;
// Mapa de ponderaciones por categoría
private static final Map<String, Double> PONDERACIONES = new HashMap<>();
static {
PONDERACIONES.put("PDI_PERMANENTE", 0.51);
PONDERACIONES.put("RESTO_PROFESORADO", 0.16);
PONDERACIONES.put("ESTUDIANTES", 0.24);
PONDERACIONES.put("PAS", 0.09);
}
public double calcularVotosPonderados() {
double ponderacion = PONDERACIONES.getOrDefault(categoria, 0.0);
return votosTotal * ponderacion;
}
// Getters y setters...
}
public class Mesa {
private String idMesa;
private List<Urna> urnas = new ArrayList<>();
public void agregarUrna(Urna urna) {
urnas.add(urna);
}
public double calcularResultadoPonderado() {
return urnas.stream()
.mapToDouble(Urna::calcularVotosPonderados)
.sum();
}
}
Esta sección es directamente derivada de las preguntas 5, 6 y 7 del examen real.
REST (Representational State Transfer) es un estilo arquitectónico (no un protocolo) para sistemas distribuidos, definido por Roy Fielding en su tesis doctoral (2000).
Las 6 restricciones de REST:
| Restricción | Descripción |
|---|---|
| Cliente-Servidor | Separación de responsabilidades: UI y lógica de negocio independientes |
| Sin estado (Stateless) | Cada petición contiene toda la información necesaria; el servidor no guarda sesión |
| Cacheable | Las respuestas deben indicar si son cacheables para mejorar escalabilidad |
| Sistema en capas | El cliente no sabe si está conectado directamente al servidor final |
| Interfaz uniforme | Identificación de recursos, manipulación mediante representaciones, mensajes autodescriptivos |
| Código bajo demanda | (Opcional) El servidor puede enviar código ejecutable al cliente |
Métodos HTTP en REST [MUY PREGUNTADO]:
| Método | Acción CRUD | Idempotente | Seguro | Uso |
|---|---|---|---|---|
GET |
Read | Sí | Sí | Obtener recurso(s) |
POST |
Create | No | No | Crear nuevo recurso |
PUT |
Update | Sí | No | Actualizar recurso completo |
PATCH |
Update | No | No | Actualizar recurso parcialmente |
DELETE |
Delete | Sí | No | Eliminar recurso |
Códigos de estado HTTP [PREGUNTA RECURRENTE]:
| Código | Significado |
|---|---|
| 200 | OK — éxito |
| 201 | Created — recurso creado |
| 204 | No Content — éxito sin cuerpo |
| 400 | Bad Request — petición inválida |
| 401 | Unauthorized — no autenticado |
| 403 | Forbidden — no autorizado |
| 404 | Not Found — recurso no encontrado |
| 409 | Conflict — conflicto de estado |
| 500 | Internal Server Error |
SOAP (Simple Object Access Protocol) es un protocolo de mensajería basado en XML, definido por el W3C.
| Característica | Descripción |
|---|---|
| Protocolo | Protocolo formal con especificación W3C |
| Formato | Exclusivamente XML (envelope, header, body, fault) |
| Transporte | HTTP, SMTP, TCP — independiente del protocolo de transporte |
| WSDL | Web Services Description Language — define la interfaz del servicio |
| Estándar WS-* | WS-Security, WS-ReliableMessaging, WS-AtomicTransaction |
| Tipado | Tipado fuerte mediante XML Schema (XSD) |
| Estado | Puede ser con estado o sin estado |
Estructura de un mensaje SOAP:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<!-- Información de autenticación, seguridad, etc. -->
</soap:Header>
<soap:Body>
<ObtenerPersona>
<dni>12345678A</dni>
</ObtenerPersona>
</soap:Body>
</soap:Envelope>
| Aspecto | REST | SOAP |
|---|---|---|
| Tipo | Estilo arquitectónico | Protocolo formal |
| Formato | JSON, XML, texto libre | Solo XML |
| Transporte | Principalmente HTTP | HTTP, SMTP, TCP... |
| Estado | Sin estado (stateless) | Puede ser con o sin estado |
| Rendimiento | Mayor (mensajes más ligeros) | Menor (XML verboso) |
| Seguridad | HTTPS, OAuth, JWT | WS-Security (estándar robusto) |
| Contratos | No obligatorio | WSDL obligatorio |
| Escalabilidad | Alta | Menor |
| Uso típico | APIs públicas, móvil, microservicios | Banca, seguros, sistemas legacy |
| Estándar | No hay estándar único | W3C |
Interfaz de la API (Pregunta 5a):
GET /api/trabajadores/{nrp}/centromesa
POST /api/trabajadores/{nrp}/centromesa
GET /api/votoporcorreo/{dni}
PUT /api/votoporcorreo/{dni}/estado
Implementación en Java (Spring Boot) (Pregunta 5b):
@RestController
@RequestMapping("/api")
public class VotacionController {
// Asignar centro y mesa a un trabajador
@PostMapping("/trabajadores/{nrp}/centromesa")
public ResponseEntity<String> asignarCentroYMesa(
@PathVariable String nrp,
@RequestBody DatosVotacionDTO datos) {
// Lógica de negocio: actualizar DatosVotacion en BD
datosVotacionService.asignar(nrp, datos.getMesa(), datos.getCentro());
return ResponseEntity.ok("Centro y mesa asignados correctamente");
}
// Saber si una persona ha pedido el voto por correo
@GetMapping("/votoporcorreo/{dni}")
public ResponseEntity<SolicitudDTO> consultarSolicitud(
@PathVariable String dni) {
SolicitudDTO solicitud = solicitudService.findByDni(dni);
if (solicitud == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(solicitud);
}
// Actualizar el estado de la petición del voto por correo
@PutMapping("/votoporcorreo/{dni}/estado")
public ResponseEntity<String> actualizarEstado(
@PathVariable String dni,
@RequestBody EstadoDTO estadoDTO) {
solicitudService.actualizarEstado(dni, estadoDTO.getEstado());
return ResponseEntity.ok("Estado actualizado a: " + estadoDTO.getEstado());
}
}
Pregunta 6a — Estructura JSON de un trabajador:
{
"trabajador": {
"datosPersonales": {
"dni": "12345678A",
"nrp": "NRP001",
"nombre": "María",
"apellidos": "García López"
},
"datosLaborales": {
"categoria": "PDI_PERMANENTE",
"centro": "Facultad de Informática"
},
"datosVotacion": {
"mesa": "Mesa 3",
"centro": "Edificio Central"
},
"votoPorCorreo": {
"solicitud": {
"fecha": "2024-05-10",
"estado": "aceptado"
},
"recepcion": {
"fecha": "2024-06-01"
},
"entrega": {
"mesa": "Mesa 3",
"fecha": "2024-06-05"
}
}
}
}
Pregunta 6b — Clase Java para almacenar el JSON recibido:
public class TrabajadorDTO {
private DatosPersonalesDTO datosPersonales;
private DatosLaboralesDTO datosLaborales;
private DatosVotacionDTO datosVotacion;
private VotoPorCorreoDTO votoPorCorreo;
// Clases internas
public static class DatosPersonalesDTO {
private String dni;
private String nrp;
private String nombre;
private String apellidos;
// getters y setters
}
public static class DatosLaboralesDTO {
private String categoria;
private String centro;
// getters y setters
}
public static class DatosVotacionDTO {
private String mesa;
private String centro;
// getters y setters
}
public static class VotoPorCorreoDTO {
private SolicitudDTO solicitud;
private RecepcionDTO recepcion;
private EntregaDTO entrega;
// getters y setters
}
// getters y setters generales
}
Derivado directamente de las preguntas 8 y 9 del examen real.
Un ORM (Object-Relational Mapping) es una técnica de programación que permite interactuar con una base de datos relacional usando el paradigma orientado a objetos, sin escribir SQL directamente.
| Concepto ORM | Equivalente en BD relacional |
|---|---|
| Clase | Tabla |
| Objeto/Instancia | Fila (registro) |
| Atributo | Columna |
| Referencia a objeto | Clave foránea |
Al menos tres diferencias (pregunta 8):
| Aspecto | Con ORM (Hibernate/Doctrine) | Sin ORM (JDBC/PDO directo) |
|---|---|---|
| Código | Se trabaja con objetos Java/PHP directamente | Se escribe SQL manualmente |
| Portabilidad | Independiente del motor de BD (MySQL, Oracle…) | SQL puede ser específico del motor |
| Mantenimiento | Cambios en el modelo se reflejan en el mapeo | Hay que modificar SQL en múltiples sitios |
| Rendimiento | Puede generar SQL ineficiente si no se configura | Control total sobre las consultas |
| Seguridad | Protección automática contra SQL injection | Requiere sanitización manual |
| Curva de aprendizaje | Mayor (hay que aprender el ORM) | Menor para SQL simple |
| Caché | Mecanismos de caché de primer y segundo nivel | Sin caché automático |
Pregunta 9a — Cómo se crea la tabla Persona:
Hibernate puede crear la tabla automáticamente en la base de datos al arrancar la aplicación, según la configuración de hibernate.hbm2ddl.auto:
- create: elimina y crea la tabla en cada arranque.
- update: modifica la tabla si hay cambios en la entidad.
- validate: solo valida que la tabla coincide con la entidad.
- none: no hace nada automáticamente.
La tabla Persona se crearía con las columnas id (PK autoincremental), DNI, NRP, Nombre y Apellidos, según las anotaciones del código.
Pregunta 9b — Explicación de anotaciones:
import javax.persistence.*;
@Entity // (1)
@Table(name = "Persona") // (2)
public class Persona {
@Id // (3)
@GeneratedValue(strategy = GenerationType.IDENTITY) // (4)
private Long id;
@Column(name = "DNI") // (5)
private String dni;
@Column(name = "NRP")
private String nrp;
@Column(name = "Nombre")
private String nombre;
@Column(name = "Apellidos")
private String apellidos;
}
| Anotación | Explicación |
|---|---|
@Entity |
Marca la clase como una entidad JPA, es decir, será mapeada a una tabla de BD |
@Table(name="...") |
Especifica el nombre de la tabla en la BD. Si se omite, usa el nombre de la clase |
@Id |
Marca el campo como clave primaria de la entidad |
@GeneratedValue |
Indica la estrategia de generación de la clave primaria. IDENTITY delega en la BD (autoincremento) |
@Column(name="...") |
Mapea el atributo a una columna específica de la tabla. Permite especificar nombre, longitud, nulabilidad, etc. |
Estrategias de @GeneratedValue:
| Estrategia | Descripción |
|---|---|
IDENTITY |
Usa el autoincremento de la BD (MySQL, PostgreSQL) |
SEQUENCE |
Usa una secuencia de BD (Oracle) |
TABLE |
Usa una tabla auxiliar para generar IDs |
AUTO |
Hibernate elige la estrategia según la BD |
Doctrine es el ORM estándar para PHP, equivalente a Hibernate para Java.
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="Persona")
*/
class Persona
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(name="DNI", type="string", length=9)
*/
private $dni;
/**
* @ORM\Column(name="NRP", type="string")
*/
private $nrp;
/**
* @ORM\Column(name="Nombre", type="string")
*/
private $nombre;
/**
* @ORM\Column(name="Apellidos", type="string")
*/
private $apellidos;
}
Aunque el título habla de "lenguajes de programación", los tribunales suelen preguntar sobre patrones de diseño cuando hay código Java/PHP:
public interface Votable {
boolean haSolicitadoVoto();
boolean haEntregadoVoto();
}
public class Trabajador extends Persona implements Votable {
@Override
public boolean haSolicitadoVoto() { /* implementación */ }
@Override
public boolean haEntregadoVoto() { /* implementación */ }
}
default con implementación.public abstract class EntidadBase {
protected Long id;
// Método abstracto: las subclases DEBEN implementarlo
public abstract String getIdentificador();
// Método concreto: las subclases PUEDEN sobreescribirlo
public Long getId() { return id; }
}
| Aspecto | Clase Abstracta | Interfaz |
|---|---|---|
| Instanciable | No | No |
| Herencia | Solo de una | Múltiples |
| Métodos | Abstractos y concretos | Abstractos (+ default desde Java 8) |
| Atributos | Cualquier tipo | Solo constantes (public static final) |
try {
int resultado = 10 / 0; // Lanza ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
} catch (Exception e) {
System.out.println("Error genérico: " + e.getMessage());
} finally {
System.out.println("Este bloque siempre se ejecuta");
}
try: bloque de código que puede lanzar excepciones.catch: captura y maneja la excepción.finally: se ejecuta siempre, con o sin excepción (para liberar recursos).throw: lanza una excepción manualmente.throws: declara que un método puede lanzar una excepción.Jerarquía de excepciones en Java:
Throwable
├── Error (errores graves del sistema: OutOfMemoryError, StackOverflowError)
└── Exception
├── RuntimeException (no comprobadas: NullPointerException, ArrayIndexOutOfBoundsException)
└── IOException, SQLException... (comprobadas: deben capturarse o declararse)
| Colección | Implementación | Ordenada | Duplicados | Acceso |
|---|---|---|---|---|
ArrayList |
Array dinámico | Sí (índice) | Sí | O(1) |
LinkedList |
Lista enlazada | Sí | Sí | O(n) |
HashSet |
Tabla hash | No | No | O(1) |
TreeSet |
Árbol rojo-negro | Sí (natural) | No | O(log n) |
HashMap |
Tabla hash | No | No (claves) | O(1) |
TreeMap |
Árbol rojo-negro | Sí (claves) | No (claves) | O(log n) |
Relacionada con los temas de API REST del examen:
- SQL Injection: evitar con parámetros preparados o el ORM.
- XSS (Cross-Site Scripting): sanitizar entradas en la capa de presentación.
- CSRF (Cross-Site Request Forgery): tokens CSRF en formularios.
- Autenticación vs Autorización:
- Autenticación: ¿quién eres? (login, JWT, OAuth).
- Autorización: ¿qué puedes hacer? (roles, permisos).
- JWT (JSON Web Token): estándar para autenticación stateless en APIs REST.
- OAuth 2.0: protocolo de autorización delegada.
Aunque no es el tema principal, el modelo de datos del enunciado implica conocimiento de:
- Clave primaria (PK) y clave foránea (FK).
- Integridad referencial.
- Normalización (1FN, 2FN, 3FN).
- Índices en BD.
- Transacciones (ACID: Atomicidad, Consistencia, Aislamiento, Durabilidad).
git init, git add, git commit, git push, git pull, git branch, git merge.Bloque A — Lenguajes y Traductores:
¿Cuál de las siguientes afirmaciones sobre el compilador es correcta?
- a) Traduce el código línea a línea en tiempo de ejecución.
- b) Genera un ejecutable independiente antes de la ejecución.
- c) Necesita estar presente siempre en tiempo de ejecución.
- d) Solo funciona con lenguajes de alto nivel declarativos.
- Respuesta: b
¿Qué fase del compilador genera el Árbol de Análisis Sintáctico (AST)?
- a) Análisis léxico
- b) Análisis semántico
- c) Análisis sintáctico
- d) Generación de código intermedio
- Respuesta: c
¿A qué generación pertenece SQL?
- a) 2ª GL — b) 3ª GL — c) 4ª GL — d) 5ª GL
- Respuesta: c
Bloque B — Tipos de Datos:
¿Cómo se representa el número -5 en 8 bits usando complemento a dos?
- a) 10000101 — b) 11111011 — c) 00000101 — d) 11111010
- Respuesta: b
¿Cuántos bits ocupa un double según el estándar IEEE 754?
- a) 32 — b) 64 — c) 128 — d) 16
- Respuesta: b
¿Qué codificación usa Java internamente para los caracteres?
- a) ASCII — b) UTF-8 — c) UTF-16 — d) ISO-8859-1
- Respuesta: c
Bloque C — Operadores y Control de Flujo:
¿Cuál es el resultado de 7 / 2 en Java siendo ambos enteros?
- a) 3.5 — b) 3 — c) 4 — d) Error de compilación
- Respuesta: b
¿Qué ocurre en un switch en Java si no se pone break al final de un case?
- a) Error de compilación — b) Se ejecuta solo ese caso — c) Fall-through: se ejecutan los casos siguientes — d) Se ejecuta el default
- Respuesta: c
¿Cuál es la precedencia correcta (de mayor a menor)?
- a) && > || > ! > * — b) ! > * > + > && > || — c) * > + > ! > || — d) + > * > && > !
- Respuesta: b
Bloque D — Bucles y Recursividad:
¿Cuántas veces puede ejecutarse mínimo un bucle while?
¿Cuántas veces puede ejecutarse mínimo un bucle do-while?
¿Qué es imprescindible en una función recursiva para que no produzca Stack Overflow?
Bloque E — OOP y Herencia:
En Java, ¿cuántas clases puede heredar una clase mediante extends?
¿Cuántas interfaces puede implementar una clase en Java?
¿Qué anotación en Hibernate indica que una clase es una entidad persistente?
@Table — b) @Column — c) @Entity — d) @IdBloque F — REST y SOAP:
¿Cuál de los siguientes métodos HTTP es idempotente?
REST es:
¿Cuál es el formato de datos obligatorio en SOAP?
¿Qué código HTTP se devuelve cuando un recurso no se encuentra?
¿Cuál es una característica fundamental de REST en cuanto al estado?
| Tema | Concepto Crítico |
|---|---|
| Lenguajes | Compilador genera ejecutable; intérprete ejecuta línea a línea |
| Java | Compila a bytecode (javac) → JVM lo ejecuta (JIT). "Write once, run anywhere" |
| Tipos | IEEE 754 para flotantes; complemento a 2 para enteros negativos |
| Operadores | Precedencia: ! > * / > + - > comparación > && > \|\| |
| Condicionales | switch sin break produce fall-through |
| Bucles | while puede ejecutarse 0 veces; do-while al menos 1 vez |
| Recursividad | Siempre necesita caso base; usa la pila de llamadas; riesgo: StackOverflow |
| Paso de parámetros | Por valor: no modifica original; por referencia: sí modifica |
| Arrays | Homogéneos, índice desde 0, acceso O(1), memoria contigua |
| Registros | Heterogéneos, acceso por nombre de campo |
| Estructura | Todo programa: cabecera + declaraciones + subprogramas + main |
| Herencia | extends en Java (una sola clase); implements para múltiples interfaces |
| ORM | Mapea clases a tablas; evita SQL manual; riesgo de rendimiento por SQL generado |
| @Entity | Marca clase como entidad JPA persistente en Hibernate |
| REST | Stateless, métodos HTTP (GET/POST/PUT/DELETE), respuestas JSON |
| SOAP | Protocolo, XML obligatorio, WSDL, WS-Security |
| REST vs SOAP | REST: ligero, JSON, sin estado; SOAP: robusto, XML, contratos WSDL |
| Búsqueda lineal | O(n), no requiere ordenación |
| Búsqueda binaria | O(log n), requiere array ordenado |
| Bubble sort | O(n²), estable, fácil de implementar |
Temario elaborado para preparación de oposiciones TIC de nivel A1/A2. Incluye análisis de preguntas reales de examen, ingeniería inversa del tribunal y extensiones temáticas necesarias para alcanzar el nivel de una academia de oposiciones.