CodeGym/Blog Java/Random-FR/Explorer les questions et réponses d'un entretien d'embau...
John Squirrels
Niveau 41
San Francisco

Explorer les questions et réponses d'un entretien d'embauche pour un poste de développeur Java. Partie 7

Publié dans le groupe Random-FR
membres
Salut tout le monde! La programmation est semée d’embûches. Et il n’y a pratiquement pas un seul sujet qui ne vous fasse trébucher et vous cogner l’orteil. Cela est particulièrement vrai pour les débutants. La seule façon de sauver vos orteils est d’apprendre. En particulier, vous devez approfondir les sujets les plus fondamentaux. Aujourd'hui, nous allons poursuivre l'examen des questions les plus populaires lors des entretiens avec les développeurs Java. Ces questions d’entretien font un excellent travail en couvrant des sujets de base. Notez que la liste comprend également des questions pas si standards qui vous permettent d'aborder différemment les problèmes courants. Explorer les questions et réponses d'un entretien d'embauche pour un poste de développeur Java.  Partie 7 - 1

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

Une partie de la mémoire mise à disposition d'un programme Java s'appelle le tas (dont nous parlerons plus tard), et une partie du tas s'appelle le pool de chaînes . C'est pour stocker les valeurs de chaîne. En d’autres termes, lorsque vous créez une chaîne, par exemple en utilisant des guillemets doubles comme celui-ci :
String str = "Hello world";
La JVM vérifie si le pool de chaînes a déjà la valeur spécifié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 est créée dans le pool et une référence à celle-ci est affectée à la variable str . Prenons un exemple :
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true sera affiché à l’écran. N'oubliez pas que == compare les références et que ces deux variables pointent vers la même valeur dans le pool de chaînes. Cela permet d'éviter de produire de nombreux objets String identiques en mémoire. Nous pouvons le faire car, comme vous vous en souviendrez, String est une classe immuable, il n'y a donc rien de mal à avoir plusieurs références à la même valeur. Il est désormais impossible de se retrouver dans une situation où la modification de la valeur à un endroit entraîne des modifications dans plusieurs autres références. Pourtant, si nous créons une chaîne en utilisant new :
String str = new String("Hello world");
puis un objet distinct est créé en mémoire et stocke la valeur de chaîne spécifiée (peu importe si cette valeur est déjà dans le pool de chaînes). Pour confirmer cette affirmation, considérez ceci :
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 lignes indiquant false , ce qui signifie que nous aurons trois chaînes distinctes. Fondamentalement, c'est pourquoi vous devez créer des chaînes simplement en utilisant des guillemets doubles. Cela dit, il est possible d'ajouter (ou d'obtenir une référence à) des valeurs dans le pool de chaînes même lors de la création d'un objet à l'aide du nouveau mot-clé. Pour ce faire, nous utilisons la méthode intern() de la classe String . Cette méthode garantit que soit nous créons la valeur dans le pool de chaînes, soit nous obtenons une référence à celle-ci si elle est déjà là. 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);
Ce code affiche trois fois true sur la console, ce qui nous indique que les trois variables font référence à la même chaîne en mémoire.

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

Dans le pool de chaînes, le modèle de conception GoF est un modèle de poids mouche . Si vous avez remarqué un autre modèle de conception ici, partagez-le dans les commentaires. Ici, nous parlerons du modèle de conception des poids mouches. Il s'agit d'un modèle de conception structurelle dans lequel un objet qui se représente comme une instance unique à différents endroits du programme n'est en réalité pas unique. Le poids mouche économise de la mémoire en stockant l'état partagé des objets au lieu de stocker des données identiques dans chaque objet. Pour comprendre l’essentiel, considérons cet exemple élémentaire. Disons que nous avons une interface Employé :
public interface Employee {
   void work();
}
Et il a quelques implémentations, comme une classe Lawyer :
public class Lawyer implements Employee {

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

   @Override
   public void work() {
       System.out.println("Settling legal issues...");
   }
}
Et un cours de Comptable :
public class Accountant implements Employee {

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

   @Override
   public void work() {
       System.out.println("Keeping accounting records...");
   }
}
Les méthodes sont entièrement arbitraires — pour cet exemple, il suffit de voir qu'elles sont en cours d'exécution. Il en va de même pour le constructeur. La sortie de la console nous indique quand de nouveaux objets sont créés. Nous disposons également d'un service des ressources humaines dont la tâche est de renvoyer un employé demandé. Si cet employé ne fait pas déjà partie de l'équipe, il est alors embauché et le service RH renvoie le nouvel employé :
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;
   }
}
La logique est donc simple : si l’objet souhaité existe, renvoyez-le ; sinon, créez-le, mettez-le en stockage (quelque chose comme un cache) et renvoyez-le. Voyons maintenant comment tout cela fonctionne :
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();
}
Voici ce que nous verrons dans la console :
Un avocat a été engagé. Régler les problèmes juridiques... Un comptable a été embauché. Tenir des registres comptables... Régler des questions juridiques... Tenir des registres comptables... Régler des problèmes juridiques... Tenir des registres comptables... Régler des problèmes juridiques... Tenir des registres comptables... Régler des problèmes juridiques... Tenir une comptabilité enregistrements…
Comme vous pouvez le constater, nous n’avons créé que deux objets et les avons réutilisés plusieurs fois. L'exemple est très simple, mais il montre comment ce modèle de conception peut préserver nos ressources. Comme vous l’avez peut-être remarqué, la logique de ce schéma ressemble douloureusement à celle d’un pool d’assurance. Explorer les questions et réponses d'un entretien d'embauche pour un poste de développeur Java.  Partie 7 - 2

64. Comment diviser une chaîne en parties ? Donnez un exemple du code pertinent

É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);
Le paramètre regex est le délimiteur — une expression régulière utilisée pour diviser la 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);
}
La console affichera :
Bonjour tout le monde, c'est Amigo !
Ainsi, notre chaîne a été divisée en un tableau de chaînes, en utilisant un espace comme délimiteur (au lieu de l'expression régulière "\\s" , nous aurions également pu utiliser l'expression de chaîne ordinaire " " ). La deuxième variante, surchargée, possède un paramètre de limite supplémentaire . limit est la taille maximale autorisée du tableau résultant. En d'autres termes, une fois que la chaîne a été divisée en nombre maximum autorisé de sous-chaînes, la division s'arrête et le dernier élément contiendra tous les "restes" de la chaîne éventuellement non 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 limit = 2 , le dernier élément du tableau pourrait être divisé en trois sous-chaînes.

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. Le pool de chaînes et l’immuabilité des chaînes.

Lorsque nous utilisons un tableau ( char[] ), nous pouvons explicitement effacer les données une fois que nous avons fini de travailler avec. Nous pouvons également écraser le tableau autant que nous le souhaitons, en éliminant le mot de passe du système avant même le garbage collection (il suffit de remplacer quelques cellules par des valeurs invalides). En revanche, String est une classe immuable. Cela signifie que si nous voulons changer la valeur d'un objet String , nous en obtiendrons un nouveau, mais l'ancien restera dans le pool de chaînes. Si nous voulons supprimer la chaîne contenant le mot de passe, nous sommes confrontés à une tâche compliquée puisque nous avons besoin du garbage collector pour supprimer cette valeur du pool de chaînes, mais cette chaîne y restera probablement pendant longtemps. Autrement dit, lorsqu'il s'agit de stocker des données en toute sécurité, String est inférieur à un tableau de caractères .

2. Si nous envoyons la valeur String sur la console (ou dans un journal), alors nous obtenons :

String password = "password";
System.out.println("Password - " + password);
Sortie de la console :
Mot de passe - mot de passe
Et si vous imprimez le tableau sur la console :
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Password - " + arr);
la console affichera un charabia incompréhensible :
Mot de passe - [C@7f31245a
En fait, ce n’est pas du charabia. Voici comment donner un sens à ce que vous voyez : [C est le nom de la classe - tableau de caractères , @ est un délimiteur, puis 7f31245a est un code de hachage hexadécimal.

3. Le guide de référence officiel Java Cryptography Architecture (JCA) mentionne explicitement le stockage des mots de passe dans un char[] au lieu d'une String :

"Il semblerait logique de collecter et de stocker le mot de passe dans un objet de type java.lang.String . Cependant, voici la mise en garde : les objets de type String sont immuables, c'est-à-dire qu'aucune méthode n'est définie qui vous permet de modifier (écraser) ou mettez à zéro le contenu d'une chaîne après utilisation. Cette fonctionnalité rend les objets String impropres au stockage d'informations sensibles en matière de sécurité telles que les mots de passe des utilisateurs. Vous devez plutôt toujours collecter et stocker des informations sensibles en matière de sécurité dans un tableau de caractères. Explorer les questions et réponses d'un entretien d'embauche pour un poste de développeur Java.  Partie 7 - 3

Énumération

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

Enum est l'abréviation de énumération, qui est un ensemble de constantes de chaîne unies par un type commun. Nous en déclarons un en utilisant le mot-clé enum . Voici un exemple avec enum : rôles autorisés sur certains campus scolaires :
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
Les mots écrits en majuscules sont les constantes d'énumération. Ils sont déclarés de manière simplifiée, sans le nouvel opérateur. L'utilisation d'énumérations rend la vie beaucoup plus facile puisqu'elles permettent d'éviter les erreurs et les confusions dans les noms (puisque la liste définit les seules valeurs valides). Pour moi, ils sont très pratiques dans la conception du commutateur .

67. Un Enum peut-il implémenter des interfaces (utiliser le mot-clé Implements) ?

Oui. Après tout, les énumérations devraient représenter plus que de simples ensembles passifs (tels que les rôles sur un campus scolaire). En Java, ils peuvent représenter des objets plus complexes, vous devrez donc peut-être leur ajouter des fonctionnalités supplémentaires. Cela vous permet également de tirer parti du polymorphisme en remplaçant la valeur enum aux endroits où le type d'interface implémenté est nécessaire.

68. Enum peut-il étendre une classe (utiliser le mot-clé extends) ?

Non, ce n’est pas possible, car une énumération est une sous-classe de la classe Enum<T> par défaut , où T est le type enum. Ce n'est rien de plus qu'une classe de base commune pour tous les types d'énumérations du langage Java. La conversion d'une énumération en classe est effectuée par le compilateur Java au moment de la compilation. L'extension n'est pas explicitement indiquée dans le code, mais elle est toujours implicite.

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

Cette question est un peu déroutante et je ne suis pas sûr de bien la comprendre. J'ai deux interprétations : 1. Pouvez-vous avoir une énumération sans aucune valeur ? Oui, bien sûr, mais ce serait comme une classe vide — inutile, par exemple
public enum Role {
}
Et si on appelle :
var s = Role.values();
System.out.println(s);
Nous obtenons ce qui suit dans la console :
[Lflyweight.Rôle;@9f70c54
(un 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'utilisez pas l' opérateur new pour les valeurs enum, car ce sont des valeurs statiques.

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

Oui, bien sûr, vous pouvez surcharger la méthode toString() afin de définir comment afficher votre énumération lorsque la méthode toString est appelée (lors de la conversion d'une énumération en une chaîne ordinaire, par exemple, pour l'afficher dans la console ou dans les journaux).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Selected role - " + super.toString();
   }
}
C'est tout pour moi aujourd'hui. Jusqu'à la prochaine partie !
Commentaires
  • Populaires
  • Nouveau
  • Anciennes
Tu dois être connecté(e) pour laisser un commentaire
Cette page ne comporte pas encore de commentaires