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 2

Veröffentlicht in der Gruppe Random-DE
Hallo nochmal alle zusammen! Wir suchen weiterhin nach Antworten auf über 250 Fragen für Junior-, Middle- und Senior-Entwickler. Die Fragen sind sehr interessant und ich selbst analysiere sie gerne: In solchen Momenten kann man Lücken im theoretischen Wissen entdecken, und zwar an den unerwartetsten Stellen. Analyse von Interviewfragen und -antworten.  Teil 2 - 1Den vorherigen Teil finden Sie in diesem Artikel . Aber bevor wir beginnen, möchte ich Sie daran erinnern:
  1. Ich werde Fragen, die sich mit dieser Artikelserie überschneiden, überspringen , um nicht noch einmal Informationen zu duplizieren. Ich empfehle die Lektüre dieser Materialien, da sie die häufigsten (beliebtesten) Java Core-Interviewfragen enthalten.
  2. Fragen zu DOU werden auf Ukrainisch gestellt, aber ich werde hier alles auf Russisch haben.
  3. Die Antworten könnten ausführlicher beschrieben werden, aber das werde ich nicht tun, da die Beantwortung jeder Frage dann einen ganzen Artikel umfassen könnte. Und sie werden Sie bei keinem Vorstellungsgespräch so ausführlich befragen.
Bei Bedarf hinterlasse ich Links zum tieferen Studium. Lass uns fliegen!

11. Benennen Sie alle Methoden der Object-Klasse

Die Object-Klasse verfügt über 11 Methoden:
  • Class<?> getClass() – die Klasse des aktuellen Objekts abrufen;
  • int hashCode() – den Hash-Code des aktuellen Objekts abrufen;
  • boolean equal​(Object obj) – Vergleich des aktuellen Objekts mit einem anderen;
  • Object clone() – Erstellen und Zurückgeben einer Kopie des aktuellen Objekts;
  • String toString() – eine String-Darstellung eines Objekts abrufen;
  • void notify() – einen Thread wecken, der auf dem Monitor dieses Objekts wartet (Thread-Auswahl erfolgt zufällig);
  • void notifyAll() – weckt alle Threads, die auf dem Monitor dieses Objekts warten;
  • void wait() – schaltet den aktuellen Thread auf dem aktuellen Monitor in den Standby-Modus (friert ihn ein), funktioniert nur in einem synchronisierten Block, bis irgendetwas notify oder notifyAll den Thread aufweckt;
  • void wait(long timeout) – friert auch den aktuellen Thread auf dem aktuellen Monitor (auf dem aktuell synchronisierten) ein, jedoch mit einem Timer zum Verlassen dieses Zustands (oder noch einmal: bis notify oder notifyAll aufwacht);
  • void wait(long timeout, int nanos) – eine Methode ähnlich der oben beschriebenen, jedoch mit präziseren Timern für das Beenden des Einfrierens;
  • void finalize() – bevor dieses Objekt gelöscht wird, ruft der Garbage Collector diese Methode (endgültig) auf. Es dient der Bereinigung belegter Ressourcen.
Um die Methoden hashCode , equal ​, clone , toString und finalize korrekt zu verwenden , müssen sie unter Berücksichtigung der aktuellen Aufgabe und Umstände neu definiert werden.

12. Was ist der Unterschied zwischen try-with-resources und try-catch-finally beim Umgang mit Ressourcen?

Normalerweise wurde bei der Verwendung von try-catch-finally der letzte Block zum Schließen von Ressourcen verwendet. Mit Java 7 wurde eine neue Art von Operator try-with-resources eingeführt , ein Analogon zu try-catch-finally zum Freigeben von Ressourcen, jedoch kompakter und lesbarer. Erinnern wir uns daran, wie try-catch-finally aussieht :
String text = "some text......";
BufferedWriter bufferedWriter = null;
try {
   bufferedWriter = new BufferedWriter(new FileWriter("someFileName"));
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
} finally {
   try {
       bufferedWriter.close();
   } catch (IOException e) {
       e.printStackTrace();
   }
}
Schreiben wir nun diesen Code um, verwenden jedoch „try-with-resources“ :
String text = "some text......";
try(BufferedWriter bufferedWriter =new BufferedWriter(new FileWriter("someFileName"))) {
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
}
Es ist irgendwie einfacher geworden, finden Sie nicht? Neben der Vereinfachung gibt es noch ein paar Punkte:
  1. In try-with-resources müssen in Klammern deklarierte Ressourcen (die geschlossen werden) die AutoCloseable-Schnittstelle und ihre einzige Methode, close(), implementieren .

    Die close- Methode wird in einem impliziten „finally“-Block ausgeführt . Wie soll das Programm sonst genau verstehen, wie eine bestimmte Ressource geschlossen wird?

    Aber höchstwahrscheinlich werden Sie selten eigene Implementierungen von Ressourcen und deren Abschlussmethode schreiben.

  2. Reihenfolge der Blockausführung:

    1. Versuchen Sie es mit Blockieren .
    2. Implizit schließlich .
    3. Ein Catch -Block , der Ausnahmen in vorherigen Schritten abfängt.
    4. Endlich explizit .

    In der Regel unterbrechen Ausnahmen, die weiter unten in der Liste erscheinen, diejenigen, die weiter oben erscheinen.

Stellen Sie sich eine Situation vor, in der bei Verwendung von try-catch-finally eine Ausnahme in Ihrem try auftritt. Dementsprechend beginnt sofort die Ausführung eines bestimmten Catch- Blocks , in dem Sie eine weitere Ausnahme schreiben (z. B. mit einer Meldung, die den Fehler detaillierter beschreibt) und Sie möchten, dass die Methode diese Ausnahme weiter auslöst. Als nächstes folgt die Ausführung des „final“ -Blocks , in dem auch eine Ausnahme ausgelöst wird. Aber das hier ist anders. Welche dieser beiden Ausnahmen wird diese Methode letztendlich auslösen? Vom „finally “-Block ausgelöste Ausnahme ! Aber es gibt auch einen Punkt bei try-with-resources . Schauen wir uns nun das Verhalten von try-with-resources in derselben Situation an. Wir bekommen eine Ausnahme im try- Block , wenn wir versuchen, Ressourcen in der close()- Methode , also im impliziten „ final“ zu schließen . Welche dieser Ausnahmen wird erfasst ? Derjenige, der vom Try- Block geworfen wurde ! Eine Ausnahme von einem impliziten „ final“ (von der Methode „close()“ ) wird ignoriert. Dieses Ignorieren wird auch Ausnahmeunterdrückung genannt.

13. Was sind bitweise Operationen?

Bitweise Operationen sind Operationen an Bitfolgen, die logische Operationen und bitweise Verschiebungen umfassen. Logische Operationen:
  • bitweises UND – vergleicht Bitwerte, und dabei setzt jedes auf 0 (falsch) gesetzte Bit das entsprechende Bit im Ergebnis auf 0. Das heißt, wenn in beiden verglichenen Werten das Bit 1 (wahr) war, wird das Das Ergebnis wird ebenfalls 1 sein.

    Bezeichnet als - AND , &

    Beispiel: 10111101 & 01100111 = 00100101

  • bitweises ODER ist die Umkehroperation der vorherigen. Jedes auf 1 gesetzte Bit setzt ein ähnliches Bit im Ergebnis als 1. Und wenn das Bit in beiden verglichenen Werten 0 war, ist das resultierende Bit dementsprechend auch 0.

    Bezeichnet als - OR , |

    Beispiel: 10100101 | 01100011 = 11100111

  • bitweises NICHT – wird auf einen Wert angewendet und dreht (invertiert) die Bits. Das heißt, die Bits, die 1 waren, werden zu 0; und diejenigen, die 0 waren, werden zu 1.

    Bezeichnet als - NOT , ~

    Beispiel: ~10100101 = 01011010

  • bitweises exklusives ODER – vergleicht Bitwerte, und wenn in beiden Werten das Bit gleich 1 ist, ist das Ergebnis 0, und wenn in beiden Werten das Bit 0 ist, ist das Ergebnis 0. Das heißt, Damit das Ergebnis gleich 1 ist, muss nur eines der Bits gleich 1 und das zweite gleich 0 sein.

    Bezeichnet als - XOR , ^

    Beispiel: 10100101 ^ 01100011 = 11000110

Bitweise Verschiebungen>> oder << verschiebt die Bits eines Werts in der angegebenen Richtung um die angegebene Zahl. Die frei gewordenen Positionen werden mit Nullen aufgefüllt. Zum Beispiel:
  1. 01100011 >> 4 = 00000110
  2. 01100011 << 3 = 00011000
Es gibt auch eine Ausnahme, wenn eine negative Zahl nach rechts verschoben wird. Wie Sie sich erinnern, ist das erste Bit für das Vorzeichen verantwortlich, und wenn dieses Bit gleich 1 ist, ist die Zahl negativ. Wenn Sie eine negative Zahl verschieben, werden die frei gewordenen Stellen nicht mehr mit Nullen, sondern mit Einsen aufgefüllt, da das Vorzeichenbit erhalten bleiben muss. Zum Beispiel: 10100010 >> 2 = 11101000 Gleichzeitig gibt es in Java einen zusätzlichen vorzeichenlosen Rechtsverschiebungsoperator >>>. Dieser Operator ist ein Analogon von >>, beim Verschieben werden die frei gewordenen Positionen unabhängig davon mit 0 aufgefüllt die Zahl ist negativ oder positiv. Zum Beispiel: 10100010 >>> 2 = 00101000 Lesen Sie hier mehr über bitweise Operationen . Analyse von Interviewfragen und -antworten.  Teil 2 - 2Als Beispiele für die Verwendung bitweiser Verschiebungen in Java können Sie die hash()- Methode einer HashMap nennen, mit der ein spezieller interner Hash-Code für einen Schlüssel ermittelt wird: Mit Analyse von Interviewfragen und -antworten.  Teil 2 - 3dieser Methode können Sie Daten in einer HashMap gleichmäßig verteilen, um sie zu minimieren die Anzahl der Kollisionen.

14. Welche unveränderlichen Standardklassen sind Objekte in Java?

Unveränderlich ist ein Objekt, dessen ursprüngliche Parameter nicht geändert werden können. Möglicherweise gibt es Methoden, die neue Objekte eines bestimmten Typs mit Parametern zurückgeben, die Sie ändern wollten. Einige standardmäßige unveränderliche Objekte:
  • Das mit Abstand bekannteste unveränderliche Objekt in Java ist String;
  • Instanzen von Wrapper-Klassen, die Standardtypen umschließen: Boolean, Character, Byte, Short, Integer, Long, Double, Float;
  • Objekte, die normalerweise für besonders große Zahlen verwendet werden – BigInteger und BigDecimal;
  • ein Objekt, das eine Einheit in Stacktraces ist (z. B. in einem Ausnahme-Stacktrace) StackTraceElement;
  • ein Objekt der File-Klasse – kann Dateien ändern, ist aber gleichzeitig selbst unveränderlich;
  • UUID – wird oft als eindeutige ID für Elemente verwendet;
  • alle Klassenobjekte des java.time-Pakets;
  • Gebietsschema – wird zur Definition einer geografischen, politischen oder kulturellen Region verwendet.

15. Welche Vorteile hat ein unveränderliches Objekt gegenüber regulären Objekten?

  1. Solche Objekte sind sicher, wenn sie in einer Multithread-Umgebung verwendet werden . Wenn Sie sie verwenden, müssen Sie sich keine Sorgen über Datenverluste aufgrund von Thread-Race-Bedingungen machen. Anders als bei der Arbeit mit gewöhnlichen Objekten: In diesem Fall müssen Sie sehr sorgfältig nachdenken und die Mechanismen für die Verwendung des Objekts in einer parallelen Umgebung erarbeiten.
  2. Unveränderliche Objekte sind gute Schlüssel in einer Map, denn wenn Sie ein veränderliches Objekt verwenden und das Objekt dann seinen Zustand ändert, kann die Verwendung einer HashMap Verwirrung stiften: Das Objekt ist immer noch vorhanden, und wenn Sie containsKey() verwenden , ist dies möglicherweise nicht der Fall gefunden.
  3. Unveränderliche Objekte eignen sich hervorragend zum Speichern unveränderlicher (konstanter) Daten, die niemals geändert werden sollten, während das Programm ausgeführt wird.
  4. „Atomizität bis zum Scheitern“ – wenn ein unveränderliches Objekt eine Ausnahme auslöst, bleibt es trotzdem nicht in einem unerwünschten (kaputten) Zustand.
  5. Diese Klassen sind einfach zu testen.
  6. Zusätzliche Mechanismen wie ein Kopierkonstruktor und eine Klonimplementierung sind nicht erforderlich.

Fragen zu OOP

Analyse von Interviewfragen und -antworten.  Teil 2 - 4

16. Was sind die Vorteile von OOP im Allgemeinen und im Vergleich zur prozeduralen Programmierung?

Die Vorteile von OOP:
  1. Komplexe Anwendungen sind einfacher zu schreiben als prozedurale Programmierung, da alles in kleine Module – Objekte, die miteinander interagieren – zerlegt wird und sich die Programmierung daher auf Beziehungen zwischen Objekten beschränkt.
  2. Mit OOP geschriebene Anwendungen lassen sich viel einfacher ändern (solange die Designkonzepte befolgt werden).
  3. Da die Daten und Operationen darauf eine einzige Einheit bilden, werden sie nicht in der gesamten Anwendung verschmiert (was bei der prozeduralen Programmierung häufig der Fall ist).
  4. Die Informationskapselung schützt die kritischsten Daten vor dem Benutzer.
  5. Es ist möglich, denselben Code mit unterschiedlichen Daten wiederzuverwenden, da Sie mit Klassen viele Objekte erstellen können, von denen jedes seine eigenen Attributwerte hat.
  6. Durch Vererbung und Polymorphismus können Sie außerdem vorhandenen Code wiederverwenden und erweitern (anstatt ähnliche Funktionen zu duplizieren).
  7. Einfachere Anwendungserweiterbarkeit als mit einem prozeduralen Ansatz.
  8. Der OOP-Ansatz ermöglicht es, von Implementierungsdetails zu abstrahieren.

17. Sagen Sie uns, welche Mängel es bei OOP gibt

Leider sind sie auch vorhanden:
  1. OOP erfordert viel theoretisches Wissen, das beherrscht werden muss, bevor Sie etwas schreiben können.Analyse von Interviewfragen und -antworten.  Teil 2 - 5
  2. Die Ideen von OOP sind nicht so einfach zu verstehen und in der Praxis anzuwenden (man muss im Herzen ein bisschen Philosoph sein).
  3. Bei der Verwendung von OOP wird die Leistung der Software aufgrund der komplexeren Organisation des Systems leicht reduziert.
  4. Der OOP-Ansatz erfordert mehr Speicher, da alles aus Klassen, Schnittstellen und Methoden besteht, die viel mehr Speicher beanspruchen als gewöhnliche Variablen.
  5. Der Zeitaufwand für die Erstanalyse ist größer als für die Verfahrensanalyse.

18. Was ist statischer und dynamischer Polymorphismus?

Durch Polymorphismus können sich Objekte für dieselbe Klasse oder Schnittstelle unterschiedlich verhalten. Es gibt zwei Arten von Polymorphismus, die auch als frühe und späte Bindung bekannt sind . Statischer Polymorphismus oder frühere Bindung:
  • Tritt zur Kompilierzeit auf (früh im Lebenszyklus des Programms);
  • entscheidet, welche Methode zur Kompilierungszeit ausgeführt werden soll;
  • Das Überladen von Methoden ist ein Beispiel für statischen Polymorphismus.
  • Die frühe Bindung umfasst private, statische und terminale Methoden.
  • Vererbung ist an der frühen Bindung nicht beteiligt;
  • Beim statischen Polymorphismus geht es nicht um bestimmte Objekte, sondern um Informationen über die Klasse, deren Typ links vom Variablennamen dargestellt wird.
Dynamischer Polymorphismus oder späte Bindung:
  • tritt zur Laufzeit auf (während das Programm ausgeführt wird);
  • Der dynamische Polymorphismus entscheidet darüber, welche spezifische Implementierung eine Methode zur Laufzeit haben wird.
  • Das Überschreiben von Methoden ist ein Beispiel für dynamischen Polymorphismus.
  • Bei der späten Bindung handelt es sich um die Zuweisung eines bestimmten Objekts, einer Referenz seines Typs oder seiner Oberklasse.
  • Vererbung ist mit dynamischem Polymorphismus verbunden.
Weitere Informationen zu den Unterschieden zwischen früher und später Bindung finden Sie in diesem Artikel .

19. Definieren Sie das Abstraktionsprinzip in OOP

Abstraktion ist in OOP eine Möglichkeit, eine Reihe wichtiger Merkmale eines Objekts hervorzuheben und unwichtige Details auszuschließen. Das heißt, wenn Sie ein Programm mit einem OOP-Ansatz entwerfen, konzentrieren Sie sich auf Modelle im Allgemeinen, ohne sich mit den Details ihrer Implementierung zu befassen. In Java sind Schnittstellen für die Abstraktion zuständig . Sie haben beispielsweise eine Maschine und dies wird die Schnittstelle sein. Und verschiedene Interaktionen damit – zum Beispiel das Starten des Motors, die Bedienung des Getriebes – das sind Funktionen, die wir nutzen, ohne auf Implementierungsdetails einzugehen. Denn in dem Moment, in dem man ein Auto fährt, denkt man nicht darüber nach, wie genau das Getriebe seinen Zweck erfüllt, wie der Schlüssel den Motor startet oder wie genau das Lenkrad die Räder dreht. Und selbst wenn die Implementierung einer dieser Funktionen ersetzt wird (z. B. die Engine), bemerken Sie dies möglicherweise nicht. Für Sie ist das egal: Sie gehen nicht auf Details der Umsetzung ein. Für Sie ist es wichtig, dass die Aktion durchgeführt wird. Tatsächlich handelt es sich hierbei um eine Abstraktion von Implementierungsdetails. Hier machen wir heute Schluss: Fortsetzung folgt!Analyse von Interviewfragen und -antworten.  Teil 2 - 6
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION