Quel est le but de la «classe finale» en Java?

Je lis un livre sur Java et dit que vous pouvez déclarer la classe entière comme final . Je ne peux pas penser à quoi que ce soit où j’utiliserais cela.

Je ne suis que novice en programmation et je me demande si les programmeurs l’utilisent réellement dans leurs programmes . S’ils le font, quand l’utilisent-ils pour que je puisse mieux le comprendre et savoir quand l’utiliser.

Si Java est orienté object et que vous déclarez une classe final , cela n’empêche-t-il pas l’idée de classe d’avoir les caractéristiques des objects?

S’ils le font, quand l’utilisent-ils pour que je puisse mieux le comprendre et savoir quand l’utiliser.

Une classe final est simplement une classe qui ne peut pas être étendue .

(Cela ne signifie pas que toutes les références aux objects de la classe agiraient comme si elles avaient été déclarées comme étant final .)

Quand il est utile de déclarer une classe comme final est couvert dans les réponses de cette question:

  • Bonnes raisons d’interdire l’inheritance en Java?

Si Java est orienté object et que vous déclarez une classe final , cela n’empêche-t-il pas l’idée de classe d’avoir les caractéristiques des objects?

Dans un certain sens oui.

En marquant une classe comme finale, vous désactivez une fonctionnalité puissante et flexible du langage pour cette partie du code. Certaines classes ne doivent cependant pas (et dans certains cas ne peuvent pas) être conçues pour prendre en compte de manière satisfaisante le sous-classement. Dans ces cas, il est logique de marquer la classe comme finale, même si elle limite la POO. (Rappelez-vous cependant qu’une classe finale peut encore étendre une autre classe non finale.)


Article connexe: Java: quand créer une classe finale

En Java, les éléments avec le modificateur final ne peuvent pas être modifiés!

Cela inclut les classes finales, les variables finales et les méthodes finales:

  • Une classe finale ne peut être prolongée par aucune autre classe
  • Une variable finale ne peut pas être réaffectée à une autre valeur
  • Une méthode finale ne peut pas être annulée

Un scénario où final est important lorsque vous souhaitez empêcher l’inheritance d’une classe pour des raisons de sécurité. Cela vous permet de vous assurer que le code que vous utilisez ne peut pas être remplacé par quelqu’un.

Un autre scénario concerne l’optimisation: il me semble que le compilateur Java intègre certains appels de fonctions des classes finales. Donc, si vous appelez ax() et que a est déclaré final , nous soaps au moment de la compilation ce que sera le code et peut être intégré dans la fonction appelante. Je n’ai aucune idée si cela est effectivement fait, mais avec le final c’est une possibilité.

Le meilleur exemple est

Classe finale publique Ssortingng

qui est une classe immuable et ne peut pas être étendue. Bien sûr, il n’y a pas que rendre la classe finale immuable.

Si vous imaginez la hiérarchie de classes comme un arbre (comme en Java), les classes abstraites ne peuvent être que des twigs et les classes finales sont celles qui ne peuvent être que des feuilles. Les classes qui ne tombent dans aucune de ces catégories peuvent être à la fois des twigs et des feuilles.

Il n’y a pas de violation des principes d’OO ici, la finale fournit simplement une belle symésortinge.

En pratique, vous voulez utiliser final si vous voulez que vos objects soient immuables ou si vous écrivez une API, pour signaler aux utilisateurs de l’API que la classe n’est pas destinée à l’extension.

Lecture pertinente: Le principe du «open-closed» par Bob Martin.

Citation clé:

Les entités logicielles (classes, modules, fonctions, etc.) doivent être ouvertes pour l’extension, mais fermées pour modification.

Le mot clé final est le moyen d’imposer cela en Java, qu’il soit utilisé sur des méthodes ou sur des classes.

Le mot clé final lui-même signifie que quelque chose est définitif et qu’il n’est pas censé être modifié de quelque manière que ce soit. Si une classe est marquée final alors elle ne peut pas être étendue ou sous-classée. Mais la question est de savoir pourquoi marquons-nous une final classe? IMO il y a plusieurs raisons:

  1. Normalisation: Certaines classes exécutent des fonctions standard et ne sont pas destinées à être modifiées, par exemple des classes exécutant diverses fonctions liées aux manipulations de chaînes ou aux fonctions mathématiques, etc.
  2. Motifs de sécurité : Parfois, nous écrivons des classes qui exécutent diverses fonctions d’authentification et de mot de passe et nous ne voulons pas qu’elles soient modifiées par quelqu’un d’autre.

J’ai entendu dire que la correction de la classe final améliorait l’efficacité, mais franchement, je ne pouvais pas trouver cet argument très important.

Si Java est orienté object et que vous déclarez une classe finale, cela n’empêche-t-il pas l’idée de classe d’avoir les caractéristiques des objects?

Peut-être que oui, mais parfois c’est le but recherché. Parfois, nous faisons cela pour obtenir de plus grands avantages de la sécurité, etc. en sacrifiant la capacité de cette classe à être étendue. Mais une classe finale peut encore étendre une classe si nécessaire.

Sur un côté, nous devrions préférer la composition à l’inheritance et le mot clé final aide réellement à appliquer ce principe.

Si la classe est marquée comme final , cela signifie que la structure de la classe ne peut être modifiée par aucun élément externe. Là où c’est le plus visible, c’est lorsque vous faites de l’inheritance polymorphe traditionnel, la class B extends A essentiellement class B extends A ne fonctionne tout simplement pas. C’est essentiellement un moyen de protéger certaines parties de votre code (dans la mesure du possible) .

Pour clarifier, le marquage final classe ne marque pas ses champs comme final et, à ce titre, ne protège pas les propriétés de l’object mais la structure réelle de la classe à la place.

Soyez prudent lorsque vous faites un cours “final”. Parce que si vous voulez écrire un test unitaire pour une classe finale, vous ne pouvez pas sous-classer cette dernière classe pour utiliser la technique de rupture de dépendance “Subclass and Override Method” décrite dans le livre de Michael C. Feathers “Working Effective with Legacy Code” . Dans ce livre, Feathers a dit: “Sérieusement, il est facile de croire que les scellés et les derniers sont une erreur erronée, qu’ils n’auraient jamais dû être ajoutés aux langages de programmation. Mais le vrai défaut nous incombe. Quand nous dépendons directement les bibliothèques qui sont hors de notre contrôle, nous ne demandons que des problèmes. ”

POUR RÉPONDRE AU PROBLÈME DE CLASSE FINALE:

Il y a deux façons de faire une finale de classe. La première consiste à utiliser le mot clé final dans la déclaration de classe:

 public final class SomeClass { // . . . Class contents } 

La seconde façon de faire une classe finale est de déclarer tous ses constructeurs comme privés:

 public class SomeClass { public final static SOME_INSTANCE = new SomeClass(5); private SomeClass(final int value) { } 

Le fait de le marquer comme final vous évite le problème si vous constatez qu’il s’agit d’une finale réelle, pour montrer comment regarder cette classe de test. semble public à première vue.

 public class Test{ private Test(Class beanClass, Class stopClass, int flags) throws Exception{ // . . . snip . . . } } 

Malheureusement, le seul constructeur de la classe étant privé, il est impossible d’étendre cette classe. Dans le cas de la classe Test, il n’ya aucune raison que la classe soit définitive. La classe Test est un bon exemple de la façon dont les classes finales implicites peuvent causer des problèmes.

Vous devez donc le marquer comme final lorsque vous faites implicitement une classe finale en rendant son constructeur privé.

final class peut éviter de casser l’API publique lorsque vous ajoutez de nouvelles méthodes

Supposons que sur la version 1 de votre classe de Base vous faites:

 public class Base {} 

et un client fait:

 class Derived extends Base { public int method() { return 1; } } 

Alors si dans la version 2 vous voulez append une method méthode à Base :

 class Base { public Ssortingng method() { return null; } } 

cela briserait le code client.

Si nous avions plutôt utilisé la final class Base , le client n’aurait pas pu hériter et l’ajout de la méthode ne briserait pas l’API.

Oui, parfois, vous voudrez peut-être cela, que ce soit pour des raisons de sécurité ou de rapidité. C’est fait aussi en C ++. Ce n’est peut-être pas ce qui est applicable pour les programmes, mais plutôt pour les frameworks. http://www.glenmccl.com/perfj_025.htm

Une classe finale est une classe qui ne peut pas être étendue. De même, des méthodes peuvent être déclarées comme finales pour indiquer qu’elles ne peuvent pas être remplacées par des sous-classes.

Empêcher la classe d’être sous-classée pourrait être particulièrement utile si vous écrivez des API ou des bibliothèques et que vous voulez éviter d’être étendu pour modifier le comportement de base.

Un avantage de garder une classe comme final: –

La classe de chaîne est maintenue définitive pour que personne ne puisse remplacer ses méthodes et modifier la fonctionnalité. Par exemple, personne ne peut modifier la fonctionnalité de la méthode length (). Il retournera toujours la longueur d’une chaîne.

Le développeur de cette classe voulait que personne ne modifie les fonctionnalités de cette classe, il l’a donc gardé comme final.

Les classes finales ne peuvent pas être prolongées. Donc, si vous voulez qu’une classe se comporte d’une certaine manière et que personne ne remplace les méthodes (avec un code potentiellement moins efficace et plus malveillant), vous pouvez déclarer la classe entière comme une méthode finale ou spécifique que vous ne voulez pas utiliser. modifié.

Puisque déclarer une classe n’empêche pas une classe d’être instanciée, cela ne signifie pas qu’elle empêchera la classe d’avoir les caractéristiques d’un object. C’est juste que vous devrez vous en tenir aux méthodes telles qu’elles sont déclarées dans la classe.

Pensez à FINAL comme étant la “fin de la ligne” – ce type ne peut plus produire de progéniture. Donc, quand vous le voyez de cette façon, vous rencontrerez des tonnes de scénarios du monde réel qui vous obligeront à marquer un marqueur de fin de ligne pour la classe. C’est la conception pilotée par le domaine – si votre domaine demande à une ENTITY (classe) donnée de ne pas créer de sous-classes, marquez-la comme FINAL.

Je devrais noter que rien ne vous empêche d’hériter d’une classe “devrait être étiquetée comme finale”. Mais cela est généralement considéré comme un “abus d’inheritance”, et ce parce que le plus souvent, vous souhaitez hériter d’une fonction de la classe de base de votre classe.

La meilleure approche consiste à examiner le domaine et à le laisser dicter vos décisions de conception.

Comme indiqué ci-dessus, si vous souhaitez que personne ne puisse modifier la fonctionnalité de la méthode, vous pouvez la déclarer finale.

Exemple: chemin d’access au fichier du serveur d’applications pour le téléchargement / téléchargement, divisant la chaîne en fonction du décalage, ces méthodes vous permettent de le déclarer final afin que ces fonctions ne soient pas modifiées. Et si vous voulez de telles méthodes finales dans une classe séparée, définissez cette classe comme classe finale. Donc, la classe finale aura toutes les méthodes finales, où la méthode finale peut être déclarée et définie en classe non finale.

La classe Android Looper en est un bon exemple pratique. http://developer.android.com/reference/android/os/Looper.html

La classe Looper fournit certaines fonctionnalités qui NE SONT PAS destinées à être remplacées par une autre classe. Par conséquent, pas de sous-classe ici.

La classe finale est utilisée lorsque vous souhaitez standardiser les méthodes et vous assurer qu’elles ne sont pas écrasées par quelqu’un d’autre.
Alors, pourquoi certaines classes sont-elles déclarées comme Final?

  1. Étant donné que les classes finales ne peuvent pas être étendues, vous pouvez les traiter comme des primitives et ne pas avoir à vous soucier du changement de ces classes.
  2. Pour des raisons de sécurité, vous ne voulez pas que le code que vous écrivez soit remplacé par quelqu’un d’autre.

Si vous définissez une classe comme finale, vous ne pouvez pas la prolonger.

 final class Bike{} class Honda1 extends Bike{ void run(){System.out.println("running safely with 100kmph");} public static void main(Ssortingng args[]){ Honda1 honda= new Honda(); honda.run(); } } Output:Comstack Time Error 

Peu de temps, une classe, une variable ou une méthode déclarée comme finale ne peut pas être modifiée.

Ce qui est plus important est mon opinion:

Honnêtement, je crois qu’un mot clé final est une erreur car son existence permet à un utilisateur de définir quelque chose qui n’est pas final . Tout en Java devrait être final par défaut sauf les méthodes d’interface (par sa définition). C’était un choix malheureux de laisser toutes les méthodes d’instance être virtual par défaut (en termes de c # ). L’essentiel est de forcer l’utilisateur à penser d’abord et à définir explicitement une méthode comme étant virtual , ce qui lui permettrait de se demander si cette méthode devrait laisser les autres passer outre, si c’est really nécessaire ou de le persuader de revoir son code.

Disons que vous avez une classe Employee qui a une méthode greet . Lorsque la méthode de greet est appelée, elle imprime simplement Hello everyone! . Donc, c’est le comportement attendu de la méthode de greet

 public class Employee { void greet() { System.out.println("Hello everyone!"); } } 

Maintenant, laissez la sous-classe Employee GrumpyEmployee et remplacez la méthode d’ greet comme indiqué ci-dessous.

 public class GrumpyEmployee extends Employee { @Override void greet() { System.out.println("Get lost!"); } } 

Maintenant, dans le code ci-dessous, regardez la méthode sayHello . Il prend l’instance de Employee tant que paramètre et appelle la méthode de bienvenue en espérant qu’il dirait Hello everyone! Mais ce que nous obtenons, c’est se Get lost! . Ce changement de comportement est dû à l’ Employee grumpyEmployee = new GrumpyEmployee();

 public class TestFinal { static Employee grumpyEmployee = new GrumpyEmployee(); public static void main(Ssortingng[] args) { TestFinal testFinal = new TestFinal(); testFinal.sayHello(grumpyEmployee); } private void sayHello(Employee employee) { employee.greet(); //Here you would expect a warm greeting, but what you get is "Get lost!" } } 

Cette situation peut être évitée si la classe Employee était final . Imaginez la quantité de chaos qu’un programmeur effronté pourrait causer si Ssortingng Class n’était pas déclaré comme final .

L’orientation de l’object ne concerne pas l’inheritance, il s’agit de l’encapsulation. Et l’inheritance brise l’encapsulation.

Déclarer une classe finale est parfaitement logique dans de nombreux cas. Tout object représentant une «valeur» comme une couleur ou une sum d’argent pourrait être définitif. Ils sont autonomes.

Si vous écrivez des bibliothèques, rendez vos classes définitives à moins que vous ne les indiquez explicitement. Sinon, les gens peuvent dériver vos classes et remplacer les méthodes, en brisant vos hypothèses / invariants. Cela peut également avoir des conséquences sur la sécurité.

Joshua Bloch dans «Effective Java» recommande de concevoir explicitement pour l’inheritance ou de l’interdire et il note que la conception pour l’inheritance n’est pas si facile.