JavaRush /Blog Java /Random-FR /Analyse des questions et réponses des entretiens pour dév...

Analyse des questions et réponses des entretiens pour développeur Java. Partie 7

Publié dans le groupe Random-FR
Salut tout le monde! La programmation est semée d’embûches. Et il n'y a pratiquement aucun sujet sur lequel vous ne trébucherez pas et n'aurez pas de bosses. Cela est particulièrement vrai pour les débutants. La seule façon de réduire cela est d’étudier. Cela s’applique en particulier aux analyses détaillées des sujets les plus fondamentaux. Aujourd'hui, je continue d'analyser plus de 250 questions issues d'entretiens avec des développeurs Java, qui couvrent bien des sujets de base. Je voudrais noter que la liste contient également des questions non standard qui vous permettent d'aborder des sujets courants sous un angle différent.Analyse des questions et réponses des entretiens pour développeur Java.  Partie 7 - 1

62. Qu'est-ce qu'un pool de chaînes et pourquoi est-il nécessaire ?

En mémoire en Java (Heap, dont nous parlerons plus tard), il y a une zone - String pool , ou pool de chaînes. Il est conçu pour stocker des valeurs de chaîne. En d'autres termes, lorsque vous créez une certaine chaîne, par exemple via des guillemets doubles :
String str = "Hello world";
une vérification est effectuée pour voir si le pool de chaînes a la valeur donnée. Si tel est le cas, la variable str se voit attribuer une référence à cette valeur dans le pool. Si ce n'est pas le cas, une nouvelle valeur sera créée dans le pool et une référence à celle-ci sera attribuée à la variable str . Regardons un exemple :
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true sera affiché à l'écran . Nous nous souvenons que == compare les références, ce qui signifie que ces deux références font référence à la même valeur du pool de chaînes. Ceci est fait afin de ne pas produire de nombreux objets identiques de type String en mémoire, car comme nous nous en souvenons, String est une classe immuable, et si nous avons de nombreuses références à la même valeur, il n'y a rien de mal à cela. Il n'est plus possible de se retrouver dans une situation dans laquelle la modification d'une valeur à un endroit entraîne des modifications pour plusieurs autres liens à la fois. Mais néanmoins, si nous créons une chaîne en utilisant new :
String str = new String("Hello world");
un objet distinct sera créé en mémoire qui stockera cette valeur de chaîne (et peu importe si nous avons déjà une telle valeur dans le pool de chaînes). En guise de confirmation :
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);
Nous obtiendrons deux fausses valeurs , ce qui signifie que nous avons ici trois valeurs différentes qui sont référencées. En fait, c’est pourquoi il est recommandé de créer des chaînes simplement en utilisant des guillemets doubles. Cependant, vous pouvez ajouter (ou obtenir une référence à) des valeurs dans un pool de chaînes lors de la création d'un objet à l'aide de new . Pour ce faire, nous utilisons la méthode de classe chaîne - intern() . Cette méthode crée de force une valeur dans le pool de chaînes ou obtient un lien vers celle-ci si elle y est déjà stockée. Voici un exemple :
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);
En conséquence, nous recevrons trois valeurs vraies dans la console , ce qui signifie que les trois variables font référence à la même chaîne.Analyse des questions et réponses des entretiens pour développeur Java.  Partie 7 - 2

63. Quels modèles GOF sont utilisés dans le pool de chaînes ?

Le motif GOF est clairement visible dans le pool de cordes - poids mouche , autrement appelé colon. Si vous voyez un autre modèle ici, partagez-le dans les commentaires. Eh bien, parlons du modèle léger. La légèreté est un modèle de conception structurelle dans lequel un objet qui se présente comme une instance unique à différents endroits du programme ne l'est en fait pas. Lightweight économise de la mémoire en partageant l'état partagé des objets entre eux, au lieu de stocker les mêmes données dans chaque objet. Pour comprendre l'essence, regardons l'exemple le plus simple. Disons que nous avons une interface employé :
public interface Employee {
   void work();
}
Et il existe quelques implémentations, par exemple, avocat :
public class Lawyer implements Employee {

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

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

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

   @Override
   public void work() {
       System.out.println("Ведение бухгалтерского отчёта....");
   }
}
Les méthodes sont très conditionnelles : il suffit de veiller à ce qu'elles soient appliquées. La même situation s'applique au constructeur. Grâce à la sortie de la console, nous verrons quand de nouveaux objets seront créés. Nous disposons également d'un service du personnel, dont la tâche est de délivrer le salarié demandé, et s'il n'est pas là, de l'embaucher et de délivrer en réponse à la demande :
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;
   }
}
Autrement dit, la logique est simple : s'il existe une unité donnée, retournez-la ; sinon, créez-la, placez-la dans un stockage (quelque chose comme un cache) et restituez-la. Voyons maintenant comment tout cela fonctionne :
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();
}
Et dans la console, en conséquence, il y aura une sortie :
L'avocat a été engagé. Résoudre les problèmes juridiques... Un comptable a été embauché. Tenir un rapport comptable.... Résoudre des problèmes juridiques... Tenir un rapport comptable.... Résoudre des problèmes juridiques... Tenir un rapport comptable.... Résoudre des problèmes juridiques... Tenir un rapport comptable.... Résoudre les problèmes juridiques. .. Tenir les rapports comptables...
Comme vous pouvez le constater, seuls deux objets ont été créés, qui ont été réutilisés plusieurs fois. L'exemple est très simple, mais il montre clairement comment l'utilisation de ce modèle peut économiser nos ressources. Eh bien, comme vous l’avez remarqué, la logique de ce modèle est très similaire à celle du pool d’assurance. Vous pouvez en savoir plus sur les types de modèles GOF dans cet article .Analyse des questions et réponses des entretiens pour développeur Java.  Partie 7 - 3

64. Comment diviser une chaîne en parties ? Veuillez fournir un exemple du code correspondant

Évidemment, cette question concerne la méthode split . La classe String propose deux variantes de cette méthode :
String split(String regex);
Et
String split(String regex);
regex est un séparateur de ligne - une expression régulière qui divise une chaîne en un tableau de chaînes, par exemple :
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
  System.out.println(s);
}
Les éléments suivants seront affichés sur la console :
Bonjour tout le monde, c'est Amigo !
Autrement dit, notre valeur de chaîne était divisée en un tableau de chaînes et le séparateur était un espace (pour la séparation, nous pourrions utiliser une expression régulière non spatiale "\\s" et juste une expression de chaîne " " ). La deuxième méthode surchargée a un argument supplémentaire - limit . limit - la valeur maximale autorisée du tableau résultant. Autrement dit, lorsque la chaîne a déjà été divisée en le nombre maximum autorisé de sous-chaînes, il n'y aura plus de division et le dernier élément aura un « reste » de la chaîne éventuellement sous-divisée. Exemple:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
  System.out.println(s);
}
Sortie de la console :
Bonjour tout le monde, c'est Amigo !
Comme nous pouvons le voir, sans la contrainte limit = 2 , le dernier élément du tableau pourrait être divisé en trois sous-chaînes.Analyse des questions et réponses des entretiens pour développeur Java.  Partie 7 - 4

65. Pourquoi un tableau de caractères est-il meilleur qu'une chaîne pour stocker un mot de passe ?

Il existe plusieurs raisons de préférer un tableau à une chaîne lors du stockage d'un mot de passe : 1. Pool de chaînes et immuabilité des chaînes. Lorsque nous utilisons un tableau ( char[] ), nous pouvons explicitement effacer les données une fois que nous en avons terminé. De plus, nous pouvons réécrire le tableau autant que nous le souhaitons, et le mot de passe valide ne sera nulle part dans le système, même avant le garbage collection (il suffit de remplacer quelques cellules par des valeurs invalides). En même temps, String est une classe immuable. Autrement dit, si nous voulons modifier sa valeur, nous en obtiendrons une nouvelle, tandis que l'ancienne restera dans le pool de chaînes. Si nous voulons supprimer la valeur String d'un mot de passe, cela peut être une tâche très difficile, car nous avons besoin du garbage collector pour supprimer la valeur du pool String , et il y a une forte probabilité que cette valeur String y reste pendant un certain temps. longue durée. Autrement dit, dans cette situation, String est inférieur au tableau char en termes de sécurité du stockage des données. 2. Si la valeur String est accidentellement affichée sur la console (ou les journaux), la valeur elle-même sera affichée :
String password = "password";
System.out.println("Пароль - " + password);
Sortie de la console :
Mot de passe
Dans le même temps, si vous affichez accidentellement un tableau sur la console :
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Пароль - " + arr);
Il y aura un charabia incompréhensible dans la console :
Mot de passe - [C@7f31245a
En fait, ce n'est pas du charabia, mais : [C est le nom de la classe est un tableau de caractères , @ est un séparateur, suivi de 7f31245a est un hashcode hexadécimal. 3. Le document officiel, le Java Cryptography Architecture Guide, mentionne explicitement le stockage des mots de passe dans char[] au lieu de String : « Il semblerait logique de collecter et de stocker un mot de passe dans un objet de type java.lang.String . Cependant, il y a une mise en garde ici : les objets String sont immuables, c'est-à-dire qu'aucune méthode n'est définie pour permettre au contenu d'un objet String d'être modifié (écrasé) ou annulé après utilisation. Cette fonctionnalité rend les objets String impropres au stockage d'informations sensibles telles que les mots de passe des utilisateurs. Au lieu de cela, vous devez toujours collecter et stocker les informations de sécurité sensibles dans un tableau de caractères.Analyse des questions et réponses des entretiens pour développeur Java.  Partie 7 à 5

Énumération

66. Donnez une brève description d'Enum en Java

Enum est une énumération, un ensemble de constantes de chaîne unies par un type commun. Déclaré via le mot-clé -enum . Voici un exemple avec enum - rôles valides dans une certaine école :
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
Les mots écrits en majuscules sont les mêmes constantes d'énumération qui sont déclarées de manière simplifiée, sans utiliser l' opérateur new . L'utilisation d'énumérations simplifie grandement la vie, car elles permettent d'éviter les erreurs et la confusion dans la dénomination (puisqu'il ne peut y avoir qu'une certaine liste de valeurs). Personnellement, je les trouve très pratiques lorsqu'ils sont utilisés dans la conception logique de Switch .

67. Enum peut-il implémenter des interfaces ?

Oui. Après tout, les énumérations doivent représenter plus que de simples collections passives (telles que les rôles). En Java, ils peuvent représenter des objets plus complexes avec certaines fonctionnalités, vous devrez donc peut-être leur ajouter des fonctionnalités supplémentaires. Cela vous permettra également d'utiliser les capacités du polymorphisme en remplaçant la valeur enum aux endroits où le type d'interface implémentée est requis.

68. Enum peut-il prolonger une classe ?

Non, ce n'est pas possible, car une énumération est une sous-classe par défaut de la classe générique Enum <T> , où T représente le type d'énumération générique. Ce n'est rien d'autre qu'une classe de base commune pour tous les types d'énumération de langage Java. La conversion de l'énumération en classe est effectuée par le compilateur Java au moment de la compilation. Cette extension n'est pas explicitement indiquée dans le code, mais est toujours présente de manière invisible.

69. Est-il possible de créer un Enum sans instances d'objet ?

Quant à moi, la question est un peu étrange, ou alors je ne l’ai pas bien comprise. J'ai deux interprétations : 1. Peut-il y avoir une énumération sans valeurs - oui, bien sûr, ce serait quelque chose comme une classe vide - cela n'a aucun sens :
public enum Role {
}
Et j'appelle :
var s = Role.values();
System.out.println(s);
Nous recevrons dans la console :
[Lflyweight.Rôle;@9f70c54
(tableau vide de valeurs de rôle ) 2. Est-il possible de créer une énumération sans l' opérateur new - oui, bien sûr. Comme je l'ai dit ci-dessus, vous n'avez pas besoin d'utiliser l' opérateur new pour les valeurs enum (énumérations) , car ce sont des valeurs statiques.

70. Pouvons-nous remplacer la méthode toString() pour Enum ?

Oui, bien sûr, vous pouvez remplacer la méthode toString() pour définir une manière spécifique d'afficher votre énumération lors de l'appel de la méthode toString (lors de la traduction de l'énumération en une chaîne normale, par exemple, pour la sortie vers la console ou les journaux).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Выбрана роль - " + super.toString();
   }
}
C'est tout pour aujourd'hui, jusqu'à la prochaine partie !Analyse des questions et réponses des entretiens pour développeur Java.  Partie 7 - 6
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION