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 16

Veröffentlicht in der Gruppe Random-DE
Hallo Freund! Wie lange dauert es, Entwickler zu werden? Ich habe viele verschiedene Leute gefragt und viele unterschiedliche Antworten gehört. Für manche Menschen reicht möglicherweise sogar ein Monat aus, für andere reicht jedoch nicht einmal ein Jahr aus. Aber ich weiß mit Sicherheit, dass es ein schwieriger und langer Weg ist, Java-Entwickler zu werden, unabhängig von Ihren anfänglichen Fähigkeiten. Schließlich kommt es nicht so sehr auf Können an, sondern auf Sturheit und Fleiß. Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 1Deshalb analysieren wir heute weiterhin gezielt die beliebtesten Interviewfragen für Java-Entwickler. Wenn Sie sie studieren, kommen Sie Ihrem geschätzten Ziel nach und nach näher. Lass uns anfangen!

17. Nennen Sie Beispiele für den erfolgreichen und erfolglosen Einsatz von Optional

Angenommen, wir haben eine bestimmte Reihe von Werten, die wir durch den Stream durchlaufen, und am Ende erhalten wir als Ergebnis einige optionale Werte :
Optional<String> stringOptional = Stream.of("a", "ab", "abc", "abcd")
   .filter(str -> str.length() >= 3)
   .findAny();
Wie erwartet müssen wir den Wert von diesem Optional erhalten . Nur get() zu verwenden ist ein schlechter Weg:
String result = stringOptional.get();
Aber diese Methode soll den Wert von Optional abrufen und an uns zurückgeben? Das ist natürlich wahr, aber wenn es einen Sinn hat. Nun, wenn die Werte im Stream unterschiedlich wären und wir am Ende ein leeres Optional erhalten haben, wird beim Versuch, mit der Methode get() einen Wert daraus zu übernehmen , Folgendes ausgegeben: Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 2Was nicht gut ist. In diesem Fall ist es besser, die folgenden Konstruktionen zu verwenden:
  1. String result = null;
    if (stringOptional.isPresent()) {
     stringOptional.get();
    }

    In diesem Fall prüfen wir, ob das Element in Optional ist . Wenn nicht, hat die resultierende Zeichenfolge ihren alten Wert.

  2. String result = stringOptional.orElse("default value");

    In diesem Fall geben wir einen Standardwert an, der im Falle eines leeren Optionals an die resultierende Zeichenfolge übergeben wird .

  3. String result = stringOptional.orElseThrow(() -> new CustomException());

    In diesem Fall lösen wir selbst eine Ausnahme aus, wenn Optional leer ist .

Dies kann in einer Anwendung praktisch sein, wenn beispielsweise die Spring-JPA-Methode findById() verwendet wird, die optionale Werte zurückgibt . In diesem Fall versuchen wir mit dieser Methode, den Wert zu übernehmen, und wenn er nicht vorhanden ist, lösen wir eine Runtime- Ausnahme aus, die auf Controller-Ebene mit ExceptionHandler verarbeitet und in eine HTTP- Antwort mit dem Status 404 – NOT FOUND umgewandelt wird . Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 3

18. Ist es möglich, eine Hauptmethode als endgültig zu deklarieren?

Ja, natürlich hindert uns nichts daran, die Methode main() als final zu deklarieren . Der Compiler erzeugt keine Fehler. Es ist jedoch zu beachten, dass jede Methode, nachdem sie als endgültig deklariert wurde , zur letzten Methode wird und nicht überschrieben wird. Aber wer wird main neu definieren ??? Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 4

19. Ist es möglich, dasselbe Paket/dieselbe Klasse zweimal zu importieren? Was könnten die Folgen sein?

Ja, du kannst. Folgen? Wir werden ein paar unnötige Importe haben, die Intelijj IDEA grau anzeigt, d. h. ungebraucht. Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 5Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 6

20. Was ist Casting? Wann können wir eine ClassCastException bekommen?

Bei der Umwandlung oder Typumwandlung wird ein Datentyp in einen anderen Datentyp konvertiert: manuell (implizite Umwandlung) oder automatisch (explizite Typumwandlung). Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 7Die automatische Konvertierung erfolgt durch den Compiler und die manuelle Konvertierung erfolgt durch den Entwickler. Die Typumwandlung für Grundelemente und Klassen ist etwas anders, daher werden wir sie separat betrachten. Primitive Typen Ein Beispiel für die automatische Umwandlung primitiver Typen:
int value = 17;
double convertedValue = value;
Wie Sie sehen, sind hier außer dem = -Zeichen keine weiteren Manipulationen erforderlich. Beispiel für die manuelle Umwandlung primitiver Typen:
double value = 17.89;
int convertedValue = (int)value;
In diesem Fall können wir eine manuelle Umwandlung beobachten, die mit (int) implementiert wird , wobei der Teil nach dem Komma verworfen wird und der umgewandelte Wert einen Wert von -17 hat. Lesen Sie mehr über die Umwandlung primitiver Typen in diesem Artikel . Kommen wir nun zu den Objekten. Referenztypen Für Referenztypen ist eine automatische Umwandlung von Nachkommenklassen in übergeordnete Klassen möglich. Dies wird auch Polymorphismus genannt . Nehmen wir an, wir haben eine Lion- Klasse, die von einer Cat- Klasse erbt . In diesem Fall sieht die automatische Konvertierung folgendermaßen aus:
Cat cat = new Lion();
Aber bei einer expliziten Besetzung ist alles etwas komplizierter, da es keine Funktionalität zum Abschneiden von Überschüssen wie bei Primitiven gibt. Und führen Sie einfach eine explizite Konvertierung des Formulars durch:
Lion lion= (Lion)new Cat();
Sie erhalten eine Fehlermeldung: Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 8Tatsächlich können Sie der Nachkommenklasse Lion Methoden hinzufügen , die ursprünglich nicht in der Cat- Klasse enthalten waren , und dann versuchen, sie aufzurufen, da Ihr Objekttyp zu Lion wird . Nun, das hat keine Logik. Daher ist eine Typeingrenzung nur möglich, wenn das ursprüngliche Objekt vom Typ Lion ist , aber später in eine übergeordnete Klasse umgewandelt wurde:
Lion lion = new Lion();
Cat cat = lion;
Lion newLion = (Lion)cat;
Für eine höhere Zuverlässigkeit wird außerdem eine einschränkende Umwandlung für Objekte mithilfe des Konstrukts „instanceOf“ empfohlen :
if (cat instanceof Lion) {
 newLion = (Lion)new Cat();
}
Weitere Informationen zu Referenztypumwandlungen finden Sie in diesem Artikel .

21. Warum nutzen moderne Frameworks überwiegend nur ungeprüfte Ausnahmen?

Ich denke, das liegt daran, dass die Behandlung geprüfter Ausnahmen immer noch Spaghetti-Code ist, der überall wiederholt wird, aber nicht in allen Fällen wirklich benötigt wird. Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 9In solchen Fällen ist es einfacher, die Verarbeitung innerhalb des Frameworks durchzuführen, um diese nicht erneut auf die Schultern der Entwickler abzuwälzen. Ja, natürlich kann es zu einer Notfallsituation kommen, aber dieselben ungeprüften Ausnahmen können bequemer behandelt werden, ohne sich um die Verarbeitung in Try-Catch zu kümmern und ohne sie durch Methoden weiterzuleiten. Es reicht aus, die Ausnahme im Ausnahmehandler in eine HTTP-Antwort umzuwandeln .

22. Was ist statischer Import?

Wenn Sie statische Daten (Methoden, Variablen) verwenden, können Sie nicht das Objekt selbst erstellen, sondern dies über den Namen der Klasse tun, aber auch in diesem Fall benötigen wir einen Verweis auf die Klasse. Damit ist alles ganz einfach: Das Hinzufügen erfolgt über den regulären Import. Was aber, wenn wir eine statische Methode verwenden, ohne den Klassennamen zu schreiben, als wäre es eine statische Methode der aktuellen Klasse? Dies ist mit statischem Import möglich! In diesem Fall müssen wir einen statischen Import und einen Link zu dieser Methode schreiben. So zum Beispiel eine statische Methode der Math- Klasse zur Berechnung des Kosinuswerts:
import static java.lang.Math.cos;
Daher können wir die Methode verwenden, ohne den Klassennamen anzugeben:
double result = cos(60);
Mit dem statischen Import können wir auch einfach alle statischen Methoden einer Klasse auf einmal laden:
import static java.lang.Math.*;
Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 10

23. Welche Beziehung besteht zwischen den Methoden hashCode() und equal()?

Laut Oracle gilt die Regel: Wenn zwei Objekte gleich sind (d. h. die Methode equal() gibt true zurück ), müssen sie den gleichen Hash-Code haben. Vergessen Sie dabei nicht, dass zwei verschiedene Objekte denselben Hash-Code haben können. Um zu verstehen, warum equal() und hashCode() immer paarweise überschrieben werden, betrachten Sie die folgenden Fälle:
  1. Beide Methoden werden überschrieben.

    In diesem Fall geben zwei verschiedene Objekte mit denselben internen Zuständen equal() - true zurück , während hashCode() beide dieselbe Zahl zurückgeben.

    Es stellt sich heraus, dass alles in Ordnung ist, denn die Regel wird eingehalten.

  2. Beide Methoden werden nicht überschrieben.

    In diesem Fall geben zwei verschiedene Objekte mit denselben internen Zuständen bei equal() den Wert false zurück , da der Vergleich durch Referenz über den ==- Operator erfolgt .

    Die Methode hashCode() wird (höchstwahrscheinlich) auch unterschiedliche Werte zurückgeben, da sie den konvertierten Wert der Speicherortadresse erzeugt. Aber für dasselbe Objekt ist dieser Wert derselbe, genauso wie equal() in diesem Fall nur dann true zurückgibt, wenn die Referenzen auf dasselbe Objekt verweisen.

    Es stellt sich heraus, dass in diesem Fall alles in Ordnung ist und die Regel erfüllt ist.

  3. Überschriebene equal() , nicht überschriebene hashCode() .

    In diesem Fall gibt equal() für zwei verschiedene Objekte mit denselben internen Zuständen true zurück und hashCode() gibt (höchstwahrscheinlich) unterschiedliche Werte zurück.

    Dies stellt einen Regelverstoß dar und wird daher nicht empfohlen.

  4. equal() wird nicht überschrieben , hashCode() wird überschrieben .

    In diesem Fall gibt equal() für zwei verschiedene Objekte mit denselben internen Zuständen false und hashCode() dieselben Werte zurück.

    Es liegt ein Regelverstoß vor, daher ist die Vorgehensweise falsch.

Wie Sie sehen, kann die Regel nur ausgeführt werden, wenn equal() und hashCode() beide überschrieben werden oder beide überhaupt nicht überschrieben werden. Lesen Sie Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 11mehr über equal() und hashCode() in diesem Artikel .

24. Wann werden die Klassen BufferedInputStream und BufferedOutputStream verwendet?

InputStream wird verwendet, um Daten Byte für Byte aus einer Ressource zu lesen, und OutputStream wird verwendet, um Daten Byte für Byte zu schreiben. Aber Byte-Byte-Operationen können sehr umständlich sein und erfordern zusätzliche Verarbeitung (um Texte normal zu lesen/schreiben). Um solche Byte-Datensätze zu vereinfachen, wurde tatsächlich BufferedOutputStream und BufferedInputStream zum Lesen eingeführt . Diese Klassen sind nichts anderes als Puffer, die Daten sammeln, sodass Sie nicht Byte für Byte, sondern ganze Datenpakete (Arrays) mit Daten arbeiten können. Beim Erstellen nimmt BufferedInputStream eine Instanz des Typs InputStream in seinen Konstruktor auf , aus der Daten gelesen werden:
BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in);
byte[] arr = new byte[100];
bufferedInputStream.read(arr);
System.in ist ein InputStream- Objekt , das Daten von der Konsole liest. Das heißt, mit diesem BufferedInputStream -Objekt können wir Daten aus dem InputStream lesen , indem wir sie in das übergebene Array schreiben. Dies stellt sich als eine Art Wrapper der InputStream- Klasse heraus . Das arr-Array aus diesem Beispiel ist das Array, das Daten von BufferedInputStream empfängt . Das wiederum liest Daten aus dem InputStream mit einem anderen Array, das standardmäßig eine Größe von 2048 Bytes hat. Das Gleiche gilt für BufferedOutputStream : Eine Instanz des Typs OutputStream muss an den Konstruktor übergeben werden , in den wir Daten in ganzen Arrays schreiben:
byte[] arr = "Hello world!!!".getBytes();
BufferedOutputStream bufferedInputStream = new BufferedOutputStream(System.out);
bufferedInputStream.write(arr);
bufferedInputStream.flush();
System.out ist ein OutputStream- Objekt , das Daten in die Konsole schreibt. Die Methode „flush()“ sendet Daten vom BufferedOutputStream an den OutputStream und leert dabei den BufferedOutputStream . Ohne diese Methode wird nichts aufgezeichnet. Und ähnlich wie im vorherigen Beispiel: arr ist das Array, aus dem Daten in den BufferedOutputStream geschrieben werden . Von dort werden sie in einem anderen Array nach OutputStream geschrieben , das standardmäßig eine Größe von 512 Bytes hat. Lesen Sie mehr über diese beiden Klassen im Artikel .

25. Was ist der Unterschied zwischen den Klassen java.util.Collection und java.util.Collections?

Sammlung ist eine Schnittstelle, die an der Spitze der Sammlungshierarchie steht. Es werden Klassen vorgestellt, mit denen Sie ganze Gruppen von Objekten erstellen, enthalten und ändern können. Hierfür stehen viele Methoden zur Verfügung, z. B. add() , remove() , contains() und andere. Hauptschnittstellen der Collection- Klasse :
  • Set ist eine Schnittstelle, die eine Menge beschreibt, die ungeordnete eindeutige (sich nicht wiederholende) Elemente enthält.

  • List ist eine Schnittstelle, die eine Datenstruktur beschreibt, die eine geordnete Folge von Objekten speichert. Diese Objekte erhalten einen eigenen Index (Nummer), über den Sie mit ihnen interagieren können: übernehmen, löschen, ändern, überschreiben.

  • Queue ist eine Schnittstelle, die eine Datenstruktur mit Speicherelementen in Form einer Warteschlange beschreibt, die der Regel FIFO – First In First Out folgt .

Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 12Lesen Sie mehr über Sammlung . Collections ist eine Dienstprogrammklasse, die viele verschiedene Dienstprogrammmethoden bereitstellt. Zum Beispiel:
  • addAll(Collection<? super T> collection, T...element) – fügt die übergebenen Elemente vom Typ T zur Sammlung hinzu .

  • copy(List<? super T> dest, List<? erweitert T> src) – kopiert alle Elemente aus der Liste src in die Liste in dest .

  • emptyList() – gibt eine leere Liste zurück.

  • max(Collection<? erweitert T> Sammlung, Comparator<? Super T> Comp) – Gibt das maximale Element einer bestimmten Sammlung gemäß der durch den angegebenen Komparator angegebenen Reihenfolge zurück.

  • unmodifiableList(List<? erweitert T> Liste) – gibt eine nicht änderbare Darstellung der übergebenen Liste zurück.

Und es gibt eine ganze Reihe solcher praktischer Methoden in Sammlungen . Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 13Eine vollständige Liste dieser Methoden finden Sie auf der Oracle-Website . Nicht umsonst habe ich gesagt, dass sie bequem sind. Schließlich sind sie alle statisch. Das heißt, Sie müssen nicht jedes Mal ein Objekt dieser Klasse erstellen, um die erforderliche Methode dafür aufzurufen. Sie müssen lediglich den Namen der Klasse eingeben, die gewünschte Methode darauf aufrufen und alle erforderlichen Argumente übergeben. Zusammenfassend lässt sich sagen, dass Collection die Stammschnittstelle des Collections-Frameworks ist. Collections ist eine Hilfsklasse zur komfortableren Verarbeitung von Objekten, die zu einem Typ aus der Collections-Struktur gehören. Nun, das ist alles für heute. Alles Gute!Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 16 - 14
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION