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 4

Pubblicato nel gruppo Random-IT
Ciao a tutti! Oggi continuo la mia revisione delle domande del colloquio per sviluppatori Java. Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 4 - 1

29. È possibile utilizzare return in un costruttore?

Sì, ma solo senza valore a destra della parola chiave return . Puoi usare return; come istruzione di supporto in un costruttore per terminare (interrompere) urgentemente l'esecuzione di ulteriore codice e completare l'inizializzazione dell'oggetto. Ad esempio, supponiamo di avere una classe Cat e se un Cat è senza casa ( isHomeless = true , allora vogliamo terminare l'inizializzazione e non compilare gli altri campi (dopo tutto, ci sono sconosciuti, poiché il gatto è senza casa) :
public Cat(int age, String name, boolean isHomeless) {
   if (isHomeless){
       this.isHomeless = isHomeless;
       return;
   }
   this.isHomeless = isHomeless;
   this.age = age;
   this.name = name;
}
Ma se parliamo di valori concreti, la parola chiave return non può restituire un valore specifico perché:
  • quando dichiari un costruttore, non avrai nulla di simile al tipo restituito;
  • di norma, il costruttore viene chiamato implicitamente durante l'istanziazione;
  • il costruttore non è un metodo: è un meccanismo separato il cui unico scopo è inizializzare le variabili di istanza, ovvero utilizziamo l' operatore new per creare un oggetto.
Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 4 - 2

30. È possibile lanciare un'eccezione da un costruttore?

I costruttori funzionano con le eccezioni allo stesso modo dei metodi. I metodi ci consentono di generare eccezioni scrivendo Throws <ExceptionType> nell'intestazione del metodo. E i costruttori ci permettono di fare lo stesso. Quando ereditiamo e definiamo il costruttore di una classe figlia, possiamo ampliare il tipo di eccezione, ad esempio IOException -> Eccezione (ma non viceversa). Usiamo il costruttore della classe Cat come esempio di costruttore che lancia un'eccezione. Diciamo che quando creiamo un oggetto, vogliamo inserire il nome e l'età da console:
public Cat() throws IOException {
   BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   this.name = reader.readLine();
   this.age = Integer.parseInt(reader.readLine());
}
Poiché reader.readLine() lancia una IOException, la scriviamo nell'intestazione come una possibile eccezione lanciata.

31. Quali sono gli elementi di un'intestazione di classe? Scrivi un esempio

Per illustrare gli elementi che compongono un'intestazione di classe, diamo un'occhiata a un piccolo schema:
  • gli elementi obbligatori compaiono tra parentesi <>
  • gli elementi facoltativi sono in {}
{modificatore di accesso}{statico}{final}{abstract<nome classe>{ereditarietà della classe genitore}{implementazione delle interfacce} Quindi , quello che abbiamo: {modificatore di accesso} — solo i modificatori di accesso pubblico e predefinito sono disponibili per classe. {statico} : il modificatore static indica che questa classe è statica; si applica solo alle classi interne (classi all'interno di altre classi). {final} — questo è il modificatore finale , ovviamente, che rende la classe non ereditabile (un esempio pronto all'uso è String ). {abstract} — il modificatore abstract , che indica che la classe potrebbe avere metodi non implementati. Questo modificatore è in conflitto con il modificatore finale . L'intestazione della classe può averne solo uno poiché il modificatore astratto significa che la classe verrà ereditata e i suoi elementi astratti verranno implementati. Ma final indica che questa è la versione finale della classe e che non può essere ereditata. In realtà, utilizzare contemporaneamente entrambi i modificatori sarebbe assurdo. Il compilatore non ci permetterà di farlo. <class> è una parola chiave obbligatoria che indica una dichiarazione di classe. <nome classe> è un nome di classe semplice che diventa l'identificatore di una classe Java specifica. Il nome completo della classe è costituito dal nome completo del pacchetto più '.' più il semplice nome della classe. {ereditarietà della classe genitore} è un'indicazione della classe genitore (se presente) utilizzando la parola chiave extends . Ad esempio, ... estende ParentClass . {implementazione delle interfacce} — un elenco delle interfacce che questa classe implementa (se presenti), utilizzando la parola chiave implements . Ad esempio: ... implementa FirstInterface, SecondInterface ... Ad esempio, considera l'intestazione della classe Lion , che eredita Cat e implementa l' interfaccia WildAnimal :
public final class Lion extends Cat implements WildAnimal
Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 4 - 3

32. Quali sono gli elementi di un'intestazione di metodo? Scrivi un esempio

Quando consideriamo gli elementi che compongono un'intestazione di metodo, consideriamo ancora un piccolo schema:
  • gli elementi obbligatori compaiono tra parentesi <>
  • gli elementi facoltativi sono in {}
{modificatore di accesso}{statico}{abstract}{final}{sincronizzato} {nativo} <valore restituito><nome metodo> <(>{parametri del metodo}<}>{throw eccezioni} {modificatore di accesso}: tutti i modificatori di accesso sono disponibile per il metodo — public , protected , default , private . {static} — il modificatore statico , che indica che il metodo è statico e quindi associato alla classe, non a un oggetto. {abstract} — il modificatore abstract , che indica che il metodo non ha implementazione (corpo). Per funzionare correttamente, la classe che dichiara il metodo deve avere anche il modificatore abstract . Come nell'intestazione della classe, questo modificatore è in conflitto con il modificatore finale e anche con il modificatore statico , perché un Il metodo astratto implica la sovrascrittura del metodo in un discendente e i metodi statici non possono essere sovrascritti. {finale} — il modificatore finale , che indica che questo metodo non può essere sovrascritto. {synchronized} — il modificatore sincronizzato , il che significa che il metodo è protetto da accesso simultaneo ad esso da diversi thread. Se il metodo non è statico, viene chiuso per il mutex this dell'oggetto. Se il metodo è statico, viene chiuso per il mutex della classe corrente. {native} : il modificatore nativo indica che il metodo è scritto in un altro linguaggio di programmazione. <tipo restituito> : il tipo del valore che il metodo deve restituire. Se il metodo non restituisce nulla, allora void . <nome metodo> — il nome del metodo, ovvero il suo identificatore nel sistema. {parametri del metodo} — i parametri che il metodo accetta: sono necessari per implementare la sua funzionalità. {eccezioni lanciate}lancia <ExceptionType> — un elenco delle eccezioni verificate che questo metodo può lanciare. Offrirò quanto segue come esempio di intestazione del metodo:
public static void main(String[] args) throws IOException

33. Crea un costruttore predefinito in una classe figlia se non ne è già definito uno nella classe base (ma è definito un costruttore diverso)

Non sono sicuro di aver compreso appieno la domanda, ma forse significa che abbiamo un costruttore come questo nella classe genitore:
public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
In tal caso, nella classe genitore, dobbiamo assolutamente definire un costruttore che inizializzerà il genitore (cioè chiamerà il costruttore genitore):
public class Lion extends Cat {

   public Lion(int age, String name) {
       super(age, name);
   }
}
Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 4 - 4

34. Quando viene utilizzata la parola chiave this?

In Java, questo ha due significati diversi. 1. È un riferimento all'oggetto corrente, ad esempio this.age = 9 . Cioè si riferisce all'oggetto in cui viene utilizzato e al quale si riferisce il codice con questo . Lo scopo principale è migliorare la leggibilità del codice ed evitare ambiguità. Ad esempio, se un campo di istanza e un argomento di metodo hanno lo stesso nome:
public void setName(String name) {
   this.name = name;
}
Cioè this.name è il campo dell'oggetto, mentre name è il parametro del metodo. Il riferimento this non può essere utilizzato nei metodi statici. 2. Nel costruttore, questo può essere chiamato come un metodo, ad esempio this(value) . In questo caso si tratterà di una chiamata ad un altro costruttore della stessa classe. Fondamentalmente, puoi chiamare due costruttori durante il processo di creazione di un oggetto:
public Cat(int age, String name) {
   this(name);
   this.age = age;
}

public Cat(String name) {
   this.name = name;
}
Quando si chiama il primo costruttore per creare un oggetto Cat , entrambi i campi di istanza verranno inizializzati correttamente. Ci sono un paio di sfumature qui:
  1. this() funziona solo in un costruttore.
  2. Un riferimento a un altro costruttore deve trovarsi nella prima riga del blocco costruttore (corpo). Ciò significa che un costruttore non può chiamare più di un (altro) costruttore della sua classe.
Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 4 - 5

35. Cos'è un inizializzatore?

Per quanto ho capito, questa domanda riguarda i blocchi di inizializzazione ordinari e statici. Ricordiamo innanzitutto cos'è l'inizializzazione. L'inizializzazione consiste nella creazione, attivazione, preparazione e definizione dei campi. Preparare un programma o un componente affinché sia ​​pronto per l'uso. Ricorderai che quando crei un oggetto, una variabile di classe può essere inizializzata immediatamente quando viene dichiarata:
class Cat {
   private int age = 9;
   private String name = "Tom";
Oppure impostato a posteriori tramite il costruttore:
class Cat {
   private int age;
   private String name;

   public Cat(int age, String name) {
       this.age = age;
       this.name = name;
   }
Ma c'è un altro modo: puoi impostare una variabile di istanza utilizzando un blocco di inizializzazione, che assume la forma di parentesi graffe {} all'interno di una classe, senza nome (come un metodo o costruttore senza nome):
class Cat {
   private int age;
   private String name;

   {
       age = 10;
       name = "Tom";
   }
Un blocco di inizializzazione è un pezzo di codice che viene caricato quando viene creato un oggetto. Tali blocchi vengono generalmente utilizzati per eseguire determinati calcoli complessi richiesti quando viene caricata una classe. I risultati di questi calcoli possono essere impostati come valori delle variabili. Oltre ai normali blocchi di inizializzazione, ce ne sono di statici. Sembrano uguali ma hanno la parola chiave statica davanti alla parentesi graffa di apertura:
class Cat {
   private static int age;
   private static String name;

   static{
       age = 10;
       name = "Tom";
   }
Questo blocco è uguale al precedente. Ma se quello ordinario viene eseguito quando ciascun oggetto viene inizializzato, quello statico viene eseguito solo una volta, quando la classe viene caricata. Di norma, alcuni calcoli complessi vengono eseguiti in un blocco statico, utilizzato per inizializzare le variabili di classe statiche. A un blocco statico si applicano le stesse restrizioni che si applicano ai metodi statici: non è possibile utilizzare dati non statici, come un riferimento all'oggetto corrente ( this ) in un blocco statico. Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 4 - 6Ora possiamo osservare l'ordine di inizializzazione della classe (insieme alla sua classe genitore) per capire meglio quando vengono invocati esattamente i blocchi di inizializzazione.

36. Data una classe Child pubblica che estende Parent, scrivere l'ordine di inizializzazione dell'oggetto

Quando si carica la classe Child , l'ordine di inizializzazione sarà il seguente:
  1. Campi di classe statici della classe Parent .
  2. Blocco di inizializzazione statico della classe Parent .
  3. Campi statici della classe Child .
  4. Blocco di inizializzazione statico della classe Child .
  5. Campi non statici della classe Parent .
  6. Blocco di inizializzazione non statico della classe Parent .
  7. Costruttore della classe genitore .
  8. Campi non statici della classe Child .
  9. Blocco di inizializzazione non statico della classe Child .
  10. Il costruttore della classe Child .
Esplorazione di domande e risposte da un colloquio di lavoro per una posizione di sviluppatore Java.  Parte 4 - 7

37. Che tipo di relazioni tra classi (oggetti) conosci?

Esistono due tipi di variabili in Java: tipi primitivi e riferimenti a oggetti completi.
  • Relazioni IS-A
Il principio IS-A dell'OOP si basa sull'ereditarietà delle classi o sull'implementazione delle interfacce. Ad esempio, se la classe Lion eredita Cat , allora diciamo che Lion è un Cat :
Lion IS-A Cat
(ma non tutti i gatti sono un leone ) La stessa situazione esiste con le interfacce. Se la classe Lion implementa l' interfaccia WildAnimal , allora esistono anche nella relazione:
Lion IS-A WildAnimal
  • Ha una relazione
Questo tipo di relazione è quella in cui una classe utilizza altre classi, chiamata anche "associazione". Un'associazione è una classe che fa riferimento a un'altra classe (o riferimenti reciproci tra loro). Ad esempio, la classe Car può fare riferimento alla classe Passenger , che costituirebbe la seguente relazione:
Car HAS-A Passenger
E viceversa: se Passenger ha un riferimento a Car , allora questa sarà la relazione:
Passenger HAS-A Car

38. Quali relazioni oggettuali associative conosci?

Aggregazione e composizione non sono altro che casi particolari di associazione. L'aggregazione è una relazione in cui un oggetto è parte di un altro. Ad esempio, un passeggero potrebbe trovarsi in un'auto. Inoltre, potrebbero esserci più passeggeri o nessuno (e se parliamo di Tesla, potrebbe non esserci alcun conducente). Per esempio:
public class Car {
   private List passengers = new ArrayList<>();

 void setPassenger(Passenger passenger) {
     passengers.add(passenger);
 }

   void move() {
       for (Passenger passenger : passengers) {
           System.out.println("Transporting passenger - " + passenger.toString());
       }
       passengers.clear();
   }
}
In altre parole, per noi il numero dei passeggeri (qualsiasi) non è importante: la funzionalità della classe Auto non dipende da questo. L'aggregazione implica anche che quando un altro oggetto utilizza un oggetto, il primo oggetto può essere utilizzato da altri oggetti. Ad esempio, lo stesso studente potrebbe far parte sia di un club di maglieria che di un gruppo rock e contemporaneamente frequentare un corso di spagnolo. Come puoi immaginare, l'aggregazione è una relazione associativa più flessibile tra le classi. La composizione è una relazione ancora più stretta in cui un oggetto non è solo parte di un altro oggetto, ma il lavoro di un oggetto dipende molto da un altro. Ad esempio, un'auto ha un motore. Un motore può esistere senza un’auto, ma è inutile al di fuori di un’auto. E un'auto non può funzionare senza motore:
public class Car {
   private Engine engine;

   public Car(Engine engine) {
       this.engine = engine;
   }

   void startMoving() {
       engine.start();
           ...
   }
La composizione implica anche che quando un altro oggetto utilizza un oggetto, il primo oggetto non può appartenere a nessun altro oggetto. Tornando al nostro esempio, un motore può appartenere solo ad una vettura, non a due o più contemporaneamente. Penso che per oggi sia sufficiente quindi ci fermiamo qui.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION