JavaRush /Blog Java /Random-FR /Getters et setters

Getters et setters

Publié dans le groupe Random-FR
Bonjour! Lors de cours précédents, vous avez déjà appris à créer vos propres classes à part entière, avec des domaines et des méthodes. C'est un sérieux progrès, bravo ! Mais maintenant je dois vous dire une vérité désagréable. Nous n’avons pas tout à fait bien créé nos classes ! Pourquoi? À première vue, il n’y a aucune erreur dans cette classe :
public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}
En fait, il y en a. Imaginez que, assis au travail, vous ayez écrit un cours comme celui-ci Cat, désignant les chats. Et il est rentré chez lui. Pendant votre absence, un autre programmeur est venu travailler, a créé sa propre classe Main, où il a commencé à utiliser la classe que vous avez écrite Cat.
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
Peu importe pourquoi il l’a fait ou comment cela s’est produit : peut-être que la personne était fatiguée ou n’a pas suffisamment dormi. Une autre chose est importante : notre classe actuelle Catvous permet d'attribuer des valeurs folles aux champs. De ce fait, le programme contient des objets avec un état incorrect, comme ce chat âgé de -1000 ans. Quelle erreur avons-nous fini par commettre ? Lorsque nous avons créé la classe, nous avons exposé ses données. Les champs nameet agesont weightdans le domaine public. Ils sont accessibles n'importe où dans le programme : il suffit de créer un objet Cat- et c'est tout, tout programmeur a accès à ses données directement via l'opérateur «. »
Cat cat = new Cat();
cat.name = "";
Ici, nous accédons directement au champ nameet définissons sa valeur. Nous devons d’une manière ou d’une autre protéger nos données contre les interférences extérieures incorrectes. Que faut-il pour cela ? Tout d'abord, toutes les variables d'instance (champs) doivent être marquées d'un modificateur private. Private est le modificateur d'accès le plus strict en Java. Si vous l'utilisez, les champs de la classe Catne seront pas accessibles en dehors de celle-ci.
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";//error! The name field in the Cat class has private access!
   }
}
Le compilateur le voit et génère immédiatement une erreur. Désormais, les champs semblent protégés. Mais il s'avère que leur accès est « hermétiquement » fermé : le programme ne peut même pas récupérer le poids d'un chat existant, si nécessaire. Ce n’est pas non plus une option : sous cette forme, notre classe est pratiquement impossible à utiliser. Idéalement, nous devons autoriser une sorte d’accès limité aux données :
  • D'autres programmeurs devraient être capables de créer des objetsCat
  • Ils doivent être capables de lire les données d'objets déjà existants (par exemple, obtenir le nom ou l'âge d'un chat déjà existant)
  • Il devrait également être possible d'attribuer des valeurs de champ. Mais en même temps, uniquement des valeurs correctes. Nos objets doivent être protégés des objets incorrects (pas d'« âge = -1000 ans » et autres).
La liste des exigences est décente ! Mais en fait, tout cela est facilement réalisé en utilisant des méthodes spéciales - getters et setters .
Getters et setters - 2
Le nom vient de l'anglais « get » - « recevoir » (c'est-à-dire « méthode pour obtenir la valeur d'un champ ») et set - « set » (c'est-à-dire « méthode pour définir la valeur d'un champ »). Voyons à quoi ils ressemblent en utilisant notre classe comme exempleCat :
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       this.weight = weight;
   }
}
Comme vous pouvez le constater, tout est assez simple :) Leurs noms sont le plus souvent constitués du mot get/set + le nom du champ dont ils sont responsables. Par exemple, une méthode getWeight()renvoie la valeur du champ weightde l'objet pour lequel elle a été appelée. Voilà à quoi cela ressemble dans le programme :
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       String barsikName = barsik.getName();
       int barsikAge = barsik.getAge();
       int barsikWeight = barsik.getWeight();

       System.out.println("Cat name: " + barsikName);
       System.out.println("Cat's age: " + barsikAge);
       System.out.println("Weight of the cat: " + barsikWeight);
   }
}
Sortie de la console :

Name кота: Барсик
Возраст кота: 5
Вес кота: 4
Désormais, à partir d'une autre classe ( Main), il y a accès aux champs Cat, mais uniquement via des getters . Veuillez noter que les getters ont un modificateur d'accès public, ce qui signifie qu'ils sont accessibles depuis n'importe où dans le programme. Qu’en est-il de l’attribution de valeurs ? Les méthodes Setter en sont responsables
public void setName(String name) {
   this.name = name;
}
Leur travail, comme vous pouvez le constater, est également simple. Nous appelons une méthode setName()sur un objet Cat, lui passons une chaîne en argument, et cette chaîne est affectée à un champ namede notre objet.
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);

       System.out.println("The original name of the cat is " + barsik.getName());
       barsik.setName("Basil");
       System.out.println("The new name of the cat -" + barsik.getName());
   }
}
Ici, nous avons utilisé à la fois des getters et des setters. Tout d'abord, à l'aide d'un getter, nous avons reçu et affiché sur la console le nom initial du chat. Ensuite, à l'aide d'un setter, nameune nouvelle valeur a été attribuée à son champ - "Vasily". Et puis, à l’aide d’un getter, nous avons récupéré le nom pour vérifier s’il avait vraiment changé. Sortie de la console :

Изначальное Name кота — Барсик
Новое Name кота — Васorй
Il semblerait, quelle est la différence ? Nous pouvons également attribuer des valeurs incorrectes aux champs d'objet, même si nous avons des setters :
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
Sortie de la console :

Возраст Барсика — -1000 лет
La différence est qu'un setter est une méthode à part entière . Et dans une méthode, contrairement à un champ, vous pouvez mettre la logique de vérification dont vous avez besoin pour éviter les valeurs inacceptables. Par exemple, vous pouvez facilement désactiver l'attribution d'un nombre négatif à l'âge :
public void setAge(int age) {
   if (age >= 0) {
       this.age = age;
   } else {
       System.out.println("Error! Age cannot be negative!");
   }
}
Et maintenant notre code fonctionne correctement !
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
Sortie de la console :

Ошибка! Возраст не может быть отрицательным числом!
Возраст Барсика — 5 лет
Il existe une restriction à l'intérieur du setter qui protège contre les tentatives de définition de données incorrectes. L'âge de Barsik est resté inchangé. Les getters et setters doivent toujours être créés. Même si vos champs n'ont aucune restriction sur les valeurs possibles, elles ne causeront aucun préjudice. Imaginez une situation : vous et vos collègues écrivez un programme ensemble. Vous avez créé une classe Catavec des champs publics et tous les programmeurs les utilisent à leur guise. Et puis un beau jour, vous vous rendez compte : « Bon sang, tôt ou tard, quelqu'un pourrait accidentellement attribuer un nombre négatif à une variable weight! Nous devons créer des setters et rendre tous les champs privés ! » Vous les créez et tout le code écrit par vos collègues se casse instantanément. Après tout, ils avaient déjà écrit un tas de code permettant d’accéder Catdirectement aux champs.
cat.name = "Hippopotamus";
Et voilà que les champs sont devenus privés et le compilateur produit un tas d'erreurs !
cat.name = "Hippopotamus";//error! The name field of the Cat class has private access!
Dans une telle situation, il serait préférable de masquer les champs et de créer des getter-setters dès le début . Tous vos collègues les utiliseraient, et si vous vous rendiez compte tardivement que vous deviez limiter les valeurs des champs, vous ajouteriez simplement une vérification à l'intérieur du setter. Et personne ne briserait le code déjà écrit. Bien sûr, si vous souhaitez accéder en lecture seule à un certain champ, vous pouvez créer un getter pour celui-ci. « À l’extérieur », c’est-à-dire en dehors de votre classe, seules les méthodes doivent être accessibles. Les données doivent être masquées.
Getters et setters - 4
Une analogie peut être faite avec un téléphone mobile. Imaginez qu'au lieu d'un téléphone portable ordinaire allumé, vous receviez un téléphone avec un boîtier ouvert, où se trouvent tous les fils, circuits, etc. qui dépasse. Le téléphone fonctionne : si vous faites de gros efforts et jouez avec les schémas, vous pourrez peut-être même passer un appel. Mais vous allez probablement le casser. Au lieu de cela, le fabricant vous propose une interface : le client compose simplement les numéros requis, appuie sur le bouton vert du combiné et l'appel commence. Et il ne se soucie pas de ce qui se passe à l’intérieur avec les circuits et les fils et de la manière dont ils accomplissent leur tâche. Dans cet exemple, l’entreprise a un accès limité aux « éléments internes » (données) du téléphone et n’a laissé que l’interface (méthodes) à l’extérieur. En conséquence, le client obtiendra ce qu’il voulait (passer un appel) et ne cassera certainement rien à l’intérieur.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION