1. Initialisation des variables
Comme vous le savez déjà, vous pouvez déclarer plusieurs variables dans votre classe, et non seulement les déclarer, mais aussi les initialiser immédiatement avec leurs valeurs initiales.
Et ces mêmes variables peuvent également être initialisées dans un constructeur. Cela signifie qu'en théorie, ces variables pourraient être évaluées deux fois. Exemple
Code | Note |
---|---|
|
La age variable reçoit une valeur initiale La valeur initiale est écrasée La variable age stocke sa valeur initiale. |
|
Ceci est autorisé : le premier constructeur sera appelé |
|
Ceci est autorisé : le deuxième constructeur sera appelé |
C'est ce qui se passe quand Cat cat = new Cat("Whiskers", 2);
est exécuté :
- Un
Cat
objet est créé - Toutes les variables d'instance sont initialisées avec leurs valeurs initiales
- Le constructeur est appelé et son code est exécuté.
En d'autres termes, les variables reçoivent d'abord leurs valeurs initiales, puis le code du constructeur est exécuté.
2. Ordre d'initialisation des variables dans une classe
Les variables ne sont pas simplement initialisées avant l'exécution du constructeur — elles sont initialisées dans un ordre bien défini : l'ordre dans lequel elles sont déclarées dans la classe.
Regardons un code intéressant :
Code | Note |
---|---|
|
Ce code ne compilera pas, car au moment où la a
variable est créée, il n'y a pas encore de variables b
et . c
Mais vous pouvez écrire votre code comme suit — ce code se compilera et fonctionnera parfaitement.
Code | Note |
---|---|
|
0 0+2 0+2+3 |
Mais n'oubliez pas que votre code doit être transparent pour les autres développeurs. Il est préférable de ne pas utiliser de telles techniques, car cela nuit à la lisibilité du code.
Ici, nous devons nous rappeler qu'avant d'attribuer une valeur aux variables, elles ont une valeur par défaut . Pour le int
type, c'est zéro.
Lorsque la JVM initialise la a
variable, elle assignera simplement la valeur par défaut pour le type int : 0.
Lorsqu'elle atteint b
, la variable a sera déjà connue et aura une valeur, donc la JVM lui attribuera la valeur 2.
Et lorsqu'elle atteint la c
variable, les variables a
et b
seront déjà initialisées, donc la JVM calculera facilement la valeur initiale pour c
: 0+2+3.
Si vous créez une variable à l'intérieur d'une méthode, vous ne pouvez pas l'utiliser à moins que vous ne lui ayez préalablement attribué une valeur. Mais ce n'est pas vrai pour les variables d'une classe ! Si une valeur initiale n'est pas affectée à une variable d'une classe, alors une valeur par défaut lui est affectée.
3. Constantes
Pendant que nous analysons comment les objets sont créés, il est intéressant de toucher à l'initialisation des constantes, c'est-à-dire des variables avec le final
modificateur.
Si une variable a le final
modificateur, alors une valeur initiale doit lui être assignée. Vous le savez déjà, et il n'y a rien d'étonnant à cela.
Mais ce que vous ne savez pas, c'est que vous n'êtes pas obligé d'assigner la valeur initiale tout de suite si vous l'assignez dans le constructeur. Cela fonctionnera très bien pour une variable finale. La seule exigence est que si vous avez plusieurs constructeurs, une valeur finale doit être affectée à une variable finale dans chaque constructeur.
Exemple:
public class Cat
{
public final int maxAge = 25;
public final int maxWeight;
public Cat (int weight)
{
this.maxWeight = weight; // Assign an initial value to the constant
}
}
4. Code dans un constructeur
Et quelques notes plus importantes sur les constructeurs. Plus tard, au fur et à mesure que vous continuerez à apprendre Java, vous rencontrerez des choses comme l'héritage, la sérialisation, les exceptions, etc. Ils influencent tous le travail des constructeurs à des degrés divers. Cela n'a aucun sens d'approfondir ces sujets maintenant, mais nous sommes obligés de les aborder au moins.
Par exemple, voici une remarque importante sur les constructeurs. En théorie, vous pouvez écrire du code de n'importe quelle complexité dans un constructeur. Mais ne fais pas ça. Exemple:
|
Ouvrir un flux de lecture de fichier Lire le fichier dans un tableau d'octets Enregistrer le tableau d'octets sous forme de chaîne Afficher le contenu du fichier à l'écran |
Dans le constructeur de la classe FilePrinter, nous avons immédiatement ouvert un flux d'octets sur un fichier et lu son contenu. Ce comportement est complexe et peut entraîner des erreurs.
Et s'il n'y avait pas un tel fichier? Et s'il y avait des problèmes avec la lecture du fichier ? Et si c'était trop gros ?
La logique complexe implique une forte probabilité d'erreurs et cela signifie que le code doit gérer correctement les exceptions.
Exemple 1 — Sérialisation
Dans un programme Java standard, il existe de nombreuses situations où vous n'êtes pas celui qui crée les objets de votre classe. Par exemple, supposons que vous décidiez d'envoyer un objet sur le réseau : dans ce cas, la machine Java elle-même convertira votre objet en un ensemble d'octets, l'enverra et recréera l'objet à partir de l'ensemble d'octets.
Mais supposons que votre fichier n'existe pas sur l'autre ordinateur. Il y aura une erreur dans le constructeur et personne ne la gérera. Et cela est tout à fait capable de provoquer l'arrêt du programme.
Exemple 2 — Initialisation des champs d'une classe
Si votre constructeur de classe peut lancer des exceptions vérifiées, c'est-à-dire qu'il est marqué avec le mot-clé throws, vous devez intercepter les exceptions indiquées dans la méthode qui crée votre objet.
Mais que se passe-t-il s'il n'y a pas une telle méthode? Exemple:
Code | Note |
---|---|
|
Ce code ne compilera pas. |
Le FilePrinter
constructeur de classe peut lancer une exception vérifiée , ce qui signifie que vous ne pouvez pas créer un FilePrinter
objet sans l'envelopper dans un bloc try-catch. Et un bloc try-catch ne peut être écrit que dans une méthode
5. Constructeur de classe de base
Dans les leçons précédentes, nous avons un peu parlé de l'héritage. Malheureusement, notre discussion complète sur l'héritage et la POO est réservée au niveau dédié à la POO, et l'héritage des constructeurs est déjà pertinent pour nous.
Si votre classe hérite d'une autre classe, un objet de la classe parent sera intégré dans un objet de votre classe. De plus, la classe parent a ses propres variables et ses propres constructeurs.
Cela signifie qu'il est très important pour vous de connaître et de comprendre comment les variables sont initialisées et les constructeurs sont appelés lorsque votre classe a une classe parente et que vous héritez de ses variables et méthodes.
Des classes
Comment connaître l'ordre dans lequel les variables sont initialisées et les constructeurs appelés ? Commençons par écrire le code pour deux classes. L'un héritera de l'autre :
Code | Note |
---|---|
|
La ChildClass classe hérite de la ParentClass classe. |
Nous devons déterminer l'ordre dans lequel les variables sont initialisées et les constructeurs sont appelés. La journalisation nous aidera à le faire.
Enregistrement
La journalisation est le processus d'enregistrement des actions effectuées par un programme pendant son exécution, en les écrivant sur la console ou dans un fichier.
Il est assez simple de déterminer que le constructeur a été appelé : dans le corps du constructeur, écrivez un message à la console. Mais comment savoir si une variable a été initialisée ?
En fait, ce n'est pas non plus très difficile : écrivez une méthode spéciale qui renverra la valeur utilisée pour initialiser la variable et enregistrera l'initialisation. Voici à quoi pourrait ressembler le code :
Code final
|
Créer un ChildClass objet Cette méthode écrit le texte transmis à la console et le renvoie également. Déclarez la ParentClass classe Display text et initialisez également les variables avec. Écrivez un message indiquant que le constructeur a été appelé. Ignorez la valeur de retour. Déclarez la ChildClass classe Display text et initialisez également les variables avec. Écrivez un message indiquant que le constructeur a été appelé. Ignorez la valeur de retour. |
Si vous exécutez ce code, le texte s'affichera à l'écran comme suit :
Sortie console de la méthodeMain.print() |
---|
|
Ainsi, vous pouvez toujours vous assurer personnellement que les variables d'une classe sont initialisées avant l'appel du constructeur. Une classe de base est entièrement initialisée avant l'initialisation de la classe héritée.
GO TO FULL VERSION