📝 tema1_basadoex
← Volver

LENGUAJES DE PROGRAMACIÓN — TEMARIO COMPLETO PARA OPOSICIONES TIC

Nivel: A1/A2 · AGE · CCAA · Universidades · Entidades Locales
Elaborado a partir de: temario base + preguntas reales de examen + análisis de tribunal


ÍNDICE GENERAL

PARTE I — LENGUAJES DE PROGRAMACIÓN

PARTE II — TIPOS DE DATOS

PARTE III — OPERADORES

PARTE IV — INSTRUCCIONES CONDICIONALES

PARTE V — BUCLES Y RECURSIVIDAD

PARTE VI — PROCEDIMIENTOS, FUNCIONES Y PARÁMETROS

PARTE VII — VECTORES Y REGISTROS

PARTE VIII — ESTRUCTURA DE UN PROGRAMA

PARTE IX — PROGRAMACIÓN ORIENTADA A OBJETOS (derivada del examen real)

PARTE X — APIs RESTful y SOAP (derivada del examen real)

PARTE XI — ORM: HIBERNATE Y DOCTRINE (derivada del examen real)

PARTE XII — AMPLIACIONES Y ANÁLISIS DE EXAMEN


PARTE I — LENGUAJES DE PROGRAMACIÓN

1. Lenguajes de Programación

1.1 Concepto

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.


1.2 Niveles de Abstracción

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.


1.3 Clasificación por Paradigma y Generación

Por Paradigma [MUY PREGUNTADO]

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.

Por Generación [PREGUNTA TÍPICA]

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

1.4 Traductores de Lenguaje [MUY PREGUNTADO]

Los traductores convierten código escrito en un lenguaje a otro (normalmente a código máquina o a un lenguaje de nivel inferior).

Compilador

Intérprete

Transpilador (Transcompilador)

Máquina Virtual y Bytecode [IMPORTANTE]

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.


1.5 Fases de Compilación [PREGUNTA DIFÍCIL]

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

PARTE II — TIPOS DE DATOS

2. Representación de Tipos de Datos

2.1 Concepto de Tipo de Dato

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).


2.2 Tipos Simples o Primitivos

2.2.1 Entero (Integer) [PREGUNTA TÍPICA]

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

2.2.2 Real o Flotante (Float/Double) [MUY PREGUNTADO]

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.3 en la mayoría de lenguajes debido a la representación binaria. Para comparar flotantes nunca usar ==, sino Math.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.

2.2.3 Carácter (Char)

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

2.2.4 Booleano (Boolean)

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;

2.3 Tipos Compuestos o Estructurados

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;

2.4 Tipos Especiales

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.


2.5 Conversión de Tipos [PREGUNTA TÍPICA]

Conversión Implícita (Widening / Promoción)

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

Conversión Explícita (Casting / Narrowing)

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

PARTE III — OPERADORES

3. Operadores

3.1 Operadores Aritméticos

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 usar 7.0 / 2 o hacer casting: (double) 7 / 2.


3.2 Operadores Relacionales (Comparación)

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 ser false si son objetos distintos.


3.3 Operadores Lógicos

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

3.4 Operadores de Asignación

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

3.5 Operadores de Incremento/Decremento

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.


3.6 Operadores de Bits (Bitwise)

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).


3.7 Precedencia de Operadores (de mayor a menor) [MUY PREGUNTADO]

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.


PARTE IV — INSTRUCCIONES CONDICIONALES

4. Instrucciones Condicionales

4.1 Concepto

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.


4.2 IF / IF-ELSE / IF-ELSE IF

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")

4.3 SWITCH / CASE [PREGUNTA TÍPICA]

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";
};


4.4 Operador Ternario

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.


4.5 Evaluación en Cortocircuito [PREGUNTA DIFÍCIL]

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) { ... }

PARTE V — BUCLES Y RECURSIVIDAD

5. Bucles y Recursividad

5.1 Concepto de Bucle

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.


5.2 Bucle WHILE (mientras)

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


5.3 Bucle DO-WHILE (hacer-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: while puede ejecutarse 0 veces; do-while se ejecuta al menos 1 vez.


5.4 Bucle FOR (para)

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


5.5 Control de Bucles

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
}

