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 7

Veröffentlicht in der Gruppe Random-DE
Hallo alle miteinander! Die Programmierung ist voller Fallstricke. Und es gibt praktisch kein Thema, bei dem man nicht stolpert und Stolpersteine ​​bekommt. Dies gilt insbesondere für Anfänger. Die einzige Möglichkeit, dies zu reduzieren, ist das Lernen. Dies gilt insbesondere für detaillierte Analysen der grundlegendsten Themen. Heute analysiere ich weiterhin über 250 Fragen aus Interviews mit Java-Entwicklern, die grundlegende Themen gut abdecken. Ich möchte darauf hinweisen, dass die Liste auch einige nicht standardmäßige Fragen enthält, die es Ihnen ermöglichen, häufige Themen aus einem anderen Blickwinkel zu betrachten.Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 7 - 1

62. Was ist ein String-Pool und warum wird er benötigt?

Im Speicher in Java (Heap, über den wir später sprechen werden) gibt es einen Bereich – String-Pool oder String-Pool. Es dient zum Speichern von Zeichenfolgenwerten. Mit anderen Worten, wenn Sie eine bestimmte Zeichenfolge erstellen, beispielsweise durch doppelte Anführungszeichen:
String str = "Hello world";
Es wird geprüft, ob der String-Pool den angegebenen Wert hat. Wenn dies der Fall ist, wird der Variablen str eine Referenz auf diesen Wert im Pool zugewiesen. Ist dies nicht der Fall, wird im Pool ein neuer Wert erstellt und der Variable str ein Verweis darauf zugewiesen . Schauen wir uns ein Beispiel an:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true wird auf dem Bildschirm angezeigt . Wir erinnern uns, dass == Referenzen vergleicht – das heißt, diese beiden Referenzen verweisen auf denselben Wert aus dem String-Pool. Dies geschieht, um nicht viele identische Objekte vom Typ String im Speicher zu erzeugen, denn wie wir uns erinnern, ist String eine unveränderliche Klasse, und wenn wir viele Verweise auf denselben Wert haben, ist daran nichts auszusetzen. Es ist jetzt unmöglich, dass eine Situation, in der die Änderung eines Werts an einer Stelle mehrere andere Links gleichzeitig ändert, geändert wird. Aber dennoch, wenn wir mit new einen String erstellen :
String str = new String("Hello world");
Im Speicher wird ein separates Objekt erstellt, das diesen String-Wert speichert (und es spielt keine Rolle, ob wir bereits einen solchen Wert im String-Pool haben). Als Bestätigung:
String firstStr = new String("Hello world");
String secondStr = "Hello world";
String thirdStr = new String("Hello world");
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
Wir erhalten zwei falsche Werte , was bedeutet, dass wir hier drei verschiedene Werte haben, auf die verwiesen wird. Aus diesem Grund empfiehlt es sich, Zeichenfolgen einfach mit doppelten Anführungszeichen zu erstellen. Sie können einem String-Pool jedoch Werte hinzufügen (oder einen Verweis darauf abrufen), wenn Sie ein Objekt mit new erstellen . Dazu verwenden wir die String-Klassenmethode - intern() . Diese Methode erstellt zwangsweise einen Wert im String-Pool oder ruft einen Link dazu ab, wenn dieser bereits dort gespeichert ist. Hier ist ein Beispiel:
String firstStr = new String("Hello world").intern();
String secondStr = "Hello world";
String thirdStr = new String("Hello world").intern();
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
System.out.println(secondStr == thirdStr);
Als Ergebnis erhalten wir in der Konsole drei wahre Werte , was bedeutet, dass sich alle drei Variablen auf denselben String beziehen.Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 7 - 2

63. Welche GOF-Muster werden im String-Pool verwendet?

Das GOF- Muster ist im Saitenpool deutlich sichtbar – Fliegengewicht , auch Siedler genannt. Wenn Sie hier eine andere Vorlage sehen, teilen Sie sie in den Kommentaren. Nun, lassen Sie uns über die Lightweight-Vorlage sprechen. Lightweight ist ein strukturelles Entwurfsmuster, bei dem ein Objekt, das sich an verschiedenen Stellen im Programm als eindeutige Instanz darstellt, dies tatsächlich nicht ist. Lightweight spart Speicher, indem es den gemeinsamen Status von Objekten untereinander teilt, anstatt in jedem Objekt dieselben Daten zu speichern. Um das Wesentliche zu verstehen, schauen wir uns das einfachste Beispiel an. Nehmen wir an, wir haben eine Mitarbeiterschnittstelle:
public interface Employee {
   void work();
}
Und es gibt einige Implementierungen, zum Beispiel Anwalt:
public class Lawyer implements Employee {

   public Lawyer() {
       System.out.println("Юрист взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Решение юридических вопросов...");
   }
}
Und der Buchhalter:
public class Accountant implements Employee{

   public Accountant() {
       System.out.println("Бухгалтер взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Ведение бухгалтерского отчёта....");
   }
}
Die Methoden sind sehr bedingt: Wir müssen nur dafür sorgen, dass sie durchgeführt werden. Die gleiche Situation gilt für den Konstruktor. Dank der Konsolenausgabe werden wir sehen, wann neue Objekte erstellt werden. Wir haben auch eine Mitarbeiterabteilung, deren Aufgabe es ist, den gesuchten Mitarbeiter zu vermitteln. Wenn er nicht da ist, stellen Sie ihn ein und stellen Sie als Antwort auf die Anfrage Folgendes aus:
public class StaffDepartment {
   private Map<String, Employee> currentEmployees = new HashMap<>();

   public Employee receiveEmployee(String type) throws Exception {
       Employee result;
       if (currentEmployees.containsKey(type)) {
           result = currentEmployees.get(type);
       } else {
           switch (type) {
               case "Бухгалтер":
                   result = new Accountant();
                   currentEmployees.put(type, result);
                   break;
               case "Юрист":
                   result = new Lawyer();
                   currentEmployees.put(type, result);
                   break;
               default:
                   throw new Exception("Данный сотрудник в штате не предусмотрен!");
           }
       }
       return result;
   }
}
Das heißt, die Logik ist einfach: Wenn es eine bestimmte Einheit gibt, geben Sie sie zurück; wenn nicht, erstellen Sie sie, legen Sie sie in den Speicher (so etwas wie einen Cache) und geben Sie sie zurück. Schauen wir uns nun an, wie das Ganze funktioniert:
public static void main(String[] args) throws Exception {
   StaffDepartment staffDepartment = new StaffDepartment();
   Employee empl1  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl2  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl3  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl4  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl5  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl6  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl7  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl8  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl9  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl10  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
}
Und in der Konsole erscheint dementsprechend eine Ausgabe:
Der Anwalt wurde beauftragt. Lösung rechtlicher Probleme... Ein Buchhalter wurde eingestellt. Führen eines Buchhaltungsberichts.... Lösen rechtlicher Probleme... Führen eines Buchhaltungsberichts.... Lösen rechtlicher Probleme... Führen eines Buchhaltungsberichts.... Lösen rechtlicher Probleme... Führen eines Buchhaltungsberichts.... Lösung rechtlicher Probleme. .. Führung von Buchhaltungsberichten...
Wie Sie sehen, wurden nur zwei Objekte erstellt, die viele Male wiederverwendet wurden. Das Beispiel ist sehr einfach, zeigt aber deutlich, wie der Einsatz dieser Vorlage unsere Ressourcen schonen kann. Nun, wie Sie bemerkt haben, ist die Logik dieses Musters der Logik des Versicherungspools sehr ähnlich. Weitere Informationen zu den Arten von GOF- Mustern finden Sie in diesem Artikel .Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 7 - 3

64. Wie zerlege ich eine Zeichenfolge in Teile? Bitte geben Sie ein Beispiel für den entsprechenden Code an

Bei dieser Frage geht es offensichtlich um die Split- Methode . Die String- Klasse verfügt über zwei Varianten dieser Methode:
String split(String regex);
Und
String split(String regex);
Regex ist ein Zeilentrennzeichen – ein regulärer Ausdruck, der eine Zeichenfolge in ein Array von Zeichenfolgen unterteilt, zum Beispiel:
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
  System.out.println(s);
}
Folgendes wird auf der Konsole ausgegeben:
Hallo Welt, es ist Amigo!
Das heißt, unser String-Wert wurde in ein Array von Strings unterteilt und das Trennzeichen war ein Leerzeichen (zur Trennung könnten wir einen regulären Ausdruck ohne Leerzeichen „\\s“ und einfach einen String-Ausdruck „ “ verwenden ). Die zweite, überladene Methode hat ein zusätzliches Argument – ​​limit . limit – der maximal zulässige Wert des resultierenden Arrays. Das heißt, wenn die Zeichenfolge bereits in die maximal zulässige Anzahl von Teilzeichenfolgen aufgeteilt wurde, erfolgt keine weitere Aufteilung und das letzte Element enthält einen „Rest“ der möglicherweise nicht ausreichend aufgeteilten Zeichenfolge. Beispiel:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
  System.out.println(s);
}
Konsolenausgabe:
Hallo Welt, es ist Amigo!
Wie wir sehen können, könnte das letzte Element des Arrays ohne die Einschränkung limit = 2 in drei Teilzeichenfolgen aufgeteilt werden.Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 7 - 4

65. Warum ist ein Zeichenarray zum Speichern eines Passworts besser als eine Zeichenfolge?

Es gibt mehrere Gründe, beim Speichern eines Passworts ein Array einem String vorzuziehen: 1. String-Pool und String-Unveränderlichkeit. Wenn wir ein Array ( char[] ) verwenden, können wir die Daten explizit löschen, nachdem wir damit fertig sind. Außerdem können wir das Array so oft umschreiben, wie wir wollen, und das gültige Passwort wird nirgendwo im System sein, auch nicht vor der Speicherbereinigung (es reicht aus, ein paar Zellen in ungültige Werte zu ändern). Gleichzeitig ist String eine unveränderliche Klasse. Das heißt, wenn wir seinen Wert ändern möchten, erhalten wir einen neuen, während der alte im String-Pool verbleibt. Wenn wir den String- Wert eines Passworts entfernen möchten , kann dies eine sehr schwierige Aufgabe sein, da wir den Garbage Collector benötigen, um den Wert aus dem String-Pool zu entfernen , und die Wahrscheinlichkeit hoch ist, dass dieser String- Wert dort für eine Weile verbleibt lange Zeit. Das heißt, in dieser Situation ist String hinsichtlich der Datenspeichersicherheit dem char- Array unterlegen. 2. Wenn der String- Wert versehentlich an die Konsole (oder Protokolle) ausgegeben wird, wird der Wert selbst angezeigt:
String password = "password";
System.out.println("Пароль - " + password);
Konsolenausgabe:
Passwort
Wenn Sie gleichzeitig versehentlich ein Array an die Konsole ausgeben:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Пароль - " + arr);
In der Konsole wird es ein unverständliches Kauderwelsch geben:
Passwort – [C@7f31245a
Eigentlich kein Kauderwelsch, aber: [C ist der Klassenname, ein char- Array , @ ist ein Trennzeichen, gefolgt von 7f31245a ist ein hexadezimaler Hashcode. 3. Das offizielle Dokument, der Java Cryptography Architecture Guide, erwähnt ausdrücklich das Speichern von Passwörtern in char[] anstelle von String : „Es erscheint logisch, ein Passwort in einem Objekt vom Typ java.lang.String zu sammeln und zu speichern . Allerdings gibt es hier eine Einschränkung: String- Objekte sind unveränderlich, d. h. es sind keine Methoden definiert, die es ermöglichen, den Inhalt eines String- Objekts nach der Verwendung zu ändern (überschreiben) oder auf Null zu setzen. Diese Funktion macht String- Objekte ungeeignet zum Speichern vertraulicher Informationen wie Benutzerkennwörter. Stattdessen sollten Sie sensible Sicherheitsinformationen immer in einem Zeichenarray sammeln und speichern.“Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 7 - 5

Aufzählung

66. Geben Sie eine kurze Beschreibung von Enum in Java

Enum ist eine Aufzählung, eine Menge von String-Konstanten, die durch einen gemeinsamen Typ vereint sind. Deklariert durch das Schlüsselwort -enum . Hier ist ein Beispiel mit Enumeration – gültige Rollen in einer bestimmten Schule:
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
Die in Großbuchstaben geschriebenen Wörter sind dieselben Aufzählungskonstanten, die auf vereinfachte Weise ohne Verwendung des neuen Operators deklariert werden . Die Verwendung von Aufzählungen vereinfacht das Leben erheblich, da sie dazu beitragen, Fehler und Verwirrung bei der Benennung zu vermeiden (da es nur eine bestimmte Liste von Werten geben kann). Persönlich finde ich sie sehr praktisch, wenn sie im Logikdesign von Switch verwendet werden .

67. Kann Enum Schnittstellen implementieren?

Ja. Schließlich müssen Aufzählungen mehr als nur passive Sammlungen (z. B. Rollen) darstellen. In Java können sie komplexere Objekte mit einer gewissen Funktionalität darstellen, daher müssen Sie ihnen möglicherweise zusätzliche Funktionalität hinzufügen. Dadurch können Sie auch die Möglichkeiten des Polymorphismus nutzen, indem Sie den Enum- Wert an Stellen ersetzen, an denen der Typ der implementierten Schnittstelle erforderlich ist.

68. Kann Enum eine Klasse erweitern?

Nein, das ist nicht möglich, da eine Aufzählung eine Standardunterklasse der generischen Klasse Enum <T> ist , wobei T den generischen Aufzählungstyp darstellt. Es ist nichts anderes als eine gemeinsame Basisklasse für alle Enum-Typen der Java-Sprache. Die Konvertierung von Enum in Klasse erfolgt durch den Java-Compiler zur Kompilierungszeit. Diese Erweiterung wird im Code nicht explizit angegeben, ist aber immer unsichtbar vorhanden.

69. Ist es möglich, eine Enum ohne Objektinstanzen zu erstellen?

Für mich ist die Frage etwas seltsam, oder ich habe sie nicht ganz verstanden. Ich habe zwei Interpretationen: 1. Kann es eine Aufzählung ohne Werte geben – ja natürlich wäre es so etwas wie eine leere Klasse – bedeutungslos:
public enum Role {
}
Und rufe:
var s = Role.values();
System.out.println(s);
Wir erhalten in der Konsole:
[Lflyweight.Role;@9f70c54
(leeres Array von Rollenwerten ) 2. Ist es möglich, eine Aufzählung ohne den neuen Operator zu erstellen – ja, natürlich. Wie ich oben sagte, müssen Sie den neuen Operator nicht für Aufzählungswerte (Enumerationen) verwenden , da es sich um statische Werte handelt.

70. Können wir die toString()-Methode für Enum überschreiben?

Ja, natürlich können Sie die toString()- Methode überschreiben , um eine bestimmte Art der Anzeige Ihrer Aufzählung beim Aufruf der toString- Methode zu definieren (beim Übersetzen der Aufzählung in einen regulären String, beispielsweise für die Ausgabe auf der Konsole oder in Protokollen).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Выбрана роль - " + super.toString();
   }
}
Das ist alles für heute, bis zum nächsten Teil!Analyse von Fragen und Antworten aus Interviews für Java-Entwickler.  Teil 7 - 6
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION