Colloquio Tecnico Java — Cheat Sheet

Tag: java, jvm, spring, multithreading, collections, backend

Livello: intermedio

TL;DR: Schema rapido su architettura JVM, gestione della memoria, costrutti di concorrenza, collezioni fondamentali e framework Spring per sostenere colloqui tecnici backend.

Concetti chiave

La JVM gestisce memoria, garbage collection e traduzione del bytecode in codice macchina nativo.

Heap memory ospita tutti gli oggetti instanziati ed è condivisa tra i thread.

Stack memory conserva frame di metodi, variabili primitive e riferimenti locali specifici di ciascun thread.

String è immutabile; le modifiche creano nuovi oggetti a meno di usare StringBuilder o StringBuffer.

Il Garbage Collector individua oggetti non raggiungibili tramite algoritmi basati su analisi di raggiungibilità dalle GC Roots.

Il contratto equals e hashCode impone che oggetti uguali secondo equals debbano produrre lo stesso hash intero.

HashMap distribuisce le chiavi in bucket usando hashCode e gestisce le collisioni tramite linked list e alberi Red-Black.

L'astrazione di Spring IoC Container gestisce ciclo di vita e dipendenze dei bean tramite Dependency Injection.

Le annotazioni @Transactional sfruttano Spring AOP per intercettare chiamate pubbliche e gestire commit o rollback transazionali.

I thread pool creati tramite ExecutorService ottimizzano il riuso dei thread del sistema operativo evitando costosi overhead di creazione.

Domande tipiche e risposte pronte

Q: Qual è la differenza sostanziale tra Heap e Stack in Java?R: Lo Stack alloca memoria veloce per l'esecuzione dei metodi e riferimenti locali del singolo thread; lo Heap conserva gli oggetti veri e propri ed è condiviso globalmente.

Q: Come funziona internamente una HashMap in Java 8+?R: Memorizza elementi in un array di bucket calcolando l'hash della chiave. In caso di collisioni multiple oltre una soglia, converte la lista concatenata in albero Red-Black per garantire ricerca in tempo logaritmico.

Q: Perché il rispetto del contratto tra equals() e hashCode() è cruciale?R: Se sovrascrivo equals senza allineare hashCode, collezioni come HashSet o HashMap non riescono a ritrovare elementi equivalenti perché finiscono in bucket errati.

Q: Come funziona il meccanismo di Dependency Injection in Spring?R: Delega la creazione e l'iniezione delle dipendenze al container IoC, che risolve i bean tramite annotazioni come @Autowired o iniezione via costruttore.

Q: Qual è la differenza tra fail-fast e fail-safe negli iteratori?R: Un iteratore fail-fast lancia subito ConcurrentModificationException se la collezione viene modificata durante l'iterazione; un iteratore fail-safe lavora su un clone della struttura dati.

Q: Cosa comporta dichiarare una variabile volatile?R: Garantisce che ogni lettura e scrittura avvenga direttamente nella memoria centrale anziché nelle cache locali dei singoli core della CPU, assicurando visibilità immediata tra thread.

Insidie e errori comuni

Rompere il contratto equals/hashCode alterando il comportamento di lookup in strutture hash.

Usare la concatenazione operatore + su String dentro loop intensivi provocando allocazioni eccessive nello Heap.

Invocare un metodo annotato con @Transactional dall'interno della stessa classe bypassando il proxy AOP di Spring.

Dimenticare di gestire contesti concorrenti riutilizzando istanze SimpleDateFormat, non thread-safe rispetto a java.time.format.DateTimeFormatter.

Modificare una Collection standard durante un ciclo for-each senza passare dal metodo remove() dell'iteratore.

Catturare genericamente Throwable o sopprimere InterruptedException resettando impropriamente il flag di interruzione del thread.

Snippet e comandi

// Implementazione corretta del contratto equals e hashCode
public record Utente(Long id, String email) {
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Utente utente)) return false;
        return Objects.equals(id, utente.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Java

// Configurazione ThreadPool con ExecutorService
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<String> task = executor.submit(() -> {
    return "Elaborazione completata";
});
String risultato = task.get();
executor.shutdown();

Da ripassare

[ ] Garbage collector moderni: G1, ZGC e Shenandoah.

[ ] Differenza pratica tra interfacce funzionali Predicate, Function, Supplier e Consumer.

[ ] Meccanismi di locking ad alte prestazioni nel package java.util.concurrent.locks.

[ ] Propagazione delle transazioni in Spring: REQUIRED vs REQUIRES_NEW.

[x] Gerarchia delle eccezioni tra Checked e Unchecked.

[x] Principi SOLID applicati allo sviluppo ad oggetti.

Riferimenti

Java Language and Virtual Machine Specifications

Effective Java (Joshua Bloch)

Documentazione ufficiale Spring Framework e Spring Boot

Jarvis Interviews
Jarvis