5.6 Recursividad [MUY PREGUNTADO]

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.

Factorial (n!)

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;
}

Serie de Fibonacci

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

Traza de recursión — Factorial(4) [PREGUNTA TÍPICA]

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

Recursión vs Iteración [PREGUNTA TÍPICA]

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

Tipos de Recursión [PREGUNTA DIFÍCIL]

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

PARTE VI — PROCEDIMIENTOS, FUNCIONES Y PARÁMETROS

6. Procedimientos, Funciones y Parámetros

6.1 Concepto

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.


6.2 Procedimientos vs Funciones [PREGUNTA TÍPICA]

Característica Procedimiento Función
Devuelve valor No
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

6.3 Parámetros y Argumentos


6.4 Formas de Paso de Parámetros [MUY PREGUNTADO]

Por Valor (Pass by Value)

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

Por Referencia (Pass by Reference)

Se pasa la dirección de memoria. Cambios en la función 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
}

Por Nombre (Pass by Name)

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).


6.5 Ámbito (Scope) de Variables

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).


6.6 Recursividad en Funciones

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) o Segmentation Fault (C).


6.7 Sobrecarga de Funciones (Overloading)

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).


PARTE VII — VECTORES Y REGISTROS

7. Vectores y Registros

7.1 Vectores (Arrays)

Concepto

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.

Características

Declaración e Inicialización

// 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

Recorrido de un Vector

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 en un Vector [PREGUNTA TÍPICA]

// 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

Ordenación de un Vector [PREGUNTA TÍPICA]

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²)
Selección O(n²) O(n²) O(n²) No
Inserción O(n) O(n²) O(n²)
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)
HeapSort O(n log n) O(n log n) O(n log n) No

Arrays Multidimensionales (Matrices)

// 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();
}

7.2 Registros (Structs / Records)

Concepto

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).

Declaración y Uso en C

// 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);

Registros en Pascal

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.

Equivalente en Java (Clase sin métodos)

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;

7.3 Arrays de Registros

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);
}

7.4 Diferencias Clave: Vector vs Registro [PREGUNTA TÍPICA]

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

PARTE VIII — ESTRUCTURA DE UN PROGRAMA

8. Estructura de un Programa

8.1 Estructura General

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)
└─────────────────────────────┘

8.2 Estructura en Pseudocódigo

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

8.3 Estructura en C

/* ====== 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);
}

8.4 Estructura en Java

/* ====== 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;
    }
}

8.5 Estructura en Python

#!/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()

8.6 Fases de Ejecución de un Programa [PREGUNTA TÍPICA]

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.


8.7 Áreas de Memoria en Ejecución [PREGUNTA DIFÍCIL]

┌──────────────────────────────┐  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).


PARTE IX — PROGRAMACIÓN ORIENTADA A OBJETOS

9. Programación Orientada a Objetos

Esta sección es directamente derivada de las preguntas del examen real (preguntas 1 y 2 del TXT).

9.1 Conceptos Fundamentales [MUY PREGUNTADO]

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

9.2 Herencia [MUY PREGUNTADO — PREGUNTA REAL DEL EXAMEN]

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.


9.3 Clases y Objetos en Java/PHP

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());
    }
}

9.4 Ejemplo Completo con Modelo de Datos Real (Voto por Correo)

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();
    }
}

PARTE X — APIs RESTful Y SOAP

10. APIs RESTful y SOAP

Esta sección es directamente derivada de las preguntas 5, 6 y 7 del examen real.

10.1 Características de una API RESTful [MUY PREGUNTADO]

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 Obtener recurso(s)
POST Create No No Crear nuevo recurso
PUT Update No Actualizar recurso completo
PATCH Update No No Actualizar recurso parcialmente
DELETE Delete 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

10.2 Características de un Servicio SOAP [IMPORTANTE]

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>


10.3 Diferencias REST vs SOAP [MUY PREGUNTADO]

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

10.4 Implementación de Métodos REST [PREGUNTA REAL DEL EXAMEN]

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());
    }
}

10.5 JSON: Estructura y Manejo [PREGUNTA REAL DEL EXAMEN]

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
}

PARTE XI — ORM: HIBERNATE Y DOCTRINE

11. ORM: Hibernate y Doctrine

Derivado directamente de las preguntas 8 y 9 del examen real.

11.1 Concepto de ORM

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

11.2 Diferencias ORM vs Acceso Directo a BD [PREGUNTA REAL DEL EXAMEN]

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

11.3 Hibernate: Anotaciones y Configuración [PREGUNTA REAL DEL EXAMEN]

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

11.4 Doctrine (PHP)

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;
}

PARTE XII — ANÁLISIS DE EXAMEN Y EXTENSIONES

12. Conceptos que probablemente entren aunque no aparezcan en el título

12.1 Patrones de Diseño [IMPORTANTE]

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:

12.2 Interfaces en Java [IMPORTANTE]

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 */ }
}

12.3 Clases Abstractas [IMPORTANTE]

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)

12.4 Excepciones [PREGUNTA RECURRENTE]

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");
}

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)

12.5 Colecciones en Java [IMPORTANTE]

Colección Implementación Ordenada Duplicados Acceso
ArrayList Array dinámico Sí (índice) O(1)
LinkedList Lista enlazada 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)

12.6 Seguridad en Aplicaciones [IMPORTANTE]

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.


13. Conceptos relacionados que podrían ser preguntados por conexión temática

13.1 Bases de Datos y SQL

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).

13.2 Arquitectura de Aplicaciones

13.3 Metodologías de Desarrollo

13.4 Control de Versiones


14. Lista de Preguntas Tipo Test Potenciales

Bloque A — Lenguajes y Traductores:

  1. ¿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

  2. ¿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

  3. ¿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:

  1. ¿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

  2. ¿Cuántos bits ocupa un double según el estándar IEEE 754?
    - a) 32 — b) 64 — c) 128 — d) 16
    - Respuesta: b

  3. ¿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:

  1. ¿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

  2. ¿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

  3. ¿Cuál es la precedencia correcta (de mayor a menor)?
    - a) && > || > ! > * — b) ! > * > + > && > || — c) * > + > ! > || — d) + > * > && > !
    - Respuesta: b

Bloque D — Bucles y Recursividad:

  1. ¿Cuántas veces puede ejecutarse mínimo un bucle while?

    • a) 0 — b) 1 — c) 2 — d) Infinitas
    • Respuesta: a
  2. ¿Cuántas veces puede ejecutarse mínimo un bucle do-while?

    • a) 0 — b) 1 — c) 2 — d) Infinitas
    • Respuesta: b
  3. ¿Qué es imprescindible en una función recursiva para que no produzca Stack Overflow?

    • a) Llamarse a sí misma — b) Tener caso base — c) Usar variables globales — d) Ser un procedimiento
    • Respuesta: b

Bloque E — OOP y Herencia:

  1. En Java, ¿cuántas clases puede heredar una clase mediante extends?

    • a) Una sola — b) Dos — c) Ilimitadas — d) Solo clases abstractas
    • Respuesta: a
  2. ¿Cuántas interfaces puede implementar una clase en Java?

    • a) Solo una — b) Máximo dos — c) Múltiples — d) Ninguna
    • Respuesta: c
  3. ¿Qué anotación en Hibernate indica que una clase es una entidad persistente?

    • a) @Table — b) @Column — c) @Entity — d) @Id
    • Respuesta: c

Bloque F — REST y SOAP:

  1. ¿Cuál de los siguientes métodos HTTP es idempotente?

    • a) POST — b) PATCH — c) PUT — d) CONNECT
    • Respuesta: c
  2. REST es:

    • a) Un protocolo — b) Un estilo arquitectónico — c) Un formato de datos — d) Un lenguaje de marcado
    • Respuesta: b
  3. ¿Cuál es el formato de datos obligatorio en SOAP?

    • a) JSON — b) YAML — c) XML — d) CSV
    • Respuesta: c
  4. ¿Qué código HTTP se devuelve cuando un recurso no se encuentra?

    • a) 400 — b) 401 — c) 403 — d) 404
    • Respuesta: d
  5. ¿Cuál es una característica fundamental de REST en cuanto al estado?

    • a) Con estado (stateful) — b) Sin estado (stateless) — c) Requiere sesión en el servidor — d) Usa cookies obligatoriamente
    • Respuesta: b

15. Resumen para Oposición — Puntos Clave

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.