Hallo zusammen, heute analysiere ich weiterhin über 250 Interviewfragen für Java-Entwickler. Vorherige Teile der Analyse: erster , zweiter , dritter . Also machen wir weiter.
<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 :
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 .
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 {}
public final class Lion extends Cat implements WildAnimal
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 {}
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);
}
}
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:
- this() funktioniert nur im Konstruktor.
- 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.
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 . Als 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:- Statische Felder der Parent- Klasse .
- Statischer Initialisierungsblock für die übergeordnete Klasse .
- Statische Felder der Child- Klasse .
- Statischer Initialisierungsblock für die Child- Klasse .
- Nicht statische Felder der Parent- Klasse .
- Kein statischer Initialisierungsblock für die Parent- Klasse .
- Konstruktor für die Parent- Klasse .
- Nicht statische Felder der Child- Klasse .
- Kein statischer Initialisierungsblock für die Child- Klasse .
- Konstruktor der Child- Klasse .
37. Welche Beziehungen kennen Sie zwischen Klassen (Objekten)?
In Java gibt es zwei Arten von Beziehungen zwischen Klassen:- IS-A- Beziehung
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
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. Die 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.
GO TO FULL VERSION