JavaRush /Java-Blog /Random-DE /Analyse von Fragen und Antworten aus Interviews für Java-...

Analyse von Fragen und Antworten aus Interviews für Java-Entwickler. Teil 4

Veröffentlicht in der Gruppe Random-DE
Hallo zusammen, heute analysiere ich weiterhin über 250 Interviewfragen für Java-Entwickler. Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 1Vorherige Teile der Analyse: erster , zweiter , dritter . Also machen wir weiter.

29. Ist es möglich, return in einem Konstruktor zu verwenden?

Sie können, aber ohne den Rückgabewert rechts von return . Das heißt, Sie können return verwenden; als Hilfskonstruktion bei Berechnungen im Konstruktor, um die Ausführung weiteren Codes dringend zu beenden (unterbrechen) und die Initialisierung des Objekts abzuschließen. Zum Beispiel haben wir eine Klasse Cat , und wenn Cat obdachlos ist - isHomeless = true , müssen wir die Initialisierung abschließen und dürfen keine anderen Felder ausfüllen (schließlich sind sie uns unbekannt, da die Katze obdachlos ist):
public Cat(int age, String name, boolean isHomeless) {
   if (isHomeless){
       this.isHomeless = isHomeless;
       return;
   }
   this.isHomeless = isHomeless;
   this.age = age;
   this.name = name;
}
Wenn es jedoch um bestimmte Werte geht, kann ein Konstruktor Return nicht verwenden, um einen Wert zurückzugeben, weil:
  • Wenn Sie einen Konstruktor deklarieren, haben Sie nichts, was einem Rückgabetyp ähnelt.
  • Normalerweise wird der Konstruktor während der Instanziierung implizit aufgerufen;
  • Ein Konstruktor ist keine Methode: Es handelt sich um einen separaten Mechanismus, dessen einziger Zweck darin besteht, Instanzvariablen zu initialisieren, und der neue Operator ist für die Erstellung eines Objekts verantwortlich .
Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 2

30. Ist es möglich, eine Ausnahme von einem Konstruktor auszulösen?

Konstruktoren behandeln Ausnahmen genauso wie Methoden. Und wenn uns Methoden erlauben, Ausnahmen auszulösen, indem wir throws <ExceptionType> in den Methodenheader schreiben , dann ermöglicht uns der Konstruktor dies, und auch beim Erben und Definieren eines Erbkonstruktors können wir den Ausnahmetyp erweitern. Zum Beispiel IOException -> Exception (aber nicht umgekehrt). Als Beispiel für das Auslösen einer Ausnahme durch einen Konstruktor nehmen wir die Cat- Klasse . Nehmen wir an, dass wir beim Erstellen den Namen und das Alter über die Konsole eingeben möchten:
public Cat() throws IOException {
   BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   this.name = reader.readLine();
   this.age = Integer.parseInt(reader.readLine());
}
Da Reader.readLine() eine IOException auslöst, geben wir diese im Header als mögliche ausgelöste Ausnahme an.

31. Aus welchen Elementen besteht der Klassenheader? Schreiben Sie ein Beispiel

Wenn wir über die Elemente sprechen, aus denen der Klassenheader besteht, schauen wir uns ein kleines Diagramm an:
  • Pflichtbestandteile stehen in Klammern <>
  • optional – in {}
{Klassenzugriffsmodifikator}{Klassenstatizität}{Klassenendgültigkeit}{Klassenabstraktion} <Klassenname>{Vererbung von der übergeordneten Klasse} {Schnittstellenimplementierung} Was wir also haben: {Klassenzugriffsmodifikator} – für die Klasse sind nur die öffentlichen Modifikatoren und der fehlende Zugriffsmodifikator, also default , verfügbar . {class static}static ist ein Modifikator, der angibt, dass diese Klasse statisch ist und nur auf innere Klassen (Klassen innerhalb anderer Klassen) anwendbar ist. {Klassenfinalität} – wie wir uns erinnern, ist dies der letzte Modifikator , bei dessen Vorhandensein die Klasse nicht vererbbar wird (Beispiel aus der Box – String ). {Klassenabstraktion} – Modifikator – abstrakt , was darauf hinweist, dass diese Klasse möglicherweise nicht implementierte Methoden hat. Dieser Modifikator steht im Konflikt mit dem endgültigen Modifikator , d. h. nur einer von ihnen kann im Klassenheader enthalten sein, da der abstrakte Modifikator impliziert, dass die gegebene Klasse geerbt wird und ihre abstrakten Teile implementiert werden. Und final gibt an, dass dies die endgültige (endgültige) Version der Klasse ist und nicht vererbt werden kann. Eigentlich wäre die gleichzeitige Verwendung beider Modifikatoren absurd und der Compiler erlaubt uns dies nicht. <class> ist ein erforderliches Schlüsselwort, das eine Klassendeklaration angibt. <Klassenname> ist ein einfacher Klassenname, der die Kennung einer bestimmten Java-Klasse darstellt. Der vollständig qualifizierte Klassenname besteht aus dem vollständig qualifizierten Paketnamen + . + einfacher Klassenname. {Inheritance from Parent class} – Angabe der übergeordneten Klasse (falls vorhanden) mithilfe des Schlüsselworts „extends“ . Beispielsweise erweitert .. ParentClass . {Schnittstellenimplementierung} – Angabe der Schnittstellen, die diese Klasse (falls vorhanden) mithilfe des Schlüsselworts „implementiert “ implementiert . Zum Beispiel: ... implementiert FirstInterface, SecondInterface ... Nun, als Beispiel für einen Klassenheader betrachten wir den Header der Lion -Klasse, die von Cat erbt und die WildAnimal- Schnittstelle implementiert :
public final class Lion extends Cat implements WildAnimal
Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 3

32. Aus welchen Elementen besteht der Methodenheader? Schreiben Sie ein Beispiel

Betrachten Sie beim Betrachten der Elemente, aus denen ein Methodenheader besteht, erneut ein kleines Diagramm, in dem Folgendes gilt:
  • Pflichtbestandteile stehen in Klammern <>
  • optional – in {}
{Zugriffsmodifikator}{Methode statisch}{Methodenabstraktion}{Methodenendgültigkeit}{Synchronisationsmodifikator} {nativer Modifikator}<Rückgabewert><Methodenname> <(> {Methodenargumente} <)>{ausgelöste Ausnahmen} {Zugriffsmodifikator } — Alle Zugriffsmodifikatoren sind für die Methode verfügbar: public , protected , default , private . {method static}static ist ein Modifikator, der angibt, dass diese Methode statisch ist, das heißt, sie ist nicht an ein Objekt, sondern an eine Klasse gebunden. {Methodenabstraktion} ist der abstrakte Modifikator , der angibt, dass es keine Implementierung (Körper) der Methode gibt. Für den korrekten Betrieb benötigen Sie außerdem einen abstrakten Modifikator für die Klasse, in der die Methode bereitgestellt wird. Wie im Klassenheader steht dieser Modifikator im Konflikt mit dem endgültigen Modifikator , aber zusätzlich auch im Konflikt mit dem statischen Modifikator , weil Eine abstrakte Methode impliziert das Überschreiben der Methode im Nachkommen, und statische Methoden werden nicht überschrieben. {Finalität der Methode}final – ein Modifikator, der angibt, dass diese Methode nicht überschrieben werden kann. {Synchronisationsmodifikator}synchronisiert – ein Modifikator, der bedeutet, dass diese Methode vor dem gleichzeitigen Zugriff verschiedener Threads auf sie geschützt ist. Wenn die Methode nicht statisch ist, wird sie auf diesem Mutex des Objekts geschlossen. Wenn die Methode statisch ist, wird sie auf dem Mutex der aktuellen Klasse geschlossen. {native modifier}native – dieser Modifikator gibt an, dass die Methode in einer anderen Programmiersprache geschrieben ist. <Rückgabewert> ist der Werttyp, den die Methode zurückgeben soll. Wenn es nichts zurückgeben sollte, void . <Methodenname> ist der Name der Methode, ihre Kennung im System. {Methodenargumente} sind die Argumente (Parameter), die die Methode benötigt: Sie sind notwendig, um ihre Funktionalität zu implementieren. {auslösbare Ausnahmen}throwsExceptionType – eine Liste geprüfter Ausnahmen, die diese Methode auslösen kann. Und als Beispiel für einen Methodenheader gebe ich Folgendes:
public static void main(String[] args) throws IOException

33. Erstellen Sie einen Standardkonstruktor im Nachkommenobjekt, wenn dieser nicht im Basisobjekt definiert ist (aber ein anderer Konstruktor definiert ist).

Ich verstehe die Frage selbst nicht ganz, aber vielleicht bedeutet sie, dass wir zum Beispiel im übergeordneten Element einen benutzerdefinierten Konstruktor haben:
public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Daher müssen wir in der Vorfahrenklasse unbedingt einen Konstruktor definieren, der den übergeordneten Konstruktor füllt (aufruft):
public  class Lion extends Cat {

   public Lion(int age, String name) {
       super(age, name);
   }
}
Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 4

34. Wann wird das Schlüsselwort this verwendet?

In Java hat dies zwei verschiedene Bedeutungen. 1. Als Referenz auf das aktuelle Objekt, etwa this.age = 9 . Das heißt, this bezieht sich auf das Objekt, für das es aufgerufen wurde und auf das der Code, der this verwendet, verweist . Die Hauptfunktion besteht darin, die Lesbarkeit des Codes zu verbessern und Mehrdeutigkeiten zu vermeiden. Wenn beispielsweise der Name des internen Klassenfelds und das Methodenargument identisch sind:
public void setName(String name) {
   this.name = name;
}
Das heißt, this.name ist ein Feld des Objekts name ist ein Methodenargument. Die this- Referenz kann nicht in statischen Methoden verwendet werden. 2. Dies kann in einem Konstruktor in Form eines Methodenaufrufs wie this(value) verwendet werden . In diesem Fall handelt es sich um einen Aufruf eines anderen Konstruktors derselben Klasse. Kurz gesagt, Sie können beim Erstellen eines Objekts zwei Konstruktoren gleichzeitig aufrufen:
public Cat(int age, String name) {
   this(name);
   this.age = age;
}

public Cat(String name) {
   this.name = name;
}
Wenn ein Cat- Objekt erstellt und der erste Konstruktor aufgerufen wird, werden beide Felder des Objekts aufgerufen und erfolgreich initialisiert. Es gibt ein paar Nuancen:
  1. this() funktioniert nur im Konstruktor.
  2. Ein Verweis auf einen anderen Konstruktor muss in der ersten Zeile des Konstruktorblocks (Body) stehen. Daher kann in einem Konstruktor nicht mehr als ein (anderer) Konstruktor einer bestimmten Klasse aufgerufen werden.
Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 5Weitere Beispiele finden Sie in diesem Artikel .

35. Was ist ein Initialisierer?

Soweit ich weiß, sprechen wir in dieser Frage über gewöhnliche und statistische Initialisierungsblöcke. Erinnern wir uns zunächst daran, was Initialisierung ist. Initialisierung ist Erstellung, Aktivierung, Arbeitsvorbereitung, Bestimmung von Parametern. Ein Programm oder eine Komponente in einen einsatzbereiten Zustand versetzen. Wie Sie sich erinnern, kann eine Klassenvariable während der Objekterstellung direkt bei der Deklaration initialisiert werden:
class Cat {
   private int age = 9;
   private  String name = "Tom";
Oder legen Sie es extern über einen Konstruktor fest:
class Cat {
   private int age;
   private  String name;

   public Cat(int age, String name) {
       this.age = age;
       this.name = name;
   }
Aber es gibt noch eine andere Möglichkeit: eine interne Objektvariable über einen Initialisierungsblock festzulegen, der wie geschweifte Klammern { } innerhalb der Klasse aussieht, ohne Namen (wie eine Methode oder ein Konstruktor):
class Cat {
   private int age;
   private  String name;

   {
       age = 10;
       name = "Tom";
   }
Das heißt, ein Initialisierungsblock ist ein Codestück, das geladen wird, wenn ein Objekt erstellt wird. Typischerweise werden solche Blöcke verwendet, um einige komplexe Berechnungen durchzuführen, die beim Laden einer Klasse erforderlich sind. Die Ergebnisse dieser Berechnungen können als Werte für Variablen angegeben werden. Zusätzlich zu den regulären Initialisierungsblöcken gibt es auch statische Blöcke, die gleich aussehen, aber das Schlüsselwort static vor der geschweiften Klammer haben :
class Cat {
   private static int age;
   private static String name;

   static{
       age = 10;
       name = "Tom";
   }
Dieser Block ist genau derselbe wie der vorherige. Wenn jedoch die reguläre Funktion bei der Initialisierung jedes Objekts ausgelöst wird, wird die statische Funktion nur einmal ausgelöst, wenn die Klasse geladen wird. In einem solchen Block werden in der Regel auch einige komplexe Berechnungen für die anschließende Initialisierung statischer Klassenvariablen durchgeführt. Für einen statischen Block gelten die gleichen Einschränkungen wie für statische Methoden: Er kann keine nicht statischen Daten sowie einen Verweis auf das aktuelle Objekt verwenden – this . Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 6Als nächstes können wir die Reihenfolge der Initialisierung der Klasse (zusammen mit ihrem Vorfahren) sehen, um besser zu verstehen, wann die Initialisierungsblöcke ausgelöst werden.

36. Um eine öffentliche Klasse zu erben, die die Klasse Child erweitert, schreiben Sie die Reihenfolge der Initialisierung des Objekts

Wenn die Child-Klasse geladen ist, lautet die Initialisierungsreihenfolge wie folgt:
  1. Statische Felder der Parent- Klasse .
  2. Statischer Initialisierungsblock für die übergeordnete Klasse .
  3. Statische Felder der Child- Klasse .
  4. Statischer Initialisierungsblock für die Child- Klasse .
  5. Nicht statische Felder der Parent- Klasse .
  6. Kein statischer Initialisierungsblock für die Parent- Klasse .
  7. Konstruktor für die Parent- Klasse .
  8. Nicht statische Felder der Child- Klasse .
  9. Kein statischer Initialisierungsblock für die Child- Klasse .
  10. Konstruktor der Child- Klasse .
Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 7Hier ist ein kurzer Artikel, der die Initialisierungsreihenfolge in der Praxis erklärt.

37. Welche Beziehungen kennen Sie zwischen Klassen (Objekten)?

In Java gibt es zwei Arten von Beziehungen zwischen Klassen:
  • IS-A- Beziehung
Das IS-A-Prinzip in OOP basiert auf Klassenvererbung oder Schnittstellenimplementierung. Wenn beispielsweise die Klasse Lion von Cat erbt , sagen wir, dass Lion Cat ist :
Lion IS-A Cat
(aber nicht jede Katze ist ein Löwe ) Genauso verhält es sich mit Schnittstellen. Wenn die Lion- Klasse die WildAnimal- Schnittstelle implementiert , stehen sie auch in einer Beziehung:
Lion IS-A WildAnimal
  • HAS-A- Beziehungen
Diese Art von Beziehung basiert auf der Nutzung von Klassen durch andere Klassen, auch „Assoziation“ genannt. Eine Assoziation ist eine Klasse, die auf eine andere Klasse (oder sogar aufeinander) verweist. Beispielsweise könnte sich die Klasse „Car“ auf die Klasse „Passagier“ beziehen , und dies wäre die Beziehung:
Car HAS-A Passenger
Und umgekehrt: Wenn Passenger einen Verweis auf Car hat , dann ist dies die Beziehung:
Passenger HAS-A Car

38. Welche assoziativen Verbindungen zwischen Objekten kennen Sie?

Aggregation und Zusammensetzung sind nichts anderes als Sonderfälle der Assoziation. Aggregation ist eine Beziehung, bei der ein Objekt Teil eines anderen ist. Beispielsweise kann sich ein Passagier in einem Auto befinden. Außerdem kann es mehrere oder gar keine Passagiere geben (wenn es sich um einen Tesla handelt, ist der Fahrer nicht erforderlich). Zum Beispiel:
public class Car {
   private List passengers = new ArrayList<>();

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

   void move() {
       for (Passenger passenger : passengers) {
           System.out.println("Перевозка пассажира - " + passenger.toString());
       }
       passengers.clear();
   }
}
Das heißt, die Anzahl der Passagiere (oder ob es überhaupt welche gibt) ist uns egal: Die Funktionalität der Car- Klasse hängt davon nicht ab. Aggregation impliziert auch, dass, wenn ein Objekt von einem anderen Objekt verwendet wird, das erste Objekt in anderen Objekten verwendet werden kann. Beispielsweise kann derselbe Schüler sowohl Mitglied eines Strickclubs als auch einer Musikgruppe von Rockern sein und gleichzeitig zu einer Gruppe von Englischlernern gehen. Wie Sie wissen, handelt es sich bei der Aggregation um eine lockerere assoziative Beziehung zwischen Klassen. Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 8Die Komposition ist eine noch starrere Beziehung, wenn ein Objekt nicht nur Teil eines anderen Objekts ist, sondern die Arbeit des anderen Objekts stark vom ersten Objekt abhängt. Zum Beispiel ein Automotor. Obwohl der Motor ohne das Auto existieren mag, ist er außerhalb davon nutzlos. Nun, ein Auto kann nicht ohne Motor funktionieren:
public class Car {
   private Engine engine;

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

   void startMoving() {
       engine.start();
           ...
   }
Zusammensetzung impliziert auch, dass, wenn ein Objekt von einem anderen Objekt verwendet wird, das erste keinem anderen gehören kann. Wenn wir zu unserem Beispiel zurückkehren, kann ein Motor nur zu einem Auto gehören, nicht jedoch zu zwei oder mehreren gleichzeitig. Wir werden heute wahrscheinlich hier anhalten.Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 4 - 9
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION