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 7

Veröffentlicht in der Gruppe Random-DE
Hallo alle miteinander! Die Programmierung ist voller Fallstricke. Und es gibt kaum ein Thema, bei dem Sie nicht stolpern und sich den Zeh stoßen. Dies gilt insbesondere für Anfänger. Die einzige Möglichkeit, Ihre Zehen zu retten, besteht darin, zu lernen. Insbesondere müssen Sie tief in die grundlegendsten Themen eintauchen. Heute werden wir die Überprüfung der häufigsten Fragen in Interviews für Java-Entwickler fortsetzen. Diese Interviewfragen eignen sich hervorragend zur Abdeckung grundlegender Themen. Beachten Sie, dass die Liste auch einige nicht so standardmäßige Fragen enthält, mit denen Sie häufig auftretende Probleme anders angehen können. Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 7 - 1

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

Ein Teil des einem Java-Programm zur Verfügung gestellten Speichers wird als Heap bezeichnet (über den wir später sprechen werden), und ein Teil des Heaps wird als String-Pool bezeichnet . Es dient zum Speichern von Zeichenfolgenwerten. Mit anderen Worten, wenn Sie beispielsweise eine Zeichenfolge erstellen, indem Sie doppelte Anführungszeichen wie diese verwenden:
String str = "Hello world";
Die JVM prüft, ob der String-Pool bereits 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 . Betrachten wir ein Beispiel:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true wird auf dem Bildschirm angezeigt. Denken Sie daran, dass == Referenzen vergleicht und diese beiden Variablen auf denselben Wert im String-Pool verweisen. Dadurch wird vermieden, dass viele identische String- Objekte im Speicher entstehen. Wir können dies tun, weil String , wie Sie sich erinnern werden, eine unveränderliche Klasse ist und es daher nichts Falsches ist, mehrere Referenzen auf denselben Wert zu haben. Nun kann es nicht mehr vorkommen, dass eine Änderung des Werts an einer Stelle zu Änderungen an mehreren anderen Referenzen führt. Wenn wir dennoch eine Zeichenfolge mit new erstellen :
String str = new String("Hello world");
Anschließend wird ein separates Objekt im Speicher erstellt und der angegebene Zeichenfolgenwert gespeichert (es spielt keine Rolle, ob sich dieser Wert bereits im Zeichenfolgenpool befindet). Um diese Behauptung zu bestätigen, bedenken Sie Folgendes:
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 Zeilen, die false angeben , was bedeutet, dass wir drei separate Zeichenfolgen haben. Aus diesem Grund sollten Sie Zeichenfolgen grundsätzlich einfach mit doppelten Anführungszeichen erstellen. Das heißt, es ist möglich, Werte im String-Pool hinzuzufügen (oder einen Verweis darauf zu erhalten), selbst wenn ein Objekt mit dem Schlüsselwort new erstellt wird. Dazu verwenden wir die intern() -Methode der String-Klasse. Diese Methode stellt sicher, dass wir den Wert entweder im String-Pool erstellen oder einen Verweis darauf erhalten, wenn er bereits vorhanden 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);
Dieser Code gibt dreimal „true“ an die Konsole aus, was uns sagt, dass alle drei Variablen auf dieselbe Zeichenfolge im Speicher verweisen.

63. Welche GoF-Entwurfsmuster werden im String-Pool verwendet?

Im String-Pool ist das GoF- Entwurfsmuster ein Fliegengewichtsmuster . Wenn Ihnen hier ein weiteres Designmuster aufgefallen ist, teilen Sie es in den Kommentaren mit. Hier sprechen wir über das Designmuster im Fliegengewicht. Es handelt sich um ein strukturelles Entwurfsmuster, bei dem ein Objekt, das sich an verschiedenen Stellen im Programm als eindeutige Instanz darstellt, tatsächlich nicht eindeutig ist. Das Fliegengewicht spart Speicher, indem es den gemeinsamen Zustand von Objekten speichert, anstatt identische Daten in jedem Objekt zu speichern. Um das Wesentliche zu verstehen, betrachten Sie dieses einfache Beispiel. Nehmen wir an, wir haben eine Mitarbeiterschnittstelle :
public interface Employee {
   void work();
}
Und es gibt einige Implementierungen, beispielsweise eine Lawyer- Klasse:
public class Lawyer implements Employee {

   public Lawyer() {
       System.out.println("A lawyer was hired.");
   }

   @Override
   public void work() {
       System.out.println("Settling legal issues...");
   }
}
Und ein Buchhalterkurs :
public class Accountant implements Employee {

   public Accountant() {
       System.out.println("An accountant was hired.");
   }

   @Override
   public void work() {
       System.out.println("Keeping accounting records...");
   }
}
Die Methoden sind völlig willkürlich – in diesem Beispiel müssen wir nur sehen, dass sie ausgeführt werden. Das Gleiche gilt für den Konstruktor. Die Konsolenausgabe teilt uns mit, wann neue Objekte erstellt werden. Wir verfügen außerdem über eine Personalabteilung, deren Aufgabe es ist, einen angeforderten Mitarbeiter zurückzugeben. Wenn dieser Mitarbeiter noch nicht zum Personal gehört, wird er eingestellt und die Personalabteilung gibt den neuen Mitarbeiter zurück:
public class HumanResourcesDepartment {
   private Map<String, Employee> currentEmployees = new HashMap<>();

   public Employee getEmployee(String type) throws Exception {
       Employee result;
       if (currentEmployees.containsKey(type)) {
           result = currentEmployees.get(type);
       } else {
           switch (type) {
               case "Accountant":
                   result = new Accountant();
                   currentEmployees.put(type, result);
                   break;
               case "Lawyer":
                   result = new Lawyer();
                   currentEmployees.put(type, result);
                   break;
               default:
                   throw new Exception("This employee is not on the staff!");
           }
       }
       return result;
   }
}
Die Logik ist also einfach: Wenn das gewünschte Objekt existiert, geben Sie es zurück; Wenn nicht, erstellen Sie es, legen Sie es in den Speicher (so etwas wie einen Cache) und geben Sie es zurück. Schauen wir uns nun an, wie das Ganze funktioniert:
public static void main(String[] args) throws Exception {
   HumanResourcesDepartment humanResourcesDepartment = new HumanResourcesDepartment();
   Employee empl1 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl2 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl3 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl4 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl5 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl6 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl7 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl8 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
   Employee empl9 = humanResourcesDepartment.getEmployee("Lawyer");
   empl1.work();
   Employee empl10 = humanResourcesDepartment.getEmployee("Accountant");
   empl2.work();
}
Folgendes sehen wir in der Konsole:
Ein Anwalt wurde beauftragt. Klärung rechtlicher Fragen... Ein Buchhalter wurde eingestellt. Buchhaltungsunterlagen führen... Rechtsfragen klären... Buchhaltungsunterlagen führen... Rechtsfragen klären... Buchhaltungsunterlagen führen... Rechtsfragen klären... Buchhaltungsunterlagen führen... Rechtsfragen klären... Buchhaltung führen Aufzeichnungen…
Wie Sie sehen, haben wir nur zwei Objekte erstellt und sie viele Male wiederverwendet. Das Beispiel ist sehr einfach, zeigt aber, wie dieses Entwurfsmuster unsere Ressourcen schonen kann. Wie Sie vielleicht bemerkt haben, ist die Logik dieses Musters der Logik eines Versicherungspools schmerzlich ähnlich. Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 7 - 2

64. Wie zerlegen wir eine Zeichenfolge in Teile? Geben Sie ein Beispiel für den relevanten Code

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);
Der Regex- Parameter ist das Trennzeichen – ein regulärer Ausdruck, der zum Aufteilen der Zeichenfolge in ein Array von Zeichenfolgen verwendet wird, zum Beispiel:
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
  System.out.println(s);
}
Die Konsole zeigt Folgendes an:
Hallo Welt, es ist Amigo!
Daher wurde unser String in ein Array von Strings aufgeteilt, wobei ein Leerzeichen als Trennzeichen verwendet wurde (anstelle des regulären Ausdrucks „\\s“ hätten wir auch den gewöhnlichen String-Ausdruck „ “ verwenden können ). Die zweite, überladene Variante verfügt über einen zusätzlichen Limit- Parameter. limit ist die maximal zulässige Größe des resultierenden Arrays. Mit anderen Worten: Sobald die Zeichenfolge in die maximal zulässige Anzahl von Teilzeichenfolgen aufgeteilt wurde, stoppt die Aufteilung und das letzte Element enthält alle „Reste“ der möglicherweise nicht 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 limit = 2 in drei Teilzeichenfolgen aufgeteilt werden.

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. Der String-Pool und die String-Unveränderlichkeit.

Wenn wir ein Array ( char[] ) verwenden, können wir die Daten explizit löschen, sobald wir mit der Arbeit damit fertig sind. Wir können das Array auch beliebig oft überschreiben und so das Passwort noch vor der Garbage Collection aus dem System entfernen (es reicht aus, ein paar Zellen in ungültige Werte zu ändern). Im Gegensatz dazu ist String eine unveränderliche Klasse. Das heißt, wenn wir den Wert eines String- Objekts ändern möchten, erhalten wir ein neues, das alte bleibt jedoch im String-Pool. Wenn wir den String mit dem Passwort entfernen möchten , stehen wir vor einer komplizierten Aufgabe, da wir den Garbage Collector benötigen, um diesen Wert aus dem String-Pool zu entfernen, dieser String aber wahrscheinlich noch lange dort bleiben wird. Das heißt, wenn es um die sichere Speicherung von Daten geht, ist String einem char- Array unterlegen.

2. Wenn wir den String- Wert an die Konsole (oder ein Protokoll) ausgeben , erhalten wir:

String password = "password";
System.out.println("Password - " + password);
Konsolenausgabe:
Passwort - Passwort
Und wenn Sie das Array zufällig auf der Konsole ausgeben:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Password - " + arr);
Die Konsole zeigt unverständliches Kauderwelsch an:
Passwort – [C@7f31245a
Tatsächlich ist es kein Kauderwelsch. So verstehen Sie, was Sie sehen: [C ist der Klassenname – char- Array, @ ist ein Trennzeichen und dann ist 7f31245a ein hexadezimaler Hash-Code.

3. Im offiziellen Java Cryptography Architecture (JCA)-Referenzhandbuch wird ausdrücklich erwähnt, dass Passwörter in einem char[] statt in einem String gespeichert werden :

„Es erscheint logisch, das Passwort in einem Objekt vom Typ java.lang.String zu sammeln und zu speichern . Hier ist jedoch die Einschränkung: Objekte vom Typ String sind unveränderlich, d. h. es sind keine Methoden definiert, die es Ihnen ermöglichen, sie zu ändern (überschreiben). oder den Inhalt eines Strings nach der Verwendung auf Null setzen. Diese Funktion macht String- Objekte ungeeignet zum Speichern sicherheitsrelevanter Informationen wie Benutzerkennwörter. Sie sollten stattdessen immer sicherheitsrelevante Informationen in einem char-Array sammeln und speichern.“ Erkundung der Fragen und Antworten aus einem Vorstellungsgespräch für eine Stelle als Java-Entwickler.  Teil 7 - 3

Aufzählung

66. Geben Sie eine kurze Beschreibung von Enum in Java

Enum ist die Abkürzung für Enumeration, also eine Menge von String-Konstanten, die durch einen gemeinsamen Typ vereint sind. Wir deklarieren eines mit dem Schlüsselwort enum . Hier ist ein Beispiel mit enum : erlaubte Rollen auf einem Schulcampus:
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
Die in Großbuchstaben geschriebenen Wörter sind die Aufzählungskonstanten. Sie werden auf vereinfachte Weise ohne den neuen Operator deklariert. Die Verwendung von Aufzählungen macht das Leben viel einfacher, da sie dazu beitragen, Fehler und Verwirrung bei Namen zu vermeiden (da die Liste die einzigen gültigen Werte definiert). Für mich sind sie in der Schalterkonstruktion sehr praktisch .

67. Kann eine Enum Schnittstellen implementieren (mit dem Schlüsselwort „implements“)?

Ja. Schließlich sollten Aufzählungen mehr als nur passive Mengen darstellen (z. B. Rollen auf einem Schulgelände). In Java können sie komplexere Objekte darstellen, daher müssen Sie ihnen möglicherweise zusätzliche Funktionalität hinzufügen. Dadurch können Sie auch den Polymorphismus nutzen, indem Sie den Enum -Wert an Stellen ersetzen, an denen der implementierte Schnittstellentyp benötigt wird.

68. Kann Enum eine Klasse erweitern (mit dem Schlüsselwort „extens“)?

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

69. Ist es möglich, eine Aufzählung ohne Instanzen von Objekten zu erstellen?

Diese Frage ist etwas verwirrend und ich bin mir nicht sicher, ob ich sie vollständig verstehe. Ich habe zwei Interpretationen: 1. Kann man eine Aufzählung ohne Werte haben? Ja, natürlich, aber es wäre wie eine leere Klasse – sinnlos, zum Beispiel
public enum Role {
}
Und wenn wir anrufen:
var s = Role.values();
System.out.println(s);
In der Konsole erhalten wir Folgendes:
[Lflyweight.Role;@9f70c54
(ein 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, verwenden Sie den neuen Operator nicht für Aufzählungswerte, da es sich um statische Werte handelt.

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

Ja, natürlich können Sie die toString()- Methode überschreiben, um zu definieren, wie Ihre Aufzählung angezeigt werden soll , wenn die toString- Methode aufgerufen wird (wenn Sie eine Aufzählung in einen gewöhnlichen String konvertieren, um ihn beispielsweise auf der Konsole oder in Protokollen auszugeben).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Selected role - " + super.toString();
   }
}
Das ist alles für mich heute. Bis zum nächsten Teil!
Kommentare
  • Beliebt
  • Neu
  • Alt
Du musst angemeldet sein, um einen Kommentar schreiben zu können
Auf dieser Seite gibt es noch keine Kommentare