JavaRush /Java Blog /Random-IT /Analisi di domande e risposte da interviste per sviluppat...

Analisi di domande e risposte da interviste per sviluppatori Java. Parte 3

Pubblicato nel gruppo Random-IT
Ciao! Così come è impossibile imparare a pilotare un aereo senza una formazione specifica, è anche impossibile diventare uno sviluppatore Java senza dedicare lunghe ore allo studio delle basi teoriche necessarie. Oggi lavoreremo proprio su questo: continueremo ad analizzare oltre 250 domande di intervista per sviluppatori Java e, di conseguenza, le risposte ad esse. Ecco la prima e la seconda parte dell'analisi. Sì, certo, puoi diventare un buon sviluppatore Java senza tutte queste domande. Tuttavia, se hai una buona conoscenza dei dettagli del linguaggio Java, questo ti darà un vantaggio, rendendoti un candidato più desiderabile agli occhi del tuo futuro datore di lavoro.Analisi di domande e risposte da interviste per sviluppatori Java.  Parte 3 - 1

20. Quali elementi linguistici sono responsabili dell'incapsulamento?

Come ricordiamo, l'incapsulamento nasconde i dettagli di implementazione di una classe. Cioè, quando la nostra classe viene utilizzata esternamente, i contenuti interni e la logica non sono ovvi. E quali elementi del linguaggio ne sono responsabili? Naturalmente, modificatori di accesso ! Contrassegniamo ciò che dobbiamo nascondere con il modificatore private . Ad esempio, campi privati ​​di una classe o alcuni metodi interni che aiutano a implementare determinate funzionalità interne. E a ciò a cui vogliamo fornire l'accesso esterno, aggiungiamo il modificatore di accesso pubblico . Ad esempio, un metodo responsabile di fornire alcune funzionalità (all'interno delle quali possono essere utilizzati molti metodi privati) o gli stessi getter e setter per accedere ai campi privati ​​di una classe. Oh, e abbiamo anche i modificatori predefiniti e protetti , che possono essere utilizzati per una configurazione più flessibile e specifica dell'accesso a parti selezionate della classe.

21. Quali elementi linguistici sono responsabili dell'ereditarietà?

L'ereditarietà è un meccanismo che consente di creare classi basate su un'altra classe. In Java, la parola chiave extends viene utilizzata a questo scopo . Ad esempio, abbiamo una certa classe Cat e vogliamo creare il suo successore: Lion . Nel codice sarà simile a questo:
public class Lion extends Cat
E questo significa che la classe Lion eredita tutti i metodi e le variabili della classe Cat , tranne quelle statiche. Inoltre, gli elementi linguistici responsabili dell'ereditarietà includono super . Questo è un riferimento simile a this , ma mentre questo si riferisce all'oggetto su cui è stato chiamato, super si riferisce all'oggetto genitore corrente. Tipicamente si usa super :
  1. Per chiamare un costruttore di superclasse: ad esempio, la classe Cat ha un nome di variabile interna che deve essere inizializzata nel costruttore. Nel costruttore della classe Lion sarebbe simile a questo:

    public Lion(final String name) {
       super(name);
    }
  2. Per accedere ai campi e ai metodi genitore: ad esempio, nella classe Cat abbiamo un campo age inizializzato :

    public class Cat {
       int age = 10;
Allo stesso tempo, abbiamo lo stesso campo inizializzato in Lion :
public class Lion extends Cat {
   int age = 15;
E se vogliamo accedere alla variabile age dell'oggetto genitore dall'oggetto Lion , dobbiamo farlo tramite super :
super.name

22. Quali elementi del linguaggio sono responsabili del polimorfismo?

Il polimorfismo è la capacità di un oggetto con una firma di assumere molte forme (implementazioni multiple). Possiamo tranquillamente affermare che in Java le parole chiave implements ed extendsAnalisi di domande e risposte da interviste per sviluppatori Java.  Parte 3 - 2 sono responsabili del polimorfismo . implements - quando creiamo la nostra interfaccia, implementiamo una delle sue possibili forme in qualche classe, ma non è l'unica forma, vero? Ricordiamo come si presentano gli strumenti di implementazione :
public class Cat implements Animal
E nella classe Cat dobbiamo implementare tutti i metodi astratti presentati nell'interfaccia Animal . Lo stesso vale per l'ereditarietà: in una classe discendente possiamo sovrascrivere un'implementazione già esistente di un metodo. Ad esempio: diversi discendenti -> diversi override diversi dello stesso metodo. Ebbene, o la superclasse era astratta e ha un certo metodo che deve essere implementato in modo speciale per ciascuno dei suoi discendenti. Possiamo cioè dire che il metodo assumerà molte forme. Inoltre, ci può aiutare l'annotazione @Override this , che è posizionata sopra i metodi implementati e indica che vogliamo implementare o sovrascrivere (se l'implementazione esiste già nella superclasse) uno o un altro metodo della superclasse o dell'interfaccia. È facoltativo e viene utilizzato per facilitare il rilevamento degli errori. Con questa annotazione indichi al compilatore che desideri sovrascrivere/implementare un metodo di superclasse/interfaccia e ti assicurerai di non commettere errori nella firma del metodo.

23. Cos'è SOLIDO? Dare esempi

SOLID è l'acronimo di Five Basic Design Principles for OOP, coniato da Robert Martin. S - Principio di responsabilità unica - il principio di responsabilità unica, che afferma che una classe dovrebbe avere un solo obiettivo e un unico scopo. Cioè, non dovresti creare classi che facciano tutto. In questo caso puoi riprodurre l’antipattern “Oggetto Divino”. Se disponi di un oggetto Cat , dovrebbe contenere metodi che interagiscono solo con la sua funzionalità interna e non con la logica aziendale che non è rilevante per questa istanza. Ad esempio, una sorta di salvataggio di oggetti di questo tipo da qualche parte. Questa funzionalità esterna (relativa a Cat ) deve essere trasferita ad altre classi, alcuni servizi il cui compito è fornire la logica di business per oggetti di questo tipo. O - Principio aperto-chiuso - principio di apertura/chiusura. Ciò significa che le entità software (classi, interfacce) dovrebbero essere aperte all'estensione, ma chiuse alla modifica. Ad esempio, avevamo bisogno di funzionalità simili a quelle della classe Cat già esistente , ma leggermente diverse. Invece di modificare la funzionalità della classe Cat , interrompendo i punti in cui è già utilizzata, utilizziamo l'ereditarietà o la composizione . Di conseguenza, abbiamo raggiunto il nostro obiettivo con la funzionalità modificata della classe Gatto , ma allo stesso tempo non l'abbiamo modificata né rotto nulla. L - Principio di sostituzione di Liskov - Principio di sostituzione di Barbara Liskov. Il principio afferma che una funzione che utilizza un tipo base dovrebbe essere in grado di utilizzare sottotipi del tipo base senza saperlo. Ad esempio, la nostra classe Gatto dovrebbe essere intercambiabile con qualsiasi dei suoi discendenti, ad esempio Leone , senza modificare sostanzialmente il comportamento. La logica generale (comportamento) rimane la stessa, ma cambiano i dettagli dell'implementazione di questa o quella funzionalità. I - Principio di segregazione dell'interfaccia - il principio della separazione dell'interfaccia. Questo principio afferma che è meglio avere molte interfacce specializzate (localmente focalizzate) piuttosto che una universale. Ad esempio, un utente implementa un'interfaccia di cui ha bisogno solo questo metodo, ma questa interfaccia ha altri nove metodi che non hanno nulla a che fare con la logica del metodo desiderato. In questo caso, l'utente dovrà implementare dieci metodi di interfaccia, nove dei quali non sono necessari per lui! È meglio invece realizzare dieci diverse interfacce che possono essere implementate se necessario. Bene, o non dieci, ma diversi, che avranno metodi strettamente correlati allo scopo comune dell'interfaccia. D - Principio di inversione delle dipendenze— il principio dell'inversione di dipendenza. Il principio afferma che i moduli ai livelli più alti non dovrebbero dipendere dai moduli ai livelli più bassi. Questo principio è anche descritto come “l’astrazione non dovrebbe dipendere dai dettagli, i dettagli dovrebbero dipendere dall’astrazione”. Dobbiamo cioè costruire la nostra logica facendo riferimento alle interfacce e solo successivamente passare a questa funzionalità oggetti specifici, le cui classi implementano l'interfaccia richiesta. Ad esempio, se abbiamo un'interfaccia Cat e alcune delle sue implementazioni, ad esempio Lion e HomeCat , costruiamo la nostra logica di interazione specificatamente con il tipo di interfaccia Cat e solo successivamente sostituiamo un'implementazione specifica di Lion o HomeCat , ma non viceversa.

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

Come ricordiamo, Java è un linguaggio OOP. Cioè, i programmi Java si basano sull'interazione tra oggetti. Si scopre che il programma è come un formicaio, dove ogni formica è un oggetto. Analisi di domande e risposte da interviste per sviluppatori Java.  Parte 3 - 3Gli oggetti sono alcuni dati raggruppati che contengono vari metodi (funzioni) per interagire con questi dati interni. E le classi sono istruzioni, modelli per creare oggetti. Cioè, possono esserci molti oggetti costruiti secondo la stessa istruzione, riempiti con valori di dati diversi o identici. Per fare un esempio dalla vita, possiamo dire che una classe è un disegno di un edificio e un oggetto è un edificio creato appositamente sulla base di questo disegno. Le interfacce sono analoghi alle classi con la differenza che non è possibile creare oggetti utilizzandole. Il loro obiettivo è aggiungere un elemento di astrazione a Java. Più precisamente, per aggiungere flessibilità nelle relazioni tra classi e oggetti. Per flessibilità intendiamo il polimorfismo e l'astrazione descritti in precedenza, che a loro volta aprono molte opportunità per costruire l'architettura interna dell'applicazione.

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

Analisi di domande e risposte da interviste per sviluppatori Java.  Parte 3 - 4POJO - Plain Old Java Object - un buon vecchio oggetto Java: un semplice oggetto di una classe che non è ereditato 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, tali classi non ereditano da altre classi (ad eccezione delle classi POJO dello 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. Ma noto che i POJO possono avere metodi con logica di business e costruttori di qualsiasi tipo. Se si consentono annotazioni che non apportano modifiche alla semantica della classe (senza le quali lo scopo dell'oggetto e la logica del suo funzionamento non cambieranno), i POJO possono includere anche entità JPA Entity e oggetti DTO deserializzati da XML o JSON , le cui regole sono specificate nelle annotazioni. È inoltre consigliabile sovrascrivere equals e hashCode per le classi POJO , poiché ciò potrebbe aiutarli a svolgere meglio il loro ruolo. Esempio di 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?

La classe può contenere i seguenti elementi:
  • campi di classe;
  • campi di classi statiche;
  • blocco di inizializzazione;
  • blocco di inizializzazione statica;
  • costruttori (vuoto è sempre definito per impostazione predefinita);
  • metodi;
  • metodi statici;
  • varie annotazioni (che possono essere appese sopra la classe stessa o i suoi componenti);
  • generici ;
  • eredità da altre classi ( extends ) o implementazione da interfacce ( implements ).

27. Spiegare l'ereditarietà in Java. Quali sono i vantaggi dell’utilizzo della parola chiave super?

Sopra ho già parlato dell'ereditarietà e della super parola chiave in Java. Vorrei menzionare alcuni punti più importanti:
  1. È possibile ereditare una sola classe: in Java non esiste l'ereditarietà multipla (ma 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 avranno accesso ad essi dall'erede (ma se, ad esempio, abbiamo un campo privato e ci sono getter e setter pubblici o protetti per esso, è possibile lavorare con il campo attraverso loro).
  3. le classi finali non vengono ereditate.
  4. i metodi finali non vengono sovrascritti (ma possono essere ereditati e sovraccaricati).
  5. i metodi e le variabili statiche non vengono ereditate (poiché non sono legate agli oggetti, ma alle classi).
  6. Quando si eredita da classi astratte, è richiesta l'implementazione dei relativi metodi astratti oppure anche la classe corrente deve essere dichiarata astratta.
  7. Se sono presenti costruttori non predefiniti nel genitore, devono essere sovrascritti nella classe figlia (ma @Override non viene scritto su di essi).
  8. I metodi sottoposti a override nel discendente possono essere estesi con un modificatore di accesso: private -> default -> protected -> public .
  9. I metodi sottoposti a override nel discendente possono restringere le eccezioni scritte, ad esempio: Exception -> IOException -> FileNotFoundException.
Analisi di domande e risposte da interviste per sviluppatori Java.  Parte 3 - 5

28. Cos'è una firma del metodo? Fornisci esempi di firme corrette e errate

La firma di un metodo è il nome del metodo più i tipi dei parametri in entrata (e l'ordine dei parametri è importante). La firma del metodo non include il valore restituito o le eccezioni generate. Esempio di firma corretta:
doSomething(int, double, double)
Un 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!Analisi di domande e risposte da interviste per sviluppatori Java.  Parte 3 - 6
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION