CodeGym /Java Blog /Random-IT /Esplorazione di domande e risposte da un colloquio di lav...
John Squirrels
Livello 41
San Francisco

Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java. Parte 8

Pubblicato nel gruppo Random-IT
Pratica o teoria? Cosa è più importante? Molte persone diranno naturalmente che la pratica è più importante. Ad esempio, esercitati fino al tramonto e sarai felice. Oserò non essere d'accordo con questo. Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 8 - 1Durante le interviste, nessuno saprà mai quanto sei forte mentre ti alleni. Ti verrà invece chiesto di dimostrare le tue nozioni teoriche. Solo più tardi, quando avrai superato tutti i livelli dei colloqui e sarai assegnato a un progetto, applicherai le tue abilità pratiche. Potresti obiettare, dicendo che a volte ti danno un compito di prova, quindi la pratica è ancora necessaria. Non sono in disaccordo, ma il mio punto è che A VOLTE, ma devi SEMPRE dimostrare la conoscenza della teoria in un colloquio. Senti la differenza? Tutto ciò significa che è necessario avere solide basi teoriche sotto i piedi, ed è ciò che continueremo a costruire oggi. Più nello specifico, continueremo ad esaminare le domande che spesso vengono poste nelle interviste.

71. Cosa succede se non sovrascriviamo il metodo toString() di Enum?

Supponiamo di avere la seguente enumerazione :
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;
}
Visualizziamo il campo STUDENT sulla console chiamando il suo metodo toString() :
System.out.println(Role.STUDENT.toString());
Di conseguenza, otteniamo il seguente output della console:
ALUNNO
Pertanto, vediamo che per un enum , l'implementazione predefinita di toString() restituisce il nome della costante stessa.

72. Puoi dichiarare un costruttore all'interno di un Enum?

Sì, naturalmente. Il costruttore è ciò che imposta i valori dei campi interni di enum . Ad esempio, aggiungiamo due campi all'enumerazione precedente ( ageFrom e ageTo ) per indicare la fascia di età per ciascun ruolo:
public enum Role {
   STUDENT(5,18),
   TEACHER(20,60),
   DIRECTOR(40,70),
   SECURITY_GUARD(18,50);

   int ageFrom;
   int ageTo;

   Role(int ageFrom, int ageTo) {
       this.ageFrom = ageFrom;
       this.ageTo = ageTo;
   }
}

73. Qual è la differenza tra == e equals()?

Questa è una delle domande più comuni poste nei colloqui agli aspiranti sviluppatori Java. Per cominciare, quando confrontiamo valori semplici ( int , char , double ...), usiamo == , poiché queste variabili contengono valori concreti che possono essere confrontati direttamente. Inoltre, le variabili primitive non sono oggetti a tutti gli effetti: non ereditano la classe Object e non hanno un metodo equals() . Se parliamo di confrontare variabili che si riferiscono a oggetti, allora dobbiamo sapere che == confronta solo il valore dei riferimenti, cioè se si riferiscono o meno allo stesso oggetto. Anche se tutti i dati in un oggetto sono identici a tutti i dati in un altro, utilizzando == per un confronto si otterrà un risultato negativo ( false ), poiché si tratta di oggetti separati. Come avrai intuito, utilizziamo il metodo equals() per confrontare le variabili di riferimento. Questo è uno dei metodi standard della classe Object ed è necessario per un confronto completo degli oggetti. Ma devo dire subito che affinché questo metodo funzioni correttamente è necessario sovrascriverlo per indicare esattamente come devono essere confrontati gli oggetti. Se non esegui l'override del metodo, otterrai l'implementazione predefinita, che confronta gli oggetti utilizzando == . In IntelliJ IDEA, puoi sovrascriverlo automaticamente utilizzando una scorciatoia IDEA: Alt+Insert . Nella finestra che appare, seleziona equals() e hashCode() . Quindi seleziona i campi che dovrebbero essere coinvolti. Ecco! I metodi vengono implementati automaticamente. Ecco un esempio di come un metodo equals generato automaticamente cerca la classe Cat più semplice possibile con due campi: int age e String name :
@Override
public boolean equals(final Object o) {
   if (this == o) return true;
   if (o == null || this.getClass() != o.getClass()) return false;
   final Cat cat = (Cat) o;
   return this.age == cat.age &&
           Objects.equals(this.name, cat.name);
}
Quando si tratta di enum , non c'è una differenza pratica tra == e equals() . Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 8 - 2Dopotutto, un'enumerazione memorizza costanti e, anche quando confrontiamo valori identici utilizzando == , otterremo true , poiché i riferimenti confrontati punteranno sempre agli stessi oggetti. E anche l'uso di equals() ci dà il risultato corretto. Se entri nel corpo del metodo equals per Enum , vedrai che la classe EnumEsplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 8 - 3 ha la seguente implementazione: All'interno possiamo vedere un buon vecchio confronto di riferimenti! Per riassumere, per enum s, possiamo confrontare correttamente utilizzando sia == che equals() . Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 8 - 4

74. Cosa fa il metodo ordinal() di Enum?

Quando chiamiamo il metodo int ordinal() su un campo enum , otteniamo l'indice in base zero del campo nell'elenco dei valori enum. Chiamiamo questo metodo su un campo dell'enumerazione Role , che abbiamo considerato in precedenza:
System.out.println(Role.DIRECTOR.ordinal());
Di conseguenza, la console visualizza:
2

75. Enum può essere utilizzato con TreeSet o TreeMap in Java?

Possiamo utilizzare i tipi enum in TreeSet e TreeMap . E possiamo scrivere questo:
TreeSet<Role> treeSet = new TreeSet<>();
treeSet.add(Role.SECURITY_GUARD);
treeSet.add(Role.DIRECTOR);
treeSet.add(Role.TEACHER);
treeSet.add(Role.STUDENT);
treeSet.forEach(System.out::println);
E la console mostrerà:
DIRETTORE STUDENTE INSEGNANTE SECURITY_GUARD
Abbiamo ottenuto l'output, ma non in ordine alfabetico. Il punto è che se utilizziamo i campi enum come valori TreeSet o come chiavi TreeMap , i campi vengono ordinati nel loro ordine naturale (nell'ordine in cui sono specificati in enum ) . Capire che è così che funziona ci aiuta a scrivere codice migliore.

76. Come sono correlati i metodi ordinal() e compareTo() di Enum?

Come accennato in precedenza, ordinal() restituisce l'indice di un campo nell'elenco dei campi enum. Inoltre, nella nostra considerazione della domanda precedente, hai visto che quando i campi enum vengono inseriti in un TreeSet (che è un insieme ordinato), assumono l'ordine in cui sono dichiarati in enum . E come sappiamo, TreeSet e TreeMap ordinano gli elementi chiamando il metodo compareTo() della loro interfaccia Comparable . Questo ci dice che la classe Enum implementa l' interfaccia Comparable , il che significa che implementa il metodo compareTo() , che utilizza internamente il metodo ordinal() per determinare l'ordinamento. Entrando nella classe Enum , possiamo confermare la nostra ipotesi: Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 8 - 5Ed ecco il corpo del metodo stesso: Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 8 - 6Il metodo ordinal() non viene chiamato qui. Viene invece utilizzata la variabile ordinale , che è il numero di indice dell'elemento nell'enumerazione. Lo stesso metodo ordinal()Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 8 - 7 non è altro che un getter per la variabile ordinale .

77. Scrivi un esempio Enum

Nelle domande discusse sopra, ho già fornito esempi di enum s. Non vedo alcun motivo per duplicare il codice qui. Ad esempio, vedere la domanda 72 riguardante un costruttore in un'enumerazione.

78. È possibile utilizzare un Enum in un caso di switch?

Può e dovrebbe essere! Osservando la mia esperienza, noterò che uno degli usi più comuni di enum è nei costrutti logici come le istruzioni switch . In questo caso, puoi fornire tutti i casi possibili : una volta scritta la logica per ciascun campo enum , non avrai nemmeno bisogno di una clausola predefinita ! Dopotutto, se usi String o un valore numerico, come un int , potresti ricevere un valore inaspettato, ma ciò è impossibile con un enum . Ecco come apparirebbe un'istruzione switch per l'esempio precedente:
public void doSomething(Role role) {
   switch (role) {
       case STUDENT:
           // some logic for STUDENT
           break;
       case TEACHER:
           // some logic for TEACHER
           break;
       case DIRECTOR:
           // some logic for DIRECTOR
           break;
       case SECURITY_GUARD:
           // some logic for SECURITY_GUARD
           break;
   }
}

79. Come posso ottenere tutti i possibili valori di un Enum?

Se è necessario ottenere tutti i possibili valori enum, esiste un metodo value() , che restituisce un array di tutti i possibili valori per l' enum nel loro ordine naturale (ovvero nell'ordine in cui sono specificati in enum ). Esempio:
Role[] roles = Role.values();
for (Role role : roles) {
   System.out.println(role);
}
Avremo quanto segue sulla console:
DIRETTORE STUDENTE INSEGNANTE SECURITY_GUARD

API di flusso

80. Cos'è uno stream in Java?

L' API Java Stream è un modo relativamente nuovo di interagire con un flusso di dati, consentendoci di elaborare i big data in modo più pratico e compatto, nonché di elaborare i dati in parallelo tra un certo numero di flussi, aumentando potenzialmente le prestazioni.

81. Nomina le principali proprietà delle transazioni

L'argomento qui è l'API Stream, ma la domanda riguarda le transazioni. Hmm... Innanzitutto, capiamo cos'è una transazione. Una transazione è un gruppo di operazioni sequenziali su un database. Rappresenta un'unità logica di lavoro. Una transazione può essere eseguita indipendentemente da altre transazioni simultanee o completamente e con successo, mantenendo così l'integrità dei dati, oppure non eseguita affatto, nel qual caso non ha alcun effetto. Le transazioni hanno quattro proprietà principali, che possiamo facilmente ricordare grazie all'acronimo ACID . Vediamo cosa significa ciascuna lettera di questo acronimo: A sta per Atomicity . Questa proprietà garantisce che nessuna transazione venga parzialmente impegnata nel sistema. Verranno eseguite tutte le sue sottooperazioni oppure nessuna di esse ( all or Nothing ). С sta per Coerenza . Questa proprietà garantisce che ogni transazione riuscita commetterà solo risultati validi. In altre parole, questa è una garanzia che, se la transazione ha esito positivo, tutte le regole del sistema per dati specifici verranno rispettate. Se la transazione non va a buon fine, non verrà eseguita e i dati del sistema torneranno allo stato precedente. I sta per Isolamento . Questa proprietà fa sì che quando una transazione viene eseguita, le transazioni concorrenti non devono influenzarne l'esito. Questa proprietà richiede molte risorse, quindi, di norma, è parzialmente implementata, consentendo determinati livelli di isolamento che risolvono problemi di isolamento specifici. Ne discuteremo più in dettaglio nella prossima domanda. D sta per Durabilità . Questa proprietà garantisce che se l'utente riceve la conferma che la transazione è stata completata, allora può essere sicuro che le modifiche non verranno annullate a causa di qualche errore. Cioè, puoi essere certo che qualche errore del sistema operativo non avrà alcun effetto sui tuoi dati se hai già ricevuto la conferma che la transazione è stata completata con successo.

82. Quali sono i livelli di isolamento delle transazioni?

Come ho detto prima, quando si tratta di proprietà ACID, garantire l'isolamento è un processo che richiede molte risorse. Di conseguenza, questa proprietà è parzialmente implementata. Esistono diversi livelli di isolamento: più alto è il livello, più grave è l'impatto sulle prestazioni. Prima di passare ai livelli di isolamento delle transazioni, dobbiamo considerare vari problemi che si verificano a causa di un isolamento insufficiente delle transazioni :
  • letture fantasma : quando la stessa richiesta, richiamata più volte all'interno di una stessa transazione, dà risultati diversi a causa di inserimenti da parte di un'altra transazione;

  • letture non ripetibili : quando la stessa richiesta, richiamata più di una volta all'interno di una singola transazione, restituisce dati diversi a causa di modifiche (aggiornamenti) e cancellazioni da parte di un'altra transazione;

  • letture sporche : lettura di dati non ancora impegnati che sono stati aggiunti o modificati da una transazione e successivamente sottoposti a rollback;

  • aggiornamenti persi : quando un blocco di dati viene modificato simultaneamente da diverse transazioni e tutte le modifiche tranne l'ultima vengono perse (simile a una condizione di competizione nel multithreading).

In realtà, i livelli di isolamento delle transazioni sono caratterizzati dai problemi di isolamento da cui proteggono. Considera la seguente tabella dei livelli di isolamento e dei problemi da cui proteggono:
Livello di isolamento Il fantasma legge Letture non ripetibili Letture sporche Aggiornamento perso
SERIALIZZABILE + + + +
LETTURA RIPETIBILE - + + +
LEGGI IMPEGNO - - + +
LEGGI SENZA IMPEGNO - - - +
NESSUNO - - - -
E non dimenticare il rovescio della medaglia: maggiore è il livello di isolamento, maggiore sarà il tempo necessario per l'elaborazione delle transazioni (data l'esecuzione parallela di più transazioni).

83. Qual è la differenza tra uno Statement e un PreparedStatement?

Qui abbiamo cambiato bruscamente la transizione alle funzionalità di JDBC . In ogni caso, vediamo prima di cosa si tratta . È un oggetto utilizzato per formare query SQL. JDBC utilizza tre tipi: Statement , PreparedStatement e CallableStatement . Non prenderemo in considerazione CallableStatement oggi. Stiamo invece parlando della differenza tra Statement e PreparedStatement .
  1. L'istruzione viene utilizzata per eseguire semplici query SQL senza parametri di input di runtime. PrepareStatement può accettare parametri di input in fase di esecuzione.

  2. Per impostare i parametri per PreparedStatement , i parametri di input vengono scritti come punti interrogativi nella richiesta, in modo che possano essere sostituiti da qualche valore utilizzando vari setter, come setDouble() , setFloat() , setInt() , setTime() ... Questo significa che non inserirai il tipo di dati sbagliato nella richiesta.

  3. PreparedStatement è precompilato e utilizza la memorizzazione nella cache, quindi può essere eseguito leggermente più velocemente di una richiesta composta da oggetti Statement . Di conseguenza, le istruzioni SQL eseguite frequentemente vengono create come oggetti PreparedStatement per migliorare le prestazioni.

  4. L'istruzione è vulnerabile all'iniezione SQL, ma PreparedStatement le impedisce.

E con questo chiudiamo qui!
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION