CodeGym /Java-Blog /Random-DE /Erkundung der Fragen und Antworten aus einem Vorstellungs...
John Squirrels
Level 41
San Francisco

Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler. Teil 4

Veröffentlicht in der Gruppe Random-DE
Hallo zusammen! Heute setze ich meine Überprüfung der Interviewfragen für Java-Entwickler fort. Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 4 - 1

29. Kann return in einem Konstruktor verwendet werden?

Ja, aber nur ohne Wert rechts vom Schlüsselwort return . Sie können return verwenden ; als Hilfsanweisung in einem Konstruktor, um die Ausführung weiteren Codes dringend zu beenden (unterbrechen) und die Initialisierung des Objekts abzuschließen. Angenommen, wir haben eine Cat- Klasse und wenn eine Katze obdachlos ist ( isHomeless = true , dann möchten wir die Initialisierung beenden und die anderen Felder nicht 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 sich jedoch um konkrete Werte handelt, kann das Schlüsselwort „return“ keinen bestimmten Wert zurückgeben, weil:
  • Wenn Sie einen Konstruktor deklarieren, haben Sie nichts Vergleichbares wie den Rückgabetyp.
  • In der Regel wird der Konstruktor bei der Instanziierung implizit aufgerufen;
  • Der Konstruktor ist keine Methode: Es handelt sich um einen separaten Mechanismus, dessen einziger Zweck darin besteht, Instanzvariablen zu initialisieren. Das heißt, wir verwenden den neuen Operator, um ein Objekt zu erstellen.
Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 4 - 2

30. Kann ein Konstruktor eine Ausnahme auslösen?

Konstruktoren arbeiten mit Ausnahmen auf die gleiche Weise wie Methoden. Mit Methoden können wir Ausnahmen auslösen, indem wir throws <ExceptionType> in den Methodenheader schreiben. Und Konstrukteure ermöglichen es uns, dasselbe zu tun. Wenn wir den Konstruktor einer untergeordneten Klasse erben und definieren, können wir den Ausnahmetyp erweitern – zum Beispiel IOException -> Exception (aber nicht umgekehrt). Lassen Sie uns den Konstruktor der Cat- Klasse als Beispiel für einen Konstruktor verwenden, der eine Ausnahme auslöst. Nehmen wir an, dass wir beim Erstellen eines Objekts 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, schreiben wir diese als mögliche ausgelöste Ausnahme in den Header.

31. Was sind die Elemente eines Klassenheaders? Schreiben Sie ein Beispiel

Um die Elemente zu veranschaulichen, aus denen ein Klassenheader besteht, schauen wir uns ein kleines Schema an:
  • Pflichtelemente erscheinen in Klammern <>
  • optionale Elemente sind in {}
{Zugriffsmodifikator}{statisch}{final}{abstract}<Klassenname>{Vererbung der übergeordneten Klasse}{Implementierung von Schnittstellen} Was wir also haben: {Zugriffsmodifikator} – nur die öffentlichen und Standardzugriffsmodifikatoren sind für verfügbar Klasse. {static} – der statische Modifikator gibt an, dass diese Klasse statisch ist; es gilt nur für innere Klassen (Klassen innerhalb anderer Klassen). {final} – Dies ist natürlich der letzte Modifikator, der die Klasse nicht vererbbar macht (ein Standardbeispiel ist String ). {abstract} – der abstrakte Modifikator, der angibt, dass die Klasse möglicherweise nicht implementierte Methoden hat. Dieser Modifikator steht im Konflikt mit dem letzten Modifikator. Der Klassenheader kann nur eines davon enthalten, da der abstrakte Modifikator bedeutet, dass die Klasse geerbt und ihre abstrakten Elemente implementiert werden. Final gibt jedoch an, dass dies die endgültige Version der Klasse ist und nicht vererbt werden kann. Eigentlich wäre die gleichzeitige Verwendung beider Modifikatoren absurd. Der Compiler lässt uns das nicht zu. <class> ist ein obligatorisches Schlüsselwort, das eine Klassendeklaration angibt. <Klassenname> ist ein einfacher Klassenname, der zur Kennung einer bestimmten Java-Klasse wird. Der vollständig qualifizierte Klassenname besteht aus dem qualifizierten Paketnamen plus „.“ plus den einfachen Klassennamen. {Inheritance of the Parent class} ist ein Hinweis auf die übergeordnete Klasse (falls vorhanden) unter Verwendung des Schlüsselworts „extens“ . Beispielsweise ... erweitert ParentClass . {Implementierung von Schnittstellen} – eine Liste der Schnittstellen, die diese Klasse (falls vorhanden) mithilfe des Schlüsselworts „ implementiert “ implementiert . Zum Beispiel: ... implementiert FirstInterface, SecondInterface ... Betrachten Sie als Beispiel die Klassenüberschrift der Lion- Klasse, die Cat erbt und die WildAnimal- Schnittstelle implementiert:
public final class Lion extends Cat implements WildAnimal
Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 4 - 3

32. Was sind die Elemente eines Methodenheaders? Schreiben Sie ein Beispiel

Wenn wir die Elemente betrachten, aus denen ein Methodenheader besteht, betrachten wir noch einmal ein kleines Schema:
  • Pflichtelemente erscheinen in Klammern <>
  • optionale Elemente sind in {}
{Zugriffsmodifikator}{statisch}{abstrakt}{final}{synchronisiert} {nativ} <Rückgabewert><Methodenname> <(>{Methodenparameter}<}>{Ausnahmen auslösen} {Zugriffsmodifikator} – alle Zugriffsmodifikatoren sind Verfügbar für die Methode – public , protected , default , private . {static} – der statische Modifikator, der angibt, dass die Methode statisch und daher mit der Klasse und nicht mit einem Objekt verknüpft ist. {abstract} – der abstrakte Modifikator, der dies angibt Die Methode hat keine Implementierung (Körper). Um ordnungsgemäß zu funktionieren, muss die Klasse, die die Methode deklariert, auch über den abstrakten Modifikator verfügen. Wie im Klassenheader steht dieser Modifikator im Konflikt mit dem endgültigen Modifikator und auch im Konflikt mit dem statischen Modifikator, da ein Eine abstrakte Methode impliziert das Überschreiben der Methode in einem Nachkommen, und statische Methoden können nicht überschrieben werden. {finale} – der letzte Modifikator, der angibt, dass diese Methode nicht überschrieben werden kann. {synchronized} – der synchronisierte Modifikator, der bedeutet, dass die Methode vor geschützt ist gleichzeitiger Zugriff darauf aus verschiedenen Threads. Wenn die Methode nicht statisch ist, ist sie für diesen Mutex des Objekts geschlossen. Wenn die Methode statisch ist, ist sie für den Mutex der aktuellen Klasse geschlossen. {native} – der native Modifikator gibt an, dass die Methode in einer anderen Programmiersprache geschrieben ist. <Rückgabetyp> – der Typ des Werts, den die Methode zurückgeben muss. Wenn die Methode nichts zurückgibt, dann void . <Methodenname> – der Name der Methode, dh ihre Kennung im System. {Methodenparameter} – die Parameter, die die Methode akzeptiert: Sie sind notwendig, um ihre Funktionalität zu implementieren. {ausgelöste Ausnahmen}löst <ExceptionType> aus – eine Liste der geprüften Ausnahmen, die diese Methode auslösen kann. Als Beispiel für einen Methodenheader biete ich Folgendes an:
public static void main(String[] args) throws IOException

33. Erstellen Sie einen Standardkonstruktor in einer untergeordneten Klasse, wenn keiner bereits in der Basisklasse definiert ist (sondern ein anderer Konstruktor definiert ist).

Ich bin mir nicht sicher, ob ich die Frage ganz verstehe, aber vielleicht bedeutet es, dass wir in der übergeordneten Klasse einen Konstruktor wie diesen haben:
public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
In diesem Fall müssen wir in der übergeordneten Klasse unbedingt einen Konstruktor definieren, der die übergeordnete Klasse initialisiert (d. h. den übergeordneten Konstruktor aufruft):
public class Lion extends Cat {

   public Lion(int age, String name) {
       super(age, name);
   }
}
Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 4 - 4

34. Wann wird das Schlüsselwort this verwendet?

In Java hat dies zwei verschiedene Bedeutungen. 1. Es handelt sich um eine Referenz auf das aktuelle Objekt, z. B. this.age = 9 . Das heißt, this bezieht sich auf das Objekt, in dem es verwendet wird und auf das sich der Code damit bezieht . Der Hauptzweck besteht darin, die Lesbarkeit des Codes zu verbessern und Mehrdeutigkeiten zu vermeiden. Wenn beispielsweise ein Instanzfeld und ein Methodenargument denselben Namen haben:
public void setName(String name) {
   this.name = name;
}
Das heißt, this.name ist das Feld des Objekts, während name der Methodenparameter ist. Die this- Referenz kann nicht in statischen Methoden verwendet werden. 2. Im Konstruktor kann dies wie eine Methode aufgerufen werden, z. B. this(value) . In diesem Fall handelt es sich um einen Aufruf eines anderen Konstruktors derselben Klasse. Grundsätzlich können Sie beim Erstellen eines Objekts zwei Konstruktoren aufrufen:
public Cat(int age, String name) {
   this(name);
   this.age = age;
}

public Cat(String name) {
   this.name = name;
}
Beim Aufruf des ersten Konstruktors zum Erstellen eines Cat- Objekts werden beide Instanzfelder erfolgreich initialisiert. Hier gibt es ein paar Nuancen:
  1. this() funktioniert nur in einem Konstruktor.
  2. Ein Verweis auf einen anderen Konstruktor muss in der ersten Zeile des Konstruktorblocks (Body) stehen. Das bedeutet, dass ein Konstruktor nicht mehr als einen (anderen) Konstruktor seiner Klasse aufrufen kann.
Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 4 - 5

35. Was ist ein Initialisierer?

Soweit ich weiß, handelt es sich bei dieser Frage um gewöhnliche und statische Initialisierungsblöcke. Erinnern wir uns zunächst daran, was Initialisierung ist. Unter Initialisierung versteht man die Erstellung, Aktivierung, Vorbereitung und Definition von Feldern. Ein Programm oder eine Komponente so vorbereiten, dass sie einsatzbereit ist. Sie werden sich erinnern, dass beim Erstellen eines Objekts eine Klassenvariable sofort initialisiert werden kann, wenn sie deklariert wird:
class Cat {
   private int age = 9;
   private String name = "Tom";
Oder nachträglich über den Konstruktor festlegen:
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: Sie können eine Instanzvariable mithilfe eines Initialisierungsblocks festlegen, der die Form von geschweiften Klammern {} innerhalb einer Klasse annimmt, ohne Namen (wie eine namenlose Methode oder ein Konstruktor):
class Cat {
   private int age;
   private String name;

   {
       age = 10;
       name = "Tom";
   }
Ein Initialisierungsblock ist ein Codeteil, der geladen wird, wenn ein Objekt erstellt wird. Solche Blöcke werden typischerweise verwendet, um bestimmte komplexe Berechnungen durchzuführen, die beim Laden einer Klasse erforderlich sind. Die Ergebnisse dieser Berechnungen können als Werte von Variablen festgelegt werden. Neben gewöhnlichen Initialisierungsblöcken gibt es auch statische. Sie sehen gleich aus, haben aber das Schlüsselwort static vor der öffnenden geschweiften Klammer:
class Cat {
   private static int age;
   private static String name;

   static{
       age = 10;
       name = "Tom";
   }
Dieser Block ist derselbe wie der vorherige. Wenn jedoch die gewöhnliche Ausführung bei der Initialisierung jedes Objekts ausgeführt wird, wird die statische Ausführung nur einmal ausgeführt, wenn die Klasse geladen wird. In der Regel werden bestimmte komplexe Berechnungen in einem statischen Block durchgeführt, der zur Initialisierung statischer Klassenvariablen verwendet wird. Für einen statischen Block gelten die gleichen Einschränkungen wie für statische Methoden: Sie können in einem statischen Block keine nicht statischen Daten verwenden, beispielsweise einen Verweis auf das aktuelle Objekt ( this ). Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 4 - 6Jetzt können wir uns die Reihenfolge der Initialisierung der Klasse (zusammen mit ihrer übergeordneten Klasse) ansehen, um besser zu verstehen, wann genau die Initialisierungsblöcke aufgerufen werden.

36. Schreiben Sie bei einer öffentlichen Child-Klasse, die Parent erweitert, die Initialisierungsreihenfolge des Objekts auf

Beim Laden der Child- Klasse lautet die Initialisierungsreihenfolge wie folgt:
  1. Statische Klassenfelder der übergeordneten Klasse.
  2. Statischer Initialisierungsblock der Parent- Klasse.
  3. Statische Felder der Сhild- Klasse.
  4. Statischer Initialisierungsblock der Child- Klasse.
  5. Nicht statische Felder der Parent- Klasse.
  6. Nicht statischer Initialisierungsblock der Parent- Klasse.
  7. Konstruktor der übergeordneten Klasse.
  8. Nichtstatische Felder der Сhild- Klasse.
  9. Nicht statischer Initialisierungsblock der Сhild- Klasse.
  10. Der Konstruktor der Сhild- Klasse.
Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 4 - 7

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

In Java gibt es zwei Arten von Variablen: primitive Typen und Verweise auf vollwertige Objekte.
  • IS-A- Beziehungen
Das IS-A-Prinzip von OOP basiert auf der Klassenvererbung oder der Implementierung von Schnittstellen. Wenn beispielsweise die Lion -Klasse Cat erbt , sagen wir, dass Lion eine Cat ist :
Lion IS-A Cat
(aber nicht jede Katze ist ein Löwe ) Die gleiche Situation besteht bei Schnittstellen. Wenn die Lion- Klasse die WildAnimal- Schnittstelle implementiert , existieren sie auch in der Beziehung:
Lion IS-A WildAnimal
  • HAS-A- Beziehung
Bei dieser Art von Beziehung verwendet eine Klasse andere Klassen, was auch als „Assoziation“ bezeichnet wird. Eine Assoziation ist eine Klasse, die auf eine andere Klasse verweist (oder gegenseitige Verweise aufeinander). Beispielsweise kann die Klasse „Car“ auf die Klasse „Passagier“ verweisen , was die folgende Beziehung darstellen würde:
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 Objektbeziehungen 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 könnte sich ein Passagier in einem Auto befinden. Darüber hinaus kann es mehrere oder gar keine Passagiere geben (und wenn wir über Tesla sprechen, gibt es möglicherweise keinen Fahrer). 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("Transporting passenger - " + passenger.toString());
       }
       passengers.clear();
   }
}
Mit anderen Worten, die Anzahl der Passagiere ist für uns nicht wichtig: Die Funktionalität der Pkw- Klasse hängt davon nicht ab. Aggregation impliziert auch, dass, wenn ein anderes Objekt ein Objekt verwendet, das erste Objekt von anderen Objekten verwendet werden kann. Beispielsweise kann derselbe Schüler sowohl in einem Strickclub als auch in einer Rockband sein und gleichzeitig einen Spanischkurs besuchen. Wie Sie sich vorstellen können, handelt es sich bei der Aggregation um eine lockerere assoziative Beziehung zwischen Klassen. Komposition ist eine noch engere Beziehung, bei der ein Objekt nicht nur Teil eines anderen Objekts ist, sondern die Arbeit eines Objekts stark von einem anderen Objekt abhängt. Ein Auto hat zum Beispiel einen Motor. Ein Motor mag ohne Auto existieren, aber außerhalb eines Autos ist er nutzlos. Und ein Auto kann nicht ohne Motor funktionieren:
public class Car {
   private Engine engine;

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

   void startMoving() {
       engine.start();
           ...
   }
Die Zusammensetzung impliziert auch, dass, wenn ein anderes Objekt ein Objekt verwendet, das erste Objekt keinem anderen Objekt gehören darf. Um auf unser Beispiel zurückzukommen: Ein Motor kann nur zu einem Auto gehören, nicht zu zwei oder mehreren gleichzeitig. Ich denke, das reicht für heute, deshalb hören wir hier auf.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION