Lors de la déclaration des propriétés, des méthodes et des classes en Java, le mot-clé final peut être utilisé pour le modifier. La variable finale est une constante et ne peut être attribuée qu'une seule fois; La méthode finale ne peut pas être réécrite par une sous-classe; La classe finale ne peut pas être héritée.
1. Membres finaux
La déclaration d'un champ final aide l'optimiseur à prendre de meilleures décisions d'optimisation, car si le compilateur sait que la valeur du champ ne changera pas, elle peut mettre en toute sécurité la valeur dans le registre. Le champ final fournit également un niveau de sécurité supplémentaire en faisant en sorte que le compilateur force le champ à être en lecture seule.
1.1 sur l'affectation des membres finaux
1) En Java, les variables ordinaires peuvent être initialisées par défaut. Mais les variables de type final doivent être explicitement initialisées.
2) Les membres finaux ne peuvent et ne peuvent être initialisés qu'une seule fois.
3) Le membre final doit être initialisé à la déclaration (attribuant une valeur directement à la variable finale lorsqu'il est défini) ou dans le constructeur, et ne peut pas être initialisé ailleurs.
Exemple 1 bat.java
classe publique Bat {Double Pi final = 3,14; // Attribuez final int i lorsqu'il est défini; // Parce qu'il doit être initialisé dans le constructeur, la liste finale <ATM> ne peut pas être attribuée ici; // Parce qu'il doit être initialisé dans le constructeur, BAT () ne peut pas être attribué ici {i = 100; list = new LinkedList <at> (); } Bat (int ii, list <at> l) {i = ii; list = l; } public static void main (String [] args) {bat b = new bat (); B.List.add (new BAT ()); // bi = 25; // b.list = new ArrayList <At> (); System.out.println ("i =" + bi + "Type de liste:" + b.list.getClass ()); b = new Bat (23, new ArrayList <at> ()); B.List.add (new BAT ()); System.out.println ("i =" + bi + "Type de liste:" + b.list.getClass ()); }}
résultat:
I = 100 Type de liste: classe java.util.linkedlisti = 23 Type de liste: classe java.util.arraylist
Il y a deux lignes d'instructions dans la méthode principale qui sont commentées. Si vous supprimez le commentaire, le programme ne pourra pas compiler. Cela signifie que, que ce soit la valeur de I ou le type de liste, une fois initialisé, il ne peut pas être modifié. Cependant, B peut spécifier la valeur de I ou le type de liste par réinitialisation.
1.2 Initialisation non valide du champ de référence final
Il est un peu gênant d'utiliser correctement le champ final, en particulier pour les références d'objets dont les constructeurs peuvent lancer des exceptions. Étant donné que le champ final ne doit être initialisé qu'une seule fois dans chaque constructeur, si le constructeur référencé par l'objet final peut lancer une exception, le compilateur peut signaler une erreur disant que le champ n'avait pas été initialisé. Le compilateur est généralement suffisamment intelligent pour constater que l'initialisation dans chaque branche de deux branches de code mutex (par exemple, si ... les blocs sinon) ne se produit qu'une seule fois, mais il n'est généralement pas si "pardonnant" d'essayer ... Catch Blocks.
Le code suivant a généralement des problèmes.
Class Thingie {public static thingie getDefaultthingie () {return new Thingie (); }} classe publique foo {private final thingIe thingie; public foo () {try {thingie = new thingie (); } catch (exception e) {thingie = thingie.getdefaultthingie (); // erreur: le champ final Thingie a peut-être déjà été attribué}}}
Vous pouvez modifier cela.
classe publique Foo {Final Thingie privé Thingie; public foo () {thingie tempshingie; essayez {temphie = new thingie (); } catch (exception e) {temphie = thingIe.getDefaulthingie (); } thingie = temphie; }}
1.3 sur l'utilisation finale des membres
Lorsque vous définissez une variable dans une classe, ajoutez le mot-clé final avant, cela signifie qu'une fois cette variable initialisée, elle ne peut pas être modifiée. La signification de l'immuabilité ici est que sa valeur est immuable pour le type de base, et sa référence ne peut plus être modifiée pour la variable d'objet. Cependant, les objets eux-mêmes peuvent être modifiés et Java ne fournit pas de moyen de rendre les objets constants. Cette limitation s'adapte également à des tableaux, qui sont des objets.
Exemple 2
private final int Val_one = 9; private static final int val_two = 99; public static final int val_terre = 999;
Étant donné que Val_One et Val_Tow sont des types primitifs finaux avec des valeurs de temps de compilation, les deux peuvent être utilisés comme constantes de compilation-temps et il n'y a pas de différence significative. VAL_THREE est un moyen plus typique de définir les constantes: définies comme publiques, elle peut être utilisée en dehors du package; défini comme statique pour souligner une seule copie; défini comme final pour indiquer qu'il s'agit d'une constante.
La variable marquée finale devient une constante, mais cette "constante" ne peut être utilisée qu'à l'intérieur de cette classe et ne peut pas être utilisée directement en dehors de la classe. Cependant, lorsque nous utilisons la finale statique publique pour marquer une constante, cette constante devient une constante globale (un champ qui est à la fois statique et final n'occupe qu'un espace de stockage qui ne peut pas être modifié). De plus, les constantes définies de cette manière ne peuvent se voir attribuer des valeurs que lorsqu'elles sont définies, et aucun autre endroit ne peut le faire.
Exemple 3
classe de classe {int i; Valeur publique (int i) {this.i = i; }} classe publique finalData {private static random rand = new random (); ID de chaîne privée; public finalData (String id) {this.id = id; } final privé int i4 = rand.nextint (20); statique final int i5 = rand.nextint (20); public String toString () {return id + ":" + "i4:" + i4 + ", i5 =" + i5; } public static void main (String [] args) {finalData fd1 = new FinalData ("fd1"); System.out.println (FD1); System.out.println ("Création de nouveaux FinalData"); FinalData fd2 = new FinalData ("FD2"); System.out.println (FD1); System.out.println (FD2); }}
résultat
fd1: i4: 6, i5 = 3Creating new FinalDatafd1: i4: 6, i5 = 3fd2: i4: 17, i5 = 3
La section Exemples montre la différence entre la définition d'une valeur finale comme statique (i5) et non statique (i4). Cette différence n'apparaîtra que lorsque la valeur est initialisée pendant l'exécution, car le compilateur traite également la valeur compilée. (Et ils peuvent disparaître de l'optimisation.) Vous verrez cette différence lorsque vous exécutez le programme. Notez que dans FD1 et FD2, la valeur de i5 ne peut pas être modifiée en créant un deuxième objet finalData. En effet, il est statique, qui est initialisé au chargement, pas chaque fois qu'un nouvel objet est créé.
Exemple 4
classe de classe {int i; Valeur publique (int i) {this.i = i; }} classe publique… {valeur privée v1 = nouvelle valeur (11); valeur finale privée v2 = nouvelle valeur (22); valeur finale statique privée v3 = nouvelle valeur (33); …} Public static void main (String [] args) {… fd1.v2.i ++; // ok - object n'est pas constant! fd1.v1 = nouvelle valeur (9); // ok - pas final fd1.v2 = nouvelle valeur (0); // erreur: Impossible de modifier la référence fd1.v3 = nouvelle valeur (1); // erreur: impossible de modifier la référence…} Les variables de V1 à V3 illustrent la signification des références finales. Comme vous pouvez le voir dans Main (), vous ne pouvez pas penser que vous ne pouvez pas modifier sa valeur simplement parce que V2 est définitif. Puisqu'il s'agit d'une référence, final signifie que vous ne pouvez pas pointer à nouveau V2 vers un autre nouvel objet.
Exemple 5
classe publique… {private final int [] a = {1,2,3,4,5,6}; …} Public static void main (String [] args) {… pour (int i = 0; i <fd1.a.length; i ++) fd1.a [i] ++; // ok - object n'est pas constant! fd1.a = new int [3]; // Erreur: Impossible de changer la référence…} Ayant la même signification pour un tableau (il peut modifier sa valeur, mais il ne peut pas pointer vers un nouvel objet), un tableau est une autre référence.
1.4 Résoudre les limites des tableaux finaux
Bien que les références de tableau puissent être déclarées définitivement, les éléments du tableau ne peuvent pas. Cela signifie que ni les classes qui exposent des champs de tableau final publics ni des références de retour à ces champs via leurs méthodes ne sont mutables.
// non immuable - Le tableau des États pourrait être modifié par un malveillant // appelerPublicClass dangereux {private final String [] States = new String [] {"Alabama", "Alaska", "ect"}; String public [] getStates () {States de retour; }}
De même, bien qu'une référence d'objet puisse être déclarée comme un champ final, l'objet qu'il fait référence peut toujours être mutable. Si vous souhaitez créer un objet invariant en utilisant le champ final, vous devez empêcher les références à des tableaux ou des objets mutables de "Escape" votre classe. Pour ce faire sans avoir à cloner le tableau à plusieurs reprises, un moyen facile est de convertir le tableau en liste.
// IMMUTABLE - Renvoie une liste non modifiable à la place PublicClass Safestates {private final String [] States = new String [] {"Alabama", "Alaska", "ect"}; Liste finale privée StatesAsList = new AbstractList () {public objet get (int n) {return states [n]; } public int size () {return states.length; }}; Liste publique getStates () {return statesAslist; }}
1.5 sur l'utilisation des paramètres finaux
Une autre utilisation consiste à définir le paramètre dans la méthode comme final. Pour les variables des types de base, cela n'a pas de signification pratique, car les variables des types de base transmettent des valeurs lors de l'appel de la méthode, c'est-à-dire que vous pouvez modifier la variable de paramètre dans la méthode sans affecter l'instruction d'appel. Cependant, pour les variables d'objets, elle est très pratique car les variables d'objet sont transmises leurs références lors du passage. De cette façon, votre modification des variables d'objet dans la méthode affectera également les variables d'objet dans l'instruction d'appel. Lorsque vous n'avez pas besoin de modifier les variables d'objet en tant que paramètres dans la méthode, l'utilisation explicite de la déclaration Final pour la déclaration vous empêchera de modifier et d'affecter involontairement la méthode d'appel.
1.6 sur les variables de paramètres dans les classes intérieures
De plus, lors de l'utilisation de variables de paramètres dans la méthode de la classe intérieure, cette variable de paramètre doit être déclarée finale avant de pouvoir être utilisée.
Exemple 6 inclass.java
classe publique inclass {void InnerClass (final string str) {class iclass {iclass () {System.out.println (str); }} Iclass ic = new iclass (); } public static void main (String [] args) {incassing inc = new inclass (); Inc.InnerClass ("Hello"); }} 2. Méthode finale
2.1 Utilisation de la méthode finale
1) Afin de garantir que le comportement d'une certaine fonction reste inchangé pendant le processus d'héritage et ne peut pas être remplacé, la méthode finale peut être utilisée.
2) Toutes les méthodes privées et statiques de la classe sont naturellement finales.
2.2 Mots-clés finaux et privés
Toutes les méthodes privées de la classe sont implicitement spécifiées pour être finales. Étant donné que la méthode privée ne peut pas être utilisée, elle ne peut pas être écrasée.
"Override" n'apparaîtra que si une méthode fait partie de l'interface de la classe de base. Autrement dit, un objet doit être transformé vers le haut en son type primitif et appeler la même méthode. Si une méthode est privée, elle ne fait pas partie de l'interface de la classe de base. C'est juste un code caché dans la classe, mais avec le même nom. Cependant, si une méthode publique, protégée ou d'accès à package est générée de la même manière dans la classe d'exportation, la méthode ne produira pas le cas "uniquement avec le même nom" qui se produit dans la classe de base. À ce stade, vous n'avez pas remplacé la méthode, juste généré une nouvelle méthode. Étant donné que la méthode privée ne peut pas être touchée et peut être effectivement cachée, rien d'autre ne doit être pris en compte, sauf pour l'existence de la structure organisationnelle de la classe à laquelle il appartient.
3. Classe finale
Lorsqu'une classe est définie comme finale, la classe ne peut pas être héritée. Et parce que la classe finale interdit l'héritage, toutes les méthodes de la classe finale sont implicitement spécifiées comme finales car elles ne peuvent pas être écrasées.
Final est utilisé dans les classes ou les méthodes pour empêcher les liens entre les méthodes d'être brisées. Par exemple, supposons que la mise en œuvre d'une méthode de classe X suppose que la méthode M fonctionnera d'une manière ou d'une autre. Déclarer X ou M comme final empêchera la classe dérivée de redéfinir M de cette manière, ce qui fait fonctionner x anormalement. Bien qu'il puisse être préférable de mettre en œuvre X sans ces corrélations internes, cela n'est pas toujours possible, et l'utilisation de Final peut empêcher de futurs changements incompatibles.
PS: la différence entre final, enfin et finaliser