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 3

Pubblicato nel gruppo Random-IT
CIAO! Proprio come è impossibile imparare a pilotare un aereo senza una formazione specifica, non si può diventare uno sviluppatore Java senza dedicare lunghe ore allo studio delle basi teoriche necessarie. Ed è proprio su questo che lavoreremo oggi: continueremo ad esplorare le domande incontrate durante i colloqui di lavoro per sviluppatori Java e, ovviamente, esamineremo le risposte. Ecco la prima e la seconda parte di questa panoramica. Non c'è dubbio che puoi diventare un buon sviluppatore Java senza tutte queste domande. Detto questo, se hai una buona conoscenza di tutte le complessità di Java, avrai sicuramente un vantaggio e sembrerai più attraente agli occhi del tuo futuro datore di lavoro. Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 3 - 1

20. Quali elementi del linguaggio consentono l'incapsulamento?

Ricordiamo che l'incapsulamento consiste nel nascondere i dettagli di implementazione di una classe. In altre parole, quando viene utilizzata la nostra classe, le sue viscere e la sua logica interna non sono ovvie agli estranei. E quali elementi della lingua ne sono responsabili? I modificatori di accesso , ovviamente! Tutto ciò che dobbiamo nascondere, lo contrassegniamo con il modificatore private . Ad esempio, i campi privati ​​di una classe o alcuni metodi interni che aiutano a implementare alcune funzionalità interne. E per tutto ciò a cui vogliamo fornire accesso esterno, aggiungiamo il modificatore di accesso pubblico . Ad esempio, un metodo che implementa alcune funzionalità (che possono utilizzare internamente molti metodi privati) o, ovviamente, getter e setter per accedere ai campi privati ​​di una classe. Non abbiamo ancora menzionato i modificatori predefiniti e protetti , che possono essere utilizzati in modo più flessibile e personalizzare in modo specifico l'accesso a determinate parti della classe.

21. Quali elementi della lingua consentono l'ereditarietà?

L'ereditarietà è un meccanismo che consente di creare classi basate su un'altra classe. Java ha la parola chiave extends per questo. Ad esempio, supponiamo di avere una classe Gatto e di voler creare una classe figlia Leone . Nel codice, sarà simile a questo:
public class Lion extends Cat
Ciò significa che la classe Lion eredita tutti i metodi e le variabili della classe Cat , ad eccezione delle variabili statiche. Un altro elemento del linguaggio responsabile dell'ereditarietà è super . È un riferimento simile a questo . La parola chiave this si riferisce all'oggetto a cui viene fatto riferimento. La parola chiave super si riferisce al genitore dell'oggetto corrente. Tipicamente si usa super :
  1. Per chiamare il costruttore di una superclasse. Ad esempio, la classe Cat ha una variabile nome interna che deve essere inizializzata nel costruttore. Nel costruttore della classe Lion , sarà simile a questo:

    public Lion(final String name) {
       super(name);
    }

  2. Per fare riferimento ai campi e ai metodi del genitore. Ad esempio, nella classe Cat , abbiamo un campo età inizializzato:

    public class Cat {
       int age = 10;

Ma abbiamo lo stesso campo inizializzato in Lion :
public class Lion extends Cat {
   int age = 15;
E se in un oggetto Lion vogliamo fare riferimento alla variabile age dell'oggetto genitore, allora dobbiamo farlo tramite super :
super.name

22. Quali elementi della lingua sono responsabili del polimorfismo?

Il polimorfismo è la capacità di un oggetto con una firma di assumere molte forme (molte implementazioni). Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 3 - 2Possiamo affermare con sicurezza che le parole chiave implements ed extends di Java sono responsabili del polimorfismo. Quando abbiamo un'interfaccia, implements ci consente di fornire una possibile implementazione, ma questa non deve essere l'unica implementazione, vero? Rivisitiamo come appare l'utilizzo degli implementa :
public class Cat implements Animal
Quindi nella classe Cat dobbiamo implementare tutti i metodi astratti nell'interfaccia Animal . Anche l'ereditarietà: nella classe figlia possiamo sovrascrivere l'implementazione esistente di un metodo. Ciò significa che con più classi figlie possiamo avere diversi override dello stesso metodo. Oppure una superclasse può essere astratta e avere un certo metodo che deve essere implementato in modo speciale in ciascuna delle sue classi figlie. In altre parole, questo metodo avrà molte implementazioni diverse. Anche l' annotazione @Override può aiutarci in questo. È posizionato sopra i metodi implementati e indica che vogliamo implementare o sovrascrivere (se esiste già un'implementazione nella superclasse) un particolare metodo di una superclasse o di un'interfaccia. È facoltativo e aiuta a rilevare più facilmente gli errori. Si utilizza questa annotazione per indicare al compilatore che si desidera sovrascrivere/implementare il metodo della superclasse/interfaccia. Il compilatore si assicurerà quindi di non commettere errori nella firma del metodo.

23. Cos'è SOLIDO? Fornire esempi

SOLID è l'acronimo dei cinque principi base di progettazione OOP di Robert Martin. S (Principio di unica responsabilità) : afferma che una classe dovrebbe avere un solo scopo/responsabilità. In altre parole, non dovresti creare classi che facciano tutto. Se lo fai, potresti riprodurre l'anti-modello "Oggetto Dio". Se disponi di un oggetto Cat , dovrebbe avere metodi solo per interagire con le sue funzionalità interne, ma non dovrebbe contenere alcuna logica aziendale non correlata a tale istanza. Ad esempio, alcuni meccanismi per archiviare oggetti di questo tipo. Questa funzionalità (esterna all'entità di un Cat ) dovrebbe essere spostata su altre classi o servizi, il cui compito è fornire la logica di business per gli oggetti corrispondenti. O (Principio aperto-chiuso) : questo principio è descritto come segue: le entità software (classi, moduli, funzioni, ecc.) dovrebbero essere aperte per l'estensione ma chiuse per la modifica. Ad esempio, supponiamo di aver bisogno di funzionalità simili ma leggermente diverse dalla funzionalità della nostra classe Cat esistente . Invece di modificare la funzionalità della classe Cat e quindi interrompere il codice ovunque sia già utilizzato, possiamo utilizzare l'ereditarietà o la composizione . In questo modo raggiungiamo il nostro obiettivo di modificare la funzionalità della classe Cat , e lo facciamo senza modificare la classe stessa e senza rompere nulla. L (Principio di sostituzione di Liskov) : questo è il principio di sostituzione di Barbara Liskov. Il principio dice che una funzione che accetta un tipo base dovrebbe essere in grado di utilizzare i sottotipi di quel tipo base senza sapere cosa sta succedendo. Ad esempio, la nostra classe Gatto dovrebbe essere sostituibile con uno qualsiasi dei suoi discendenti, ad esempio Leone , senza modificarne radicalmente il comportamento. La logica generale (comportamento) rimane la stessa, ma cambiano i dettagli di implementazione di funzionalità specifiche. I (Principio di segregazione delle interfacce) : questo principio afferma che è meglio avere molte interfacce specializzate (localmente focalizzate) piuttosto che una universale. Ad esempio, supponiamo che uno sviluppatore implementi un'interfaccia. Necessitano solo di uno dei suoi metodi, ma l'interfaccia dispone di altri nove metodi che non si riferiscono alla logica del metodo richiesto. In questo caso, lo sviluppatore dovrà implementare dieci metodi di interfaccia, nove dei quali per lui superflui! Invece, è meglio creare dieci diverse interfacce che puoi implementare secondo necessità. Bene, se non dieci, almeno diversi, ciascuno con metodi strettamente correlati all'unico scopo dell'interfaccia. D (Principio di inversione di dipendenza): Il principio dice che i moduli di livello superiore non dovrebbero dipendere da moduli di livello inferiore. Questo principio afferma anche: "L'astrazione non dovrebbe dipendere dai dettagli. I dettagli dovrebbero dipendere dalle astrazioni". Dobbiamo costruire la nostra logica facendo riferimento alle interfacce e passare oggetti concreti di classi che implementano l'interfaccia richiesta. Ad esempio, supponiamo di avere un'interfaccia Cat e alcune implementazioni, ad esempio Lion e HouseCat . Costruiamo la nostra logica appositamente per interagire con l' interfaccia Cat . Solo allora sostituiamo l'interfaccia con un'implementazione specifica ( Lion o HouseCat ), ma non viceversa.

24. Cos'è una classe, un oggetto e un'interfaccia?

Ricorderemo che Java è un linguaggio OOP. Cioè, i programmi Java sono costruiti in base alle interazioni tra oggetti. Un programma è come un formicaio, dove ogni formica è un oggetto. Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 3 - 3Gli oggetti sono raccolte di dati che includono vari metodi (funzioni) per interagire con questi dati interni. Le classi sono istruzioni o modelli per la creazione di oggetti. Ciò significa che possiamo avere molti oggetti costruiti secondo le stesse istruzioni ma riempiti con dati diversi (o gli stessi). Prendendo un esempio dalla vita reale, possiamo dire che una classe è il progetto di un edificio e un oggetto è un edificio costruito appositamente secondo il progetto. Le interfacce sono simili alle classi, ma non possiamo usarle per creare oggetti. Il loro scopo è aggiungere astrazione a Java. Più precisamente, aggiungono flessibilità alla relazione tra classi e oggetti. Per flessibilità intendiamo il polimorfismo e l'astrazione descritti in precedenza, che creano molte opportunità per costruire l'architettura interna di un'applicazione.

25. Cos'è una lezione POJO? Fornisci un esempio di tale classe

Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 3 - 4Un POJO (Plain Old Java Object) è un semplice oggetto di classe che non eredita da alcuna classe specifica e non implementa alcuna interfaccia di servizio oltre a quelle necessarie per il modello di business. In altre parole, una classe POJO è semplicemente una classe senza requisiti speciali. L'unico requisito è l'assenza di vari fronzoli legati a un quadro specifico. Di norma, queste classi non ereditano altre classi (ad eccezione delle classi POJO nello stesso pacchetto), non implementano interfacce (a volte viene fatta un'eccezione per le interfacce marcatori della libreria standard come Serializable o Cloneable ), non utilizzano annotazioni e non dipendono da librerie di terze parti. Notiamo che un POJO può avere metodi contenenti logica di business e costruttori di qualsiasi tipo. Se consentiamo annotazioni che non modificano la semantica della classe (ovvero annotazioni la cui assenza non cambia lo scopo o la logica dell'oggetto), allora i POJO possono includere anche entità JPA e oggetti DTO deserializzati da XML o JSON , le cui regole sono specificato nelle annotazioni. Un'altra cosa da tenere a mente riguardo alle classi POJO è che è bene sovrascrivere i loro metodi equals e hashCode perché questo può aiutarli a svolgere meglio il loro ruolo. Esempio di una classe POJO :
public class User {
   private Long id;
   private String firstName;
   private String lastName;
   private Long age;

   public User(final Long id, final String firstName, final String lastName, final long age) {
       this.id = id;
       this.firstName = firstName;
       this.lastName = lastName;
       this.age = age;
   }

   public Long getId() {
       return this.id;
   }

   public String getFirstName() {
       return this.firstName;
   }

   public String getLastName() {
       return this.lastName;
   }

   public Long getAge() {
       return this.age;
   }

   @Override
   public boolean equals(final Object o) {
       if (this == o) return true;
       if (o == null || this.getClass() != o.getClass()) return false;
       final User user = (User) o;
       return Objects.equals(this.id, user.id) &&
               Objects.equals(this.firstName, user.firstName) &&
               Objects.equals(this.lastName, user.lastName) &&
               Objects.equals(this.age, user.age);
   }

   @Override
   public int hashCode() {
       return Objects.hash(this.id, this.firstName, this.lastName, this.age);
   }
}

26. Quali elementi può contenere una classe?

Una classe può contenere i seguenti elementi:
  • campi di istanza;
  • campi statici;
  • un blocco di inizializzazione;
  • un blocco di inizializzazione statico;
  • costruttori (un costruttore vuoto è sempre dichiarato per impostazione predefinita);
  • metodi;
  • metodi statici;
  • varie annotazioni (che possono essere applicate alla classe stessa o alle sue parti costitutive);
  • generici ;
  • ereditarietà di altre classi ( extends ) o implementazioni di interfacce ( implements ).

27. Parlaci dell'ereditarietà in Java. Quali sono le specifiche della super parola chiave?

Sopra, ho già parlato dell'ereditarietà e della parola chiave super in Java. Menzionerò alcuni punti più importanti:
  1. Possiamo ereditare solo una singola classe: Java non ha ereditarietà multipla in Java. Con l'avvento dei metodi predefiniti in Java 8, questa affermazione diventerà molto controversa.
  2. Anche i metodi e i campi privati ​​vengono ereditati. Semplicemente non è possibile accedervi dalla classe figlia (ma se, ad esempio, abbiamo un campo privato e abbiamo getter e setter pubblici o protetti , allora possiamo usarli per accedere al campo).
  3. le classi finali non possono essere ereditate.
  4. i metodi final non possono essere sovrascritti (ma possono essere ereditati e sovraccaricati).
  5. i metodi e le variabili statiche non vengono ereditate (perché sono collegate alle classi, non agli oggetti).
  6. Quando si ereditano classi astratte, i relativi metodi astratti devono essere implementati oppure anche la classe figlia deve essere dichiarata astratta.
  7. Se sono presenti costruttori non predefiniti nella classe genitore, devono essere sovrascritti nella classe figlia (ma @Override non è scritto sopra di essi).
  8. È possibile estendere il modificatore di accesso ai metodi sovrascritti nella classe figlia: private -> default -> protected -> public .
  9. I metodi sovrascritti nella classe figlia possono generare eccezioni più ristrette, ad esempio: Exception -> IOException -> FileNotFoundException.
Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 3 - 5

28. Cosa sono le firme dei metodi? Fornire esempi di firme corrette e errate

Una firma del metodo è il nome del metodo più i tipi dei parametri di input (l'ordine dei parametri è importante). La firma del metodo non include il valore restituito o le eccezioni generate dal metodo. Esempio di firma corretta:
doSomething(int, double, double)
Esempio di firma errata:
void doSomething(int firstArg, int secondArg) throws Exception
La firma del metodo, combinata con il tipo restituito e l'elenco delle eccezioni generate, è chiamata contratto del metodo . È tutto per oggi! Arrivederci!
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION