Bonjour à tous, mesdames et messieurs, ingénieurs logiciels ! Parlons des questions d'entrevue. À propos de ce à quoi vous devez vous préparer et de ce que vous devez savoir. C'est le moment idéal pour revoir ou étudier ces points pour la première fois. Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 1 Je me suis retrouvé avec une collection assez complète de questions fréquemment posées sur la POO, la syntaxe Java, les exceptions Java, les collections et le multithreading, que je diviserai en plusieurs parties pour plus de commodité. Il est difficile de tout couvrir en même temps, mais j'espère que ce matériel fournira une bonne base à ceux qui se préparent à trouver leur premier emploi en tant que programmeur. Pour une meilleure compréhension et rétention, je conseille également de passer au peigne fin d'autres sources. Vous pouvez mieux comprendre un concept en l'abordant sous plusieurs angles différents. Important:Nous ne parlerons que de Java avant la version 8. Toutes les innovations qui sont venues dans les versions 9, 10, 11, 12 et 13 ne seront pas considérées ici. Toutes les idées/commentaires sur la façon d'améliorer les réponses sont les bienvenus . Bonne lecture. Allons-y!

Entretien Java : questions sur la POO

1. Quelles sont les caractéristiques de Java ?

Répondre:
  1. Notions de POO :

    1. orientation objet
    2. héritage
    3. encapsulation
    4. polymorphisme
    5. abstraction
  2. Multiplateforme : un programme Java peut être exécuté sur n'importe quelle plate-forme sans aucune modification. Bien sûr, cela nécessite une JVM (machine virtuelle Java) installée.

  3. Hautes performances : Le compilateur Just-In-Time (JIT) permet des performances élevées. Le compilateur JIT convertit le bytecode en code machine, puis la JVM démarre l'exécution.

  4. Multithreading : la JVM crée un thread d'exécution appelé le main thread. Un programmeur peut créer plusieurs threads en dérivant de la classe Thread ou en implémentant l' Runnableinterface.

2. Qu'est-ce que l'héritage ?

L'héritage signifie qu'une classe peut hériter d'une autre classe (en utilisant le mot clé extend ). Cela signifie que vous pouvez réutiliser le code de la classe dont vous héritez. La classe existante est connue sous le nom de superclasset la classe nouvellement créée est le subclass. Les gens disent aussi utiliser les termes parent et child.

public class Animal {
   private int age;
}

public class Dog extends Animal {

}
Animalest le parentet Dogest le child.

3. Qu'est-ce que l'encapsulation ?

Cette question est souvent posée dans les entretiens pour les postes de développeur Java. L'encapsulation masque l'implémentation en utilisant des modificateurs d'accès, des getters et des setters. Ceci est fait afin d'empêcher l'accès externe partout où les développeurs pensent que c'est nécessaire. Un exemple simple de la vie réelle est la voiture. Nous n'avons pas d'accès direct au fonctionnement du moteur. Tout ce que nous avons à faire est de mettre la clé dans le contact et d'allumer le moteur. Les processus qui se déroulent sous le capot ne nous concernent pas. De plus, si nous devions interférer dans l'activité du moteur, cela pourrait conduire à une situation imprévisible, pouvant endommager la voiture et entraîner des lésions corporelles. Il se passe exactement la même chose en programmation. C'est bien décrit sur Wikipédia. Il y a aussi un article sur l'encapsulation sur CodeGym .

4. Qu'est-ce que le polymorphisme ?

Le polymorphisme est la capacité d'un programme à traiter des objets avec la même interface de la même manière, sans information sur le type spécifique de l'objet. Comme le dit le dicton, "une interface - plusieurs implémentations". Avec le polymorphisme, vous pouvez combiner et utiliser différents types d'objets en fonction de comportements partagés. Par exemple, nous avons une classe Animal qui a deux descendants : Dog et Cat. La classe générique Animal a un comportement partagé par tous, la capacité de faire un son. Nous utilisons des capacités polymorphes lorsque nous devons rassembler tout ce qui hérite de la classe Animal et exécuter la méthode "make sound". Voici à quoi ça ressemble :

List<Animal> animals = Arrays.asList(new Cat(), new Dog(), new Cat());
animals.forEach(animal -> animal.makeSound());
En d'autres termes, le polymorphisme est utile. Et cela s'applique également aux méthodes polymorphes (surchargées). Comment utiliser le polymorphisme

Questions d'entretien sur la syntaxe Java

5. Qu'est-ce qu'un constructeur en Java ?

Les constructeurs ont les caractéristiques suivantes :
  1. Lorsqu'un nouvel objet est créé, le programme utilise le constructeur approprié pour le créer.
  2. Un constructeur est comme une méthode. Ses particularités résident dans le fait qu'il n'y a pas de valeur de retour (y compris void) et que son nom est le même que le nom de la classe.
  3. Si aucun constructeur n'est créé explicitement, un constructeur vide est créé automatiquement.
  4. Un constructeur peut être remplacé.
  5. Si vous déclarez un constructeur avec des paramètres mais que vous en avez également besoin d'un sans paramètres, vous devez le créer séparément, car il ne sera pas créé automatiquement.

6. Quelles sont les deux classes qui n'héritent pas d'Object ?

Ne vous laissez pas berner par des questions pièges - il n'y a pas de telles classes. Toutes les classes héritent de la classe Object soit directement, soit par l'intermédiaire d'ancêtres !

7. Qu'est-ce qu'une variable locale ?

C'est une autre question d'entretien populaire pour les développeurs Java. Une variable locale est une variable qui est définie à l'intérieur d'une méthode et qui existe tant que la méthode est en cours d'exécution. Dès que l'exécution se termine, la variable locale cesse d'exister. Voici un programme qui utilise une variable locale nommée helloMessage dans la méthode main() :

public static void main(String[] args) {
   String helloMessage;
   helloMessage = "Hello, World!";
   System.out.println(helloMessage);
}

8. Qu'est-ce qu'une variable d'instance ?

Une variable d'instance est une variable déclarée dans une classe. Il existe tant qu'un objet existe. Par exemple, nous avons une classe Bee, qui a deux variables d'instance — nectarLoad et maxNectarLoad :

public class Bee {

   /**
    * Current nectar load
    */
   private double nectarLoad;

   /**
    * Maximum nectar that can the bee can collect.
    */
   private double maxNectarLoad = 20.0;
 
  ...
}

9. Que sont les modificateurs d'accès ?

Les modificateurs d'accès sont un mécanisme permettant de personnaliser l'accès aux classes, aux méthodes et aux variables. Les modificateurs suivants existent, répertoriés par ordre croissant d'accès :
  1. private— Ce modificateur d'accès est utilisé sur les méthodes, les champs et les constructeurs. L'accès est limité à la classe dans laquelle ils sont déclarés.
  2. package-private (default)— Il s'agit du niveau d'accès par défaut pour les classes. L'accès est limité au package spécifique dans lequel une classe, une méthode, une variable ou un constructeur est déclaré.
  3. protected— Ce modificateur d'accès offre le même niveau d'accès qu'avec package-privatel'ajout d'un accès pour les classes qui héritent d'une classe avec le protectedmodificateur.
  4. public— Ce niveau d'accès est également utilisé pour les cours. Ce niveau d'accès signifie qu'il y a un accès complet à travers l'application.
Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 2

10. Qu'est-ce que le remplacement de méthode ?

Nous redéfinissons les méthodes lorsqu'une classe enfant souhaite modifier le comportement de sa classe parent. Si nous devons également faire ce qui se trouve dans la méthode parent, nous pouvons utiliser super.methodName() dans l'enfant, qui exécutera la méthode parent. Nous pouvons ajouter notre logique supplémentaire après cela. Exigences à respecter :
  • la signature de la méthode doit être la même
  • la valeur de retour doit être la même

11. Que sont les signatures de méthode ?

Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 3Une signature de méthode est la combinaison du nom de la méthode et des arguments que la méthode prend. La signature de méthode est l'identifiant unique d'une méthode lors de la surcharge de méthodes.

12. Qu'est-ce que la surcharge de méthode ?

La surcharge de méthode est une caractéristique du polymorphisme dans laquelle nous modifions la signature de la méthode pour créer plusieurs méthodes qui effectuent la même action :
  • Le même nom
  • arguments différents
  • il peut y avoir différents types de retour
Par exemple, la méthode ArrayListde la classe add()peut être surchargée, ce qui nous permet d'ajouter de différentes manières en fonction des arguments d'entrée :
  • add(Object o)— Cette méthode ajoute simplement un objet
  • add(int index, Object o)— Cette méthode ajoute un objet à un index spécifique
  • add(Collection<Object> c)— Cette méthode ajoute une liste d'objets
  • add(int index, Collection<Object> c)— Cette méthode ajoute une liste d'objets à partir d'un index spécifique.

13. Qu'est-ce qu'une interface ?

Java ne prend pas en charge l'héritage multiple. Pour surmonter cette limitation, des interfaces ont été ajoutées sous la forme que nous connaissons et aimons ;) Pendant longtemps, les interfaces n'avaient que des méthodes sans aucune implémentation. Dans le cadre de cette réponse, parlons-en. Par exemple:


public interface Animal {
   void makeSound();
   void eat();
   void sleep();
}
Quelques détails en découlent :
  • Toutes les méthodes d'une interface sont publiques et abstraites
  • Toutes les variables sont publiques static final
  • Les classes n'héritent pas des interfaces (c'est-à-dire que nous n'utilisons pas le mot clé extend). Au lieu de cela, les classes les implémentent (c'est-à-dire que nous utilisons le mot clé implements). De plus, vous pouvez implémenter autant d'interfaces que vous le souhaitez.
  • Les classes qui implémentent une interface doivent fournir une implémentation de toutes les méthodes qui se trouvent dans l'interface.
Comme ça:

public class Cat implements Animal {
   public void makeSound() {
       // Method implementation
   }

   public void eat() {
       // Implementation
   }

   public void sleep() {
       // Implementation
   }
}

14. Qu'est-ce qu'une méthode par défaut dans une interface ?

Parlons maintenant des méthodes par défaut. À quoi servent-ils? Qui sont-ils pour? Ces méthodes ont été ajoutées pour servir "les deux mains". De quoi je parle ? Eh bien, d'une part, il était nécessaire d'ajouter de nouvelles fonctionnalités : les lambdas et l'API Stream. D'un autre côté, il était nécessaire de conserver ce pour quoi Java est célèbre : la rétrocompatibilité. Pour ce faire, les interfaces avaient besoin de nouvelles solutions toutes faites. C'est ainsi que nous sont venues les méthodes par défaut. Une méthode par défaut est une méthode implémentée dans une interface, marquée par le defaultmot clé. Par exemple, la méthode bien connue stream()dans l' Collectioninterface. Croyez-moi, cette interface n'est pas aussi simple qu'il y paraît. Ou encore la forEach()méthode non moins célèbre duIterableinterface. Il n'existait pas non plus jusqu'à ce que les méthodes par défaut soient ajoutées. Au fait, vous pouvez également lire à ce sujet sur CodeGym ici .

15. Comment hérite-t-on alors de deux méthodes par défaut identiques ?

La réponse précédente sur ce qu'est une méthode par défaut soulève une autre question. Si vous pouvez implémenter des méthodes dans des interfaces, vous pouvez théoriquement implémenter deux interfaces avec la même méthode. Comment fait-on cela? Voici deux interfaces différentes avec la même méthode :

interface A {
   default void foo() {
       System.out.println("Foo A");
   }
}

interface B {
   default void foo() {
       System.out.println("Foo B");
   }
}
Et nous avons une classe qui implémente ces deux interfaces. Mais comment choisir une méthode spécifique dans l'interface A ou B ? La construction spéciale suivante le permetA.super.foo() :

public class C implements A, B {
   public void fooA() {
       A.super.foo();
   }

   public void fooB() {
       B.super.foo();
   }
}
Ainsi, la fooA()méthode utilisera la foo()méthode par défaut de l' Ainterface, tandis que la fooB()méthode utilisera la foo()méthode de l' Binterface.

16. Que sont les méthodes abstraites et les classes ?

En Java, abstractest un mot réservé. Il est utilisé pour désigner des classes et des méthodes abstraites. Premièrement, nous avons besoin de définitions. Une méthode abstraite est une méthode déclarée à l'aide du abstractmot-clé sans implémentation dans une classe abstraite. C'est-à-dire qu'il s'agit d'une méthode comme dans une interface, mais avec l'ajout d'un mot-clé, par exemple :

public abstract void foo();
Une classe abstraite est une classe également marquée du abstractmot-clé :

public abstract class A {

}
Une classe abstraite a plusieurs fonctionnalités :
  • vous ne pouvez pas créer un objet d'une classe abstraite
  • il peut avoir des méthodes abstraites
  • il peut aussi ne pas avoir de méthodes abstraites
Les classes abstraites sont nécessaires pour l'abstraction (désolé pour la tautologie) qui a un ensemble de comportements et d'états communs (c'est-à-dire des méthodes et des variables). La vraie vie regorge d'exemples. Tout autour de nous. "Animal", "Voiture", "Figure géométrique", etc.

17. Quelle est la différence entre String, StringBuilder et StringBuffer ?

Stringles valeurs sont stockées dans un pool de chaînes constantes. Dès qu'une chaîne est créée, elle apparaît dans ce pool. Et vous ne pouvez pas le supprimer. Par exemple:

String name = "book";
La variable pointera vers le pool de chaînes constantes Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 4En définissant la variable name sur une valeur différente, nous avons :

name = "pen";
Le pool de chaînes constantes ressemble à ceci : Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 5En d'autres termes, les deux valeurs y restent. Tampon de chaîne :
  • Stringles valeurs sont stockées dans une pile. Si une valeur est modifiée, la nouvelle valeur remplacera l'ancienne.
  • String Bufferest synchronisé et est donc thread-safe.
  • En raison de la sécurité des threads, ses performances sont médiocres.
Exemple:

StringBuffer name = “book”;
Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 6Dès que la valeur de la variable name change, la valeur dans la pile change : Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 7StringBuilder est exactement le même que StringBuffer, sauf qu'il n'est pas thread-safe. En conséquence, il est nettement plus rapide que StringBuffer.

18. Quelle est la différence entre une classe abstraite et une interface ?

Classe abstraite :
  • Les classes abstraites ont un constructeur par défaut. Elle est appelée chaque fois qu'un descendant de la classe abstraite est créé.
  • Ils peuvent inclure à la fois des méthodes abstraites et des méthodes non abstraites. En général, une classe abstraite n'a pas besoin d'avoir des méthodes abstraites.
  • Une classe qui hérite d'une classe abstraite ne doit implémenter que des méthodes abstraites.
  • Une classe abstraite peut avoir des variables d'instance (voir Question #5).
Interface:
  • Une interface n'a pas de constructeur et ne peut pas être initialisée.
  • Seules les méthodes abstraites peuvent être ajoutées (à l'exception des méthodes par défaut).
  • Les classes qui implémentent l'interface doivent implémenter toutes les méthodes (à l'exception des méthodes par défaut).
  • Les interfaces ne peuvent avoir que des constantes.

19. Pourquoi l'accès à un élément d'un tableau est-il O(1) ?

Cette question a été littéralement posée lors de ma dernière interview. Comme je l'ai appris plus tard, le but de cette question est de voir comment une personne pense. De toute évidence, ces connaissances ont peu de valeur pratique. Le simple fait de le savoir suffit. Tout d'abord, nous devons préciser que O(1) est la notation de la complexité temporelle d'un algorithme "à temps constant". En d'autres termes, cette désignation indique le temps d'exécution le plus rapide. Pour répondre à cette question, nous devons considérer ce que nous savons sur les tableaux. Pour créer un inttableau, nous devons écrire ce qui suit :

int[] intArray = new int[100];
Plusieurs conclusions peuvent être tirées de cette syntaxe :
  1. Lorsqu'un tableau est déclaré, son type est connu. Si le type est connu, la taille de chaque cellule du tableau est connue.
  2. La taille de l'ensemble du tableau est connue.
Il s'ensuit donc que pour comprendre dans quelle cellule écrire, il suffit de calculer dans quelle zone de mémoire écrire. Pour un ordinateur, c'est facile. L'ordinateur sait où commence la mémoire allouée, le nombre d'éléments et la taille de chaque cellule. Tout cela signifie que l'endroit à écrire sera égal à l'endroit de départ du tableau + la taille de chaque cellule multipliée par l'indice.

Alors, comment arrivons-nous à O(1) lors de l'accès aux objets d'une ArrayList ?

Cette question suit immédiatement la précédente. La vérité est que lorsque vous travaillez avec un tableau contenant des primitives, nous connaissons à l'avance (au moment de la création) la taille du type d'élément. Mais que faire si nous avons ce type de hiérarchie d'héritage et Top 50 des questions et réponses d'entretien d'embauche pour Java Core.  Partie 1 - 8que nous voulons créer une collection pour les éléments de type A et ajouter différentes implémentations (B, C et D) :

List<A> list = new ArrayList();
list.add(new B());
list.add(new C());
list.add(new D());
list.add(new B());
Dans cette situation, comment calcule-t-on la taille de chaque cellule ? Après tout, chaque objet sera différent, éventuellement avec des champs supplémentaires différents. Ce qu'il faut faire? Ici, la question est posée d'une manière qui est destinée à vous confondre. Nous savons que la collection ne stocke pas directement les objets. Il ne stocke que les références aux objets. Et toutes les références ont la même taille, et c'est connu. Par conséquent, nous calculons ici les adresses de la même manière que dans la question précédente.

21. Boîte automatique et déballage

Contexte historique : l'autoboxing et l'unboxing sont quelques-unes des principales innovations du JDK 5. L'autoboxing est le processus de conversion automatique d'un type primitif en une classe wrapper correspondante. Le déballage est l'exact opposé de l'autoboxing. C'est le processus de conversion d'une classe wrapper en une primitive. Mais si la valeur d'un wrapper est null, alors un NullPointerExceptionsera lancé lors du déballage.

Primitives et leurs enveloppes correspondantes

Primitif Classe wrapper
booléen booléen
entier Entier
octet Octet
carboniser Personnage
flotter Flotter
long Long
court Court
double Double

// L'autoboxing se produit :

  • lors de l'affectation d'une primitive à une référence à une classe wrapper :

    AVANT Java 5 :

    
    // Manual boxing (the way it was BEFORE Java 5).
    public void boxingBeforeJava5() {
       Boolean booleanBox = new Boolean(true);
       Integer intBox = new Integer(3);
       // And so on for other types
    }
    
    After Java 5:
    // Automatic boxing (the way it became in Java 5).
    public void boxingJava5() {
       Boolean booleanBox = true;
       Integer intBox = 3;
       // And so on for other types
    }
    
  • lorsqu'une primitive est passée en argument à une méthode qui attend un wrapper :

    
    public void exampleOfAutoboxing() {
       long age = 3;
       setAge(age);
    }
    
    public void setAge(Long age) {
       this.age = age;
    }
    

// Le déballage a lieu :

  • lorsque nous affectons une instance d'une classe wrapper à une variable primitive :

    
    // BEFORE Java 5:
    int intValue = new Integer(4).intValue();
    double doubleValue = new Double(2.3).doubleValue();
    char c = new Character((char) 3).charValue();
    boolean b = Boolean.TRUE.booleanValue();
    
    // And after JDK 5:
    int intValue = new Integer(4);
    double doubleValue = new Double(2.3);
    char c = new Character((char) 3);
    boolean b = Boolean.TRUE;
    
  • Lors d'opérations arithmétiques. Les opérations s'appliquent uniquement aux types primitifs, il est donc nécessaire de déballer les primitives.

    
    // BEFORE Java 5:
    Integer integerBox1 = new Integer(1);
    Integer integerBox2 = new Integer(2);
    
    // A comparison used to require this:
    integerBox1.intValue() > integerBox2.intValue()
          
    // In Java 5
    integerBox1 > integerBox2
    
  • lors du passage d'une instance d'une classe wrapper à une méthode qui prend la primitive correspondante :

    
    public void exampleOfAutoboxing() {
       Long age = new Long(3);
       setAge(age);
    }
    
    public void setAge(long age) {
       this.age = age;
    }
    

22. Quel est le mot-clé final et où est-il utilisé ?

Le finalmot-clé peut être utilisé sur des variables, des méthodes et des classes.
  1. La valeur d'une variable finale ne peut pas être modifiée après son initialisation.
  2. Une classe terminale est stérile :) Elle ne peut pas avoir d'enfants.
  3. Une méthode finale ne peut pas être remplacée par un descendant.
Nous avons couvert les trucs de haut niveau. Plongeons maintenant plus profondément.

Variables finales

Java nous donne deux manières de déclarer une variable et de lui affecter une valeur :
  1. Vous pouvez déclarer une variable et l'initialiser plus tard.
  2. Vous pouvez déclarer une variable et lui attribuer une valeur immédiatement.
Voici un exemple qui illustre ces utilisations des variables finales :

public class FinalExample {

   // A static final variable that is immediately initialized:
   final static String FINAL_EXAMPLE_NAME = "I'm likely the final one";

   // A final variable that is not initialized, but will only work if you
   // initialize it in the constructor:
   final long creationTime;

   public FinalExample() {
       this.creationTime = System.currentTimeMillis();
   }

   public static void main(String[] args) {
       FinalExample finalExample = new FinalExample();
       System.out.println(finalExample.creationTime);

       // The final FinalExample.FINAL_EXAMPLE_NAME field cannot be accessed
//    FinalExample.FINAL_EXAMPLE_NAME = "Not you're not!";

       // The final Config.creationTime field cannot be accessed
//    finalExample.creationTime = 1L;
   }
}

Une variable finale peut-elle être considérée comme une constante ?

Comme nous ne pouvons pas attribuer de nouvelles valeurs aux variables finales, il semble qu'il s'agisse de variables constantes. Mais seulement à première vue : si le type de données de la variable est immutable, alors, oui, c'est une constante. Mais si le type de données est mutable, c'est-à-dire modifiable, il sera alors possible d'utiliser des méthodes et des variables pour modifier la valeur de l'objet référencé par une finalvariable. Pour cette raison, il ne peut pas être appelé une constante. L'exemple suivant montre que certaines variables finales sont de véritables constantes, tandis que d'autres ne le sont pas, puisqu'elles peuvent être modifiées.

public class FinalExample {

   // Immutable final variables
   final static String FINAL_EXAMPLE_NAME = "I'm likely the final one";
   final static Integer FINAL_EXAMPLE_COUNT  = 10;

   // Mutable final variables
   final List<String> addresses = new ArrayList();
   final StringBuilder finalStringBuilder = new StringBuilder("Constant?");
}

Variables finales locales

Lorsqu'une finalvariable est créée dans une méthode, on l'appelle une local finalvariable :

public class FinalExample {

   public static void main(String[] args) {
       // You can do this
       final int minAgeForDriveCar = 18;

       // Or you can do this, in a for-each loop:
       for (final String arg : args) {
           System.out.println(arg);
       }
   }

}
Nous pouvons utiliser le mot clé final dans une boucle for améliorée, car une nouvelle variable est créée après chaque itération de la boucle. Gardez à l'esprit que cela ne s'applique pas à une boucle for normale, nous aurons donc une erreur de compilation.

// The final local j variable cannot be assigned
for (final int i = 0; i < args.length; i ++) {
   System.out.println(args[i]);
}

Classe finale

Une classe déclarée comme finalne peut pas être étendue. Pour le dire plus simplement, aucune autre classe ne peut en hériter. Un excellent exemple de finalclasse dans le JDK est String. La première étape pour créer une classe immuable est de la marquer comme final, l'empêchant ainsi d'être étendue :

public final class FinalExample {
}

// Compilation error!
class WantsToInheritFinalClass extends FinalExample {
}

Méthodes finales

Lorsqu'une méthode est marquée final, elle est appelée méthode finale (c'est logique, n'est-ce pas ?). Une méthode finale ne peut pas être remplacée dans une classe enfant. Incidemment, les méthodes wait() et notify() de la classe Object sont finales, nous n'avons donc pas la possibilité de les remplacer.

public class FinalExample {
   public final String generateAddress() {
       return "Some address";
   }
}

class ChildOfFinalExample extends FinalExample {

   // Compilation error!
   @Override
   public String generateAddress() {
       return "My OWN Address";
   }
}

Comment et où utiliser final en Java

  • Utilisez le mot-clé final pour définir certaines constantes au niveau de la classe ;
  • Créez des variables finales pour les objets que vous ne voulez pas modifier. Par exemple, des propriétés spécifiques à un objet que nous pouvons utiliser à des fins de journalisation.
  • Si vous ne voulez pas qu'une classe soit prolongée, marquez-la comme finale.
  • Si vous devez créer une classe immuable, vous devez la rendre finale.
  • Si vous souhaitez que l'implémentation d'une méthode ne change pas dans ses descendants, marquez la méthode comme final. Ceci est très important pour être sûr que la mise en œuvre ne change pas.

23. Que sont les types mutables et immuables ?

Mutable

Les objets mutables sont des objets dont l'état et les variables peuvent être modifiés après la création. Des exemples de classes mutables incluent StringBuilder et StringBuffer. Exemple:

public class MutableExample {

   private String address;

   public MutableExample(String address) {
       this.address = address;
   }

   public String getAddress() {
       return address;
   }

   // This setter can change the name field
   public void setAddress(String address) {
       this.address = address;
   }

   public static void main(String[] args) {

       MutableExample obj = new MutableExample("First address");
       System.out.println(obj.getAddress());

       // We are updating the name field, so this is a mutable object
       obj.setAddress("Updated address");
       System.out.println(obj.getAddress());
   }
}

Immuable

Les objets immuables sont des objets dont l'état et les variables ne peuvent pas être modifiés après la création de l'objet. Une excellente clé pour un HashMap, vous ne pensez pas ? :) Par exemple, String, Integer, Double, etc. Exemple:

// We'll make this class final so no one can change it
public final class ImmutableExample {

   private String address;

   ImmutableExample(String address) {
       this.address = address;
   }

   public String getAddress() {
       return address;
   }

   // We remove the setter

   public static void main(String[] args) {

       ImmutableExample obj = new ImmutableExample("Old address");
       System.out.println(obj.getAddress());

       // There is no way to change this field, so it is an immutable object
       // obj.setName("new address");
       // System.out.println(obj.getName());

   }
}
Dans la partie suivante, nous examinons les questions et réponses sur les collections. Mon profil sur GitHub Top 50 des questions et réponses d'entretien d'embauche pour Java Core. Partie 2