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 11

Veröffentlicht in der Gruppe Random-DE
Hallo! Selbst das schnellste Schiff treibt einfach über die Wellen, wenn es keinen Kurs hat. Wenn Sie diesen Artikel gerade lesen, haben Sie definitiv ein Ziel. Die Hauptsache ist, nicht vom Kurs abzukommen und stattdessen alles daran zu setzen, Java-Entwickler zu werden. Heute möchte ich meine Überprüfung der Fragen an Java-Entwickler fortsetzen, um einige Ihrer theoretischen Lücken zu schließen. Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 11 - 1

97. Gelten beim Überschreiben von equal() irgendwelche Regeln?

Beim Überschreiben der Methode equal() müssen Sie die folgenden Regeln beachten:
  • Reflexivität – für jeden Wert x muss x.equals (x) immer true zurückgeben (wobei x != null ).

  • Symmetrie – für alle Werte x und y muss x.equals(y) nur dann true zurückgeben, wenn y.equals(x) true zurückgibt .

  • Transitivität – für alle Werte x , y und z , wenn x.equals(y) true zurückgibt und y.equals(z) auch true zurückgibt , dann muss x.equals(z) true zurückgeben .

  • Konsistenz – für alle Werte x und y wird bei wiederholtem Aufruf von x.equals(y) immer derselbe Wert zurückgegeben, solange sich die zum Vergleich der beiden Objekte verwendeten Felder zwischen den einzelnen Aufrufen nicht geändert haben.

  • Nullvergleich – für jeden Wert x muss der Aufruf von x.equals(null) false zurückgeben .

98. Was passiert, wenn Sie equal() und hashCode() nicht überschreiben?

In diesem Fall gibt hashCode() eine Zahl zurück, die basierend auf der Adresse der Speicherzelle generiert wird, in der das Objekt gespeichert ist. Mit anderen Worten: Wenn die ursprüngliche Methode hashCode() für zwei Objekte mit genau denselben Feldern aufgerufen wird, ist das Ergebnis unterschiedlich (da sie an unterschiedlichen Speicherorten gespeichert sind). Die ursprüngliche Methode equal() vergleicht Referenzen, dh sie gibt an, ob die Referenzen auf dasselbe Objekt verweisen. Mit anderen Worten: Der Vergleich verwendet den ==- Operator und gibt für verschiedene Objekte immer „ false“ zurück , auch wenn ihre Felder identisch sind. true wird nur zurückgegeben, wenn Verweise auf dasselbe Objekt verglichen werden. Manchmal ist es sinnvoll, diese Methoden nicht zu überschreiben. Sie möchten beispielsweise, dass alle Objekte einer bestimmten Klasse eindeutig sind – das Überschreiben dieser Methoden könnte nur die bestehende Garantie eindeutiger Hash-Codes beeinträchtigen. Wichtig ist, die Nuancen dieser Methoden zu verstehen, ob außer Kraft gesetzt oder nicht, und den jeweils erforderlichen Ansatz zu verwenden.

99. Warum ist die Symmetrieanforderung nur dann erfüllt, wenn x.equals(y) true zurückgibt?

Diese Frage ist etwas seltsam. Wenn Objekt A gleich Objekt B ist, dann ist Objekt B gleich Objekt A. Wenn B nicht gleich Objekt A ist, wie könnte dann das Gegenteil möglich sein? Das ist gesunder Menschenverstand.

100. Was ist eine HashCode-Kollision? Wie gehen Sie damit um?

Eine HashCode- Kollision tritt auf, wenn zwei verschiedene Objekte denselben HashCode haben . Wie ist das möglich? Nun, der Hash-Code wird einer Ganzzahl zugeordnet, die einen Bereich von -2147483648 bis 2147483647 hat. Das heißt, es kann eine von etwa 4 Milliarden verschiedenen Ganzzahlen sein. Diese Bandbreite ist riesig, aber nicht unendlich. Das bedeutet, dass es Situationen gibt, in denen zwei völlig unterschiedliche Objekte denselben Hash-Code haben können. Es ist höchst unwahrscheinlich, aber möglich. Eine schlecht implementierte Hash-Funktion kann dazu führen, dass identische Hash-Codes häufiger vorkommen, indem sie Zahlen in einem kleinen Bereich zurückgibt und so die Wahrscheinlichkeit von Kollisionen erhöht. Um Kollisionen zu reduzieren, benötigen Sie eine gute Implementierung der HashCode- Methode, die die Werte gleichmäßig verteilt und die Wahrscheinlichkeit wiederholter Werte minimiert.

101. Was passiert, wenn sich der Wert eines am hashCode-Vertrag beteiligten Elements ändert?

Wenn sich ein an der Berechnung eines Hash-Codes beteiligtes Element ändert, sollte sich auch der Hash-Code des Objekts ändern (sofern die Hash-Funktion gut ist). Aus diesem Grund sollten Sie unveränderliche Objekte als Schlüssel in einer HashMap verwenden , da ihr interner Zustand (Felder) nach der Erstellung nicht geändert werden kann. Daraus folgt, dass sich ihr Hash-Code nach der Erstellung ändert. Wenn Sie ein veränderliches Objekt als Schlüssel verwenden, ändert sich bei einer Änderung der Felder des Objekts auch sein Hash-Code, und Sie könnten das entsprechende Schlüssel-Wert-Paar in der HashMap verlieren . Schließlich wird es in dem Bucket gespeichert, der dem ursprünglichen Hash-Code zugeordnet ist. Nachdem sich das Objekt jedoch geändert hat, wird in einem anderen Bucket danach gesucht.

102. Schreiben Sie die Methoden equal() und hashCode() für eine Student-Klasse, die über die Felder String name und int age verfügt.


public class Student {
int age;
String name;
 
 @Override
 public boolean equals(final Object o) {
   if (this == o) {
     return true;
   }
   if (o == null || this.getClass() != o.getClass()) {
     return false;
   }
 
   final Student student = (Student) o;
 
   if (this.age != student.age) {
     return false;
   }
   return this.name != null ? this.name.equals(student.name) : student.name == null;
 }
 
 @Override
 public int hashCode() {
   int result = this.age;
   result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
   return result;
 }
}
gleich():
  • Zuerst vergleichen wir die Referenzen direkt, denn wenn die Referenzen auf dasselbe Objekt verweisen, welchen Sinn hat es dann, weiterhin auf Gleichheit zu prüfen? Wir wissen bereits, dass das Ergebnis wahr sein wird .

  • Wir prüfen auf null und ob die Klassentypen gleich sind, denn wenn der Parameter null oder von einem anderen Typ ist, können die Objekte nicht gleich sein und das Ergebnis muss false sein .

  • Wir wandeln den Parameter in denselben Typ um (was passiert schließlich, wenn es sich um ein Objekt des übergeordneten Typs handelt).

  • Wir vergleichen die primitiven Felder (ein Vergleich mit =! reicht aus). Wenn sie nicht gleich sind, geben wir false zurück .

  • Wir überprüfen das nicht-primitive Feld, um festzustellen, ob es null ist, und verwenden die Methode „equals“ (die String- Klasse überschreibt die Methode, sodass der Vergleich korrekt durchgeführt wird). Wenn beide Felder null sind oder „ equals“ „ true“ zurückgibt , beenden wir die Prüfung und die Methode gibt „ true“ zurück .

Hash-Code() :
  • Wir setzen den Anfangswert des Hash-Codes auf den Wert des Altersfelds des Objekts .

  • Wir multiplizieren den aktuellen Hash-Code mit 31 (für eine größere Streuung der Werte) und fügen dann den Hash-Code des nicht-primitiven String-Felds hinzu (falls er nicht null ist).

  • Wir geben das Ergebnis zurück.

  • Das Überschreiben der Methode auf diese Weise bedeutet, dass Objekte mit demselben Namen und denselben int- Werten immer denselben Hash-Code zurückgeben.

103. Was ist der Unterschied zwischen der Verwendung von „if (obj instanceof Student)“ und „if (getClass() == obj.getClass())“?

Werfen wir einen Blick darauf, was jeder Ausdruck bewirkt:
  • Instanz von prüft, ob die Objektreferenz auf der linken Seite eine Instanz des Typs auf der rechten Seite oder einer seiner Untertypen ist.

  • „getClass() == ...“ prüft, ob Typen gleich sind.

Mit anderen Worten: getClass() gibt die spezifische Identität der Klasse zurück, aber „ instanceof“ gibt „ true“ zurück , selbst wenn das Objekt nur ein Untertyp ist, was uns mehr Flexibilität bei der Verwendung von Polymorphismus geben kann. Beide Ansätze sind erfolgversprechend, wenn man ihre Funktionsweise genau versteht und an den richtigen Stellen anwendet.

104. Geben Sie eine kurze Beschreibung der clone()-Methode.

Die clone() -Methode gehört zur Object- Klasse. Sein Zweck besteht darin, einen Klon (eine Kopie) des aktuellen Objekts zu erstellen und zurückzugeben. Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 11 - 2Um diese Methode verwenden zu können, müssen Sie die klonbare Markierungsschnittstelle implementieren:

Student implements Cloneable
Und überschreiben Sie die clone()- Methode selbst:

@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
Schließlich ist es in der Object- Klasse geschützt, dh es ist nur innerhalb der Student- Klasse sichtbar und für externe Klassen nicht sichtbar.

105. Welche besonderen Überlegungen müssen Sie in Bezug auf die clone()-Methode und Referenzvariablen in einem Objekt beachten?

Beim Klonen von Objekten werden nur Grundwerte und der Wert der Objektreferenzen kopiert. Das heißt, wenn ein Objekt über ein Feld verfügt, das auf ein anderes Objekt verweist, wird nur die Referenz geklont – dieses andere referenzierte Objekt wird nicht geklont. Dies wird als flache Kopie bezeichnet. Was also, wenn Sie eine vollständige Kopie benötigen, in der jedes verschachtelte Objekt geklont wird? Wie stellen Sie sicher, dass es sich nicht um bloße Kopien von Referenzen handelt, sondern um vollwertige Kopien unterschiedlicher Objekte, die unterschiedliche Speicheradressen im Heap belegen? Eigentlich ist alles ganz einfach – für jede Klasse, auf die intern verwiesen wird, müssen Sie die clone()- Methode überschreiben und die Cloneable- Marker-Schnittstelle hinzufügen. Sobald Sie dies tun, kopiert der Klonvorgang keine Verweise auf vorhandene Objekte, sondern stattdessen die referenzierten Objekte, da diese nun auch die Möglichkeit haben, sich selbst zu kopieren.

Ausnahmen

106. Was ist der Unterschied zwischen einem Fehler und einer Ausnahme?

Ausnahmen sowie Fehler sind Unterklassen von Throwable . Sie haben jedoch ihre Unterschiede. Der Fehler weist auf ein Problem hin, das hauptsächlich aufgrund fehlender Systemressourcen auftritt. Und unsere Anwendung sollte solche Probleme nicht sehen. Beispiele für diese Fehler sind ein Systemabsturz und ein Fehler wegen unzureichendem Arbeitsspeicher. Fehler treten meist zur Laufzeit auf, da sie ungeprüft sind. Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 11 - 3Ausnahmen sind Probleme, die zur Laufzeit und zur Kompilierungszeit auftreten können. Diese Probleme treten normalerweise in dem Code auf, den wir als Entwickler schreiben. Das bedeutet, dass diese Ausnahmen vorhersehbarer und stärker von uns abhängig sind. Im Gegensatz dazu sind Fehler eher zufällig und unabhängiger von uns. Stattdessen hängen sie von Problemen im System ab, auf dem unsere Anwendung ausgeführt wird.

107. Was ist der Unterschied zwischen aktiviert, nicht aktiviert, Ausnahme, Wurf und Würfen?

Wie ich bereits sagte, handelt es sich bei einer Ausnahme um einen Laufzeit- oder Kompilierzeitfehler, der in vom Entwickler geschriebenem Code auftritt (aufgrund einer ungewöhnlichen Situation). Als „Geprüft“ bezeichnen wir Ausnahmen, die eine Methode immer mithilfe des Try-Catch- Mechanismus behandeln oder an die aufrufende Methode erneut auslösen muss. Das Schlüsselwort throws wird in einem Methodenheader verwendet, um die Ausnahmen anzugeben, die die Methode möglicherweise auslöst. Mit anderen Worten: Es bietet uns einen Mechanismus zum Auslösen von Ausnahmen für die aufrufende Methode. Ungeprüfte Ausnahmen müssen nicht behandelt werden. Sie sind tendenziell weniger vorhersehbar und weniger wahrscheinlich. Das heißt, Sie können damit umgehen, wenn Sie möchten. Wir verwenden throw , wenn wir manuell eine Ausnahme auslösen, zum Beispiel:

throw new Exception();

108. Was ist die Ausnahmehierarchie?

Die Ausnahmehierarchie ist sehr umfangreich. Es gibt zu viel, um es hier angemessen zu beschreiben. Stattdessen betrachten wir nur seine Schlüsselzweige: Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 11 - 4 Hier, ganz oben in der Hierarchie, sehen wir die Throwable- Klasse, die der allgemeine Vorfahre der Ausnahmehierarchie ist und sich wiederum in Folgendes unterteilt:
  • Fehler – kritische, ungeprüfte Probleme.
  • Ausnahmen – Ausnahmen, die überprüft werden können.
Ausnahmen sind in verschiedene ungeprüfte Laufzeitausnahmen und verschiedene geprüfte Ausnahmen unterteilt.

109. Was sind geprüfte und ungeprüfte Ausnahmen?

Wie ich bereits gesagt habe:
  • Geprüfte Ausnahmen sind Ausnahmen, die Sie irgendwie behandeln müssen. Das heißt, Sie müssen sie entweder in einem Try-Catch- Block verarbeiten oder sie der oben genannten Methode übergeben. Verwenden Sie dazu nach dem Auflisten der Methodenargumente in der Methodensignatur throws <Exception Type> , um anzugeben, dass die Methode diese Ausnahme auslösen kann. Dies ist so etwas wie eine Warnung, die die aufrufende Methode darauf aufmerksam macht, dass sie die Verantwortung für die Behandlung dieser Ausnahme übernehmen muss.

  • Ungeprüfte Ausnahmen müssen nicht behandelt werden, da sie zur Kompilierungszeit nicht geprüft werden und normalerweise unvorhersehbarer sind. Ihr Hauptunterschied zu geprüften Ausnahmen besteht darin, dass ihre Behandlung mithilfe eines Try-Catch -Blocks oder durch erneutes Auslösen optional und nicht obligatorisch ist.

101. Schreiben Sie ein Beispiel, in dem Sie einen Try-Catch-Block verwenden, um eine Ausnahme abzufangen und zu behandeln.


try{                                                 // Start of the try-catch block
 throw new Exception();                             // Manually throw an exception
} catch (Exception e) {                              // Exceptions of this type and its subtypes will be caught
 System.out.println("Oops! Something went wrong =("); // Display the exception
}

102. Schreiben Sie ein Beispiel, in dem Sie Ihre eigenen benutzerdefinierten Ausnahmen abfangen und behandeln.

Schreiben wir zunächst unsere eigene Ausnahmeklasse, die Exception erbt , und überschreiben ihren Konstruktor, der eine Fehlermeldung als Argument verwendet:

public class CustomException extends Exception {
 
 public CustomException(final String message) {
   super(message);
 }
}
Als nächstes werfen wir manuell einen und fangen ihn, genau wie wir es im Beispiel für die vorherige Frage getan haben:

try{
 throw new CustomException("Oops! Something went wrong =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
Wenn wir unseren Code ausführen, erhalten wir erneut die folgende Ausgabe:
Hoppla! Etwas ist schief gelaufen =(
Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 11 - 5Nun, das ist alles für heute! Wir sehen uns im nächsten Teil!
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION