JavaRush /Java-Blog /Random-DE /Java Core. Fragen für ein Interview, Teil 3
Vadim625
Level 27

Java Core. Fragen für ein Interview, Teil 3

Veröffentlicht in der Gruppe Random-DE
In den beiden vorherigen Artikeln haben wir einige wichtige Fragen besprochen, die Ihnen in Vorstellungsgesprächen am häufigsten gestellt werden. Es ist Zeit, weiterzumachen und sich die restlichen Fragen anzusehen.
Java Core.  Interviewfragen, Teil 3 - 1

Tiefes Kopieren und flaches Kopieren

Eine exakte Kopie des Originals ist sein Klon. In Java bedeutet dies, dass man ein Objekt mit einer ähnlichen Struktur wie das Originalobjekt erstellen kann. Die Methode clone()stellt diese Funktionalität bereit. Durch flaches Kopieren werden so wenig Informationen wie möglich kopiert. Standardmäßig ist das Klonen in Java flach, d. h. Object classweiß nichts über die Struktur der Klasse, die es kopiert. Beim Klonen führt die JVM Folgendes aus:
  1. Wenn eine Klasse nur Mitglieder primitiver Typen enthält, wird eine völlig neue Kopie des Objekts erstellt und ein Verweis auf dieses Objekt zurückgegeben.
  2. Wenn eine Klasse nicht nur Mitglieder primitiver Typen, sondern auch Mitglieder eines beliebigen anderen Klassentyps enthält, werden Verweise auf Objekte dieser Klassen kopiert. Daher haben beide Objekte die gleichen Referenzen.
Durch tiefes Kopieren wird alles dupliziert. Beim Deep Copying handelt es sich um zwei Sammlungen, von denen eine alle Elemente der ursprünglichen Sammlung dupliziert. Wir möchten eine Kopie so erstellen, dass Änderungen an irgendeinem Element der Kopie keine Auswirkungen auf die ursprüngliche Sammlung haben. Für das tiefe Klonen sind die folgenden Regeln erforderlich:
  1. Es besteht keine Notwendigkeit, Grunddaten separat zu kopieren.
  2. Alle Mitgliedsklassen in der Originalklasse müssen das Klonen unterstützen. Für jedes Klassenmitglied muss aufgerufen werden, super.clone()wenn die Methode überschrieben wird clone().
  3. Wenn ein Mitglied einer Klasse das Klonen nicht unterstützt, müssen Sie in der Klonmethode eine neue Instanz dieser Klasse erstellen und jedes ihrer Mitglieder mit allen Attributen einzeln in ein neues Klassenobjekt kopieren.
Erfahren Sie hier mehr über das Klonen

Was ist Synchronisation? Sperren auf Objektebene und Sperren auf Klassenebene?

Synchronisation bezieht sich auf Multithreading. Ein synchronisierter Codeblock kann jeweils nur von einem Thread ausgeführt werden. Mit Java können Sie mehrere Threads gleichzeitig verarbeiten. Dies kann dazu führen, dass zwei oder mehr Threads auf dasselbe Feld zugreifen möchten. Durch die Synchronisierung können Speicherfehler vermieden werden, die auftreten, wenn Speicherressourcen falsch genutzt werden. Wenn eine Methode als synchronisiert deklariert wird, hält der Thread seinen Monitor. Wenn zu diesem Zeitpunkt ein anderer Thread versucht, auf eine synchronisierte Methode zuzugreifen, wird der Thread blockiert und wartet darauf, dass der Monitor frei wird. Die Synchronisierung in Java wird mit dem speziellen synchronisierten Schlüsselwort erreicht . Auf diese Weise können Sie einzelne Blöcke oder Methoden in Ihrer Klasse markieren. Das synchronisierte Schlüsselwort kann nicht in Verbindung mit Klassenvariablen oder -attributen verwendet werden. Das Sperren auf Objektebene ist ein Mechanismus, wenn Sie eine nicht statische Methode oder einen nicht statischen Codeblock synchronisieren möchten, sodass nur ein Thread den Codeblock für eine bestimmte Instanz der Klasse ausführen kann. Dies sollte immer erfolgen, um die Thread-Sicherheit der Klasseninstanz zu gewährleisten. Sperren auf Klassenebene verhindern, dass mehrere Threads für alle verfügbaren Instanzen der Klasse in einen synchronisierten Block eintreten. Wenn es beispielsweise 100 Instanzen der DemoClass-Klasse gibt, kann zu einem bestimmten Zeitpunkt nur 1 Thread demoMethod() unter Verwendung einer der Variablen ausführen. Dies sollte immer erfolgen, um die Sicherheit des statischen Threads zu gewährleisten. Erfahren Sie hier mehr über die Synchronisierung.

Was ist der Unterschied zwischen sleep() und wait()?

Sleep()ist eine Methode, mit der der Vorgang um einige Sekunden verzögert wird. Im Fall von wait()befindet sich der Thread im Wartezustand, bis wir die Methode notify()or aufrufen notifyAll(). Der Hauptunterschied besteht darin, dass wait()die Monitorsperre aufgehoben wird, während sleep()die Sperre nicht aufgehoben wird. Wait()Wird für Multithread-Anwendungen verwendet und sleep()dient lediglich dazu, die Thread-Ausführung anzuhalten. Thread.sleep()Versetzt den aktuellen Thread für eine bestimmte Zeit in den Status „Nicht ausführbar“. Der Thread speichert den Status des Monitors, der vor dem Aufruf dieser Methode war. Wenn ein anderer Thread aufruft t.interrupt(), wird der Thread, der „eingeschlafen“ ist, aktiviert. Beachten Sie, dass es sich sleep()um eine statische Methode handelt, was bedeutet, dass sie sich immer auf den aktuellen Thread auswirkt (denjenigen, der die Methode ausführt sleep()). t.sleep()Ein häufiger Fehler besteht darin, „wo ist ein anderer Thread“ aufzurufen t; selbst wenn der aktuelle Thread, der die Methode aufgerufen hat, kein Thread sleep()ist . Versetzt den aktuellen Thread für eine Weile in den Status „Nicht ausführbar“, genau wie , jedoch mit einigen Nuancen. Wird für ein Objekt aufgerufen, nicht für einen Thread. Wir nennen dieses Objekt „Sperrobjekt“. Vor dem Aufruf muss der aktuelle Thread mit dem „Sperrobjekt“ synchronisiert werden; Danach wird diese Sperre aufgehoben und der Thread zur „Warteliste“ hinzugefügt, die dieser Sperre zugeordnet ist. Später kann sich ein anderer Thread mit demselben Sperrobjekt synchronisieren und das aufrufen . Diese Methode „weckt“ den ursprünglichen Thread auf, der noch wartet. Im Prinzip kann / mit / verglichen werden , nur dass der aktive Thread keinen direkten Zeiger auf den schlafenden Thread benötigt, sondern nur das gemeinsam genutzte Sperrobjekt kennen muss. Lesen Sie hier den detaillierten Unterschied.tObject.wait()sleep()Wait()lock.wait()wait()lock.notify()wait()notify()sleep()interrupt()

Ist es möglich, einer Referenzvariablen null zuzuweisen?

Nein, geht nicht. In Java muss die linke Seite des Zuweisungsoperators eine Variable sein. „This“ ist ein spezielles Schlüsselwort, das immer die aktuelle Instanz der Klasse angibt. Es ist nicht irgendeine Variable. Ebenso kann null nicht mit dem Schlüsselwort „super“ oder einem anderen ähnlichen Schlüsselwort einer Variablen zugewiesen werden.

Was ist der Unterschied zwischen && und &?

&- bitweise und &&- logisch.
  1. &bewertet beide Seiten der Operation;
  2. &&wertet die linke Seite der Operation aus. Wenn dies der Fall ist, wird weiterhin die rechte Seite ausgewertet.
Schauen Sie hier für ein tieferes Verständnis.

Wie überschreibe ich die Methoden equal() und hachCode()?

hashCode()und equals()Methoden werden in der Klasse definiert Object, die die übergeordnete Klasse für Java-Objekte ist. Aus diesem Grund erben alle Java-Objekte die Standardimplementierung für Methoden. Die Methode hashCode()wird verwendet, um eine eindeutige Ganzzahl für ein bestimmtes Objekt zu erhalten. Diese Ganzzahl wird verwendet, um den Speicherort eines Objekts zu bestimmen, wenn dieses Objekt beispielsweise an gespeichert werden muss HashTable. Gibt standardmäßig eine Darstellung der Adresse des Speicherorts hashCode()zurück , an dem das Objekt gespeichert ist. Wie der Name schon sagt, dient integerdie Methode dazu, einfach zu testen, ob zwei Objekte gleich sind. equls()Die Standardimplementierung prüft Objektreferenzen, um festzustellen, ob sie gleich sind. Nachfolgend finden Sie wichtige Richtlinien zum Neuladen dieser Methoden:
  1. hashCode()Verwenden Sie beim Generieren und equals(); immer die gleichen Objektattribute .
  2. Symmetrie. Diese. xWenn es für einige Objekte „true“ zurückgibt y x.equals(y), sollte es y.equals(x)„true“ zurückgeben.
  3. Reflexivität. Denn jedes Objekt x x.equals(x)muss true zurückgeben;
  4. Konsistenz. Für alle Objekte xund y x.equals(y)gibt dasselbe zurück, wenn sich die in Vergleichen verwendeten Informationen nicht ändern;
  5. Transitivität. Für alle Objekte x, yund z, wenn x.equals(y)es true zurückgibt und y.equals(z)true zurückgibt, sollte es x.equals(z)true zurückgeben;
  6. Immer wenn während der Anwendungsausführung eine Methode für dasselbe Objekt aufgerufen wird, sollte sie dieselbe Nummer zurückgeben, es sei denn, die verwendeten Informationen ändern sich. hashCodekann unterschiedliche Werte für identische Objekte in verschiedenen Anwendungsinstanzen zurückgeben;
  7. Wenn zwei Objekte laut gleich sind equals, müssen sie hashCodedieselben Werte zurückgeben;
  8. Die gegenteilige Anforderung ist optional. Zwei ungleiche Objekte können denselben HashCode zurückgeben. Um die Leistung zu verbessern, ist es jedoch besser, unterschiedliche Objekte unterschiedliche Codes zurückgeben zu lassen.
Lesen Sie hier interessante Fakten zu diesen Methoden.

Erzählen Sie uns von Zugriffsmodifikatoren

Java-Klassen, -Felder, -Konstruktoren und -Methoden können einen von vier verschiedenen Zugriffsmodifikatoren haben: private Wenn eine Methode oder Variable als privat markiert ist , kann nur Code innerhalb derselben Klasse auf die Variable zugreifen oder die Methode aufrufen. Code innerhalb von Unterklassen kann weder auf eine Variable oder Methode noch von einer anderen Klasse aus darauf zugreifen. Der private Zugriffsmodifikator wird am häufigsten für Konstruktoren, Methoden und Variablen verwendet. default Der Standardzugriffsmodifikator wird deklariert , wenn der Modifikator überhaupt nicht angegeben ist. Dieser Modifikator bedeutet, dass der Zugriff auf die Felder, Konstruktoren und Methoden einer bestimmten Klasse durch Code innerhalb der Klasse selbst und durch Code innerhalb von Klassen im selben Paket erfolgen kann. Unterklassen können nicht auf Methoden und Mitgliedsvariablen einer Oberklasse zugreifen, wenn sie als default deklariert sind , es sei denn, die Unterklasse befindet sich im selben Paket wie die Oberklasse. protected Der protected- Modifikator funktioniert genauso wie default , mit der Ausnahme, dass Unterklassen auch auf geschützte Methoden und Variablen der Oberklasse zugreifen können. Diese Aussage gilt auch dann, wenn sich die Unterklasse nicht im selben Paket wie die Oberklasse befindet. public Der Zugriffsmodifizierer public bedeutet, dass der gesamte Code auf die Klasse, ihre Variablen, Konstruktoren oder Methoden zugreifen kann, unabhängig davon, wo sich dieser Code befindet. Java Core.  Fragen für ein Interview, Teil 3 - 2

Was ist ein Garbage Collector? Können wir ihn anrufen?

Garbage Collection ist eine Funktion der automatischen Speicherverwaltung in vielen modernen Programmiersprachen wie Java und Sprachen im NET.Framework. Sprachen, die Garbage Collection verwenden, interpretieren Garbage Collection häufig in einer virtuellen Maschine wie der JVM. Die Speicherbereinigung dient zwei Zwecken: Ungenutzter Speicher soll freigegeben werden, und Speicher darf nicht freigegeben werden, wenn das Programm ihn noch verwendet. Können Sie die Speicherbereinigung manuell ausführen? Nein, System.gc()es gibt Ihnen so viel Zugriff wie möglich. Die beste Option besteht darin, die Methode aufzurufen System.gc(), die dem Garbage Collector anzeigt, dass er ausgeführt werden muss. Es gibt keine Möglichkeit, es sofort auszuführen, da der Garbage Collector nicht deterministisch ist. Darüber hinaus erfolgt laut Dokumentation OutOfMemoryErrorkeine Weiterleitung, wenn die virtuelle Maschine nach einer vollständigen Garbage Collection keinen Speicher freigeben konnte. Erfahren Sie hier mehr über Garbage Collector.

Was bedeutet das native Schlüsselwort? Erkläre im Detail

Das native Schlüsselwort wird verwendet, um anzugeben, dass die Methode in einer anderen Programmiersprache als einer Java-Datei implementiert ist. In der Vergangenheit wurden native Methoden verwendet. In aktuellen Java-Versionen wird dies seltener benötigt. Derzeit werden native Methoden benötigt, wenn:
  1. Sie müssen eine Bibliothek aus Java aufrufen, die in einer anderen Sprache geschrieben ist.
  2. Sie benötigen Zugriff auf System- oder Hardwareressourcen, auf die nur mit einer anderen Sprache (normalerweise C) zugegriffen werden kann. Tatsächlich können viele Systemfunktionen, die mit dem realen Computer interagieren (z. B. Festplatten oder Netzwerkdaten), nur mit der nativen Methode aufgerufen werden.
Die Nachteile der Verwendung nativer Methodenbibliotheken sind ebenfalls erheblich:
  1. JNI/JNA kann die JVM destabilisieren, insbesondere wenn Sie versuchen, etwas Komplexes zu tun. Wenn Ihre native Methode etwas falsch macht, besteht die Möglichkeit, dass die JVM abstürzt. Außerdem können schlimme Dinge passieren, wenn Ihre native Methode von mehreren Threads aufgerufen wird. Usw.
  2. Es ist schwieriger, ein Programm mit nativem Code zu debuggen.
  3. Nativer Code erfordert eine separate Erstellung von Frameworks, was zu Problemen bei der Portierung auf andere Plattformen führen kann.

Was ist Serialisierung?

In der Informatik ist Serialisierung im Kontext der Datenspeicherung und -übertragung der Prozess der Übersetzung einer Datenstruktur oder des Zustands eines Objekts in ein Format, das gespeichert und später in einer anderen Computerumgebung abgerufen werden kann. Nach dem Empfang einer Reihe von Bits werden diese gemäß dem Serialisierungsformat neu berechnet und können zur Erstellung eines semantisch identischen Klons des Originalobjekts verwendet werden. Java bietet eine automatische Serialisierung, die erfordert, dass das Objekt die Schnittstelle implementiert java.io.Serializable. Die Schnittstellenimplementierung markiert die Klasse als „serialisierbar“. Die java.io.Serializable-Schnittstelle verfügt über keine Serialisierungsmethoden, aber die serialisierbare Klasse kann optional Methoden definieren, die als Teil des Serialisierungs-/Diserialisierungsprozesses aufgerufen werden. Wenn Sie Änderungen an Klassen vornehmen, müssen Sie berücksichtigen, welche mit der Serialisierung kompatibel sind und welche nicht. Die vollständige Anleitung können Sie hier lesen. Ich werde die wichtigsten Punkte nennen: Inkompatible Änderungen:
  1. Ein Feld löschen;
  2. Eine Klasse in der Hierarchie nach oben oder unten verschieben;
  3. Ändern eines nichtstatischen Feldes in ein statisches oder eines nichttransienten in ein transientes Feld;
  4. Ändern des deklarierten primitiven Datentyps;
  5. Ändern Sie die Methode WriteObjectentweder ReadObjectso, dass Felder standardmäßig nicht mehr geschrieben oder gelesen werden.
  6. Klassenwechsel oder Serializableumgekehrt Externalizable;
  7. Ändern einer Enum- Klasse in eine Nicht-Enum-Klasse oder umgekehrt;
  8. Entfernen Serializableoder Externalizable;
  9. Hinzufügen writeReplaceeiner readResolveMethode zu einer Klasse.
Kompatible Änderungen:
  1. Felder hinzufügen;
  2. Klassen hinzufügen/entfernen;
  3. Methoden hinzufügen WriteObject/ReadObject[Methoden defaultReadObjectoder defaultWriteObjectmüssen am Anfang aufgerufen werden];
  4. Methoden entfernen WriteObject/ReadObject;
  5. Zusatz java.io.Serializable;
  6. Feldzugang ändern;
  7. Ein statisches Feld in ein nichtstatisches oder ein transientes in ein nichttransientes Feld ändern .
Links zu früheren Teilen: Java Core. Interviewfragen, Teil 1 Java Core. Interviewfragen, Teil 2 Originalartikel Viel Spaß beim Lernen!
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION