JavaRush /Blog Java /Random-FR /Classes internes en méthode locale

Classes internes en méthode locale

Publié dans le groupe Random-FR
Bonjour! Parlons d'un autre type de classe imbriquée. À savoir, sur les classes locales (Méthode classes internes locales). La première chose à retenir avant d'étudier est leur place dans la structure des classes imbriquées. Classes internes en méthode locale - 2Sur la base de notre diagramme, nous pouvons comprendre que les classes locales sont un sous-type de classes internes, dont nous avons parlé en détail dans l'un des documents précédents . Cependant, les classes locales présentent un certain nombre de caractéristiques et de différences importantes par rapport aux classes internes. La clé est dans leur déclaration : une classe locale est déclarée uniquement dans un bloc de code. Le plus souvent - à l'intérieur d'une méthode d'une classe externe. Par exemple, cela pourrait ressembler à ceci :
public class PhoneNumberValidator {

   public void validatePhoneNumber(String number) {

        class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       //...code валидации номера
   }
}
IMPORTANT!Ce code ne sera pas compilé une fois collé dans IDEA si Java 7 est installé. Nous en parlerons les raisons à la fin de la conférence. En quelques mots, le travail des classes locales dépend fortement de la version linguistique. Si ce code ne se compile pas pour vous, vous pouvez soit changer la version linguistique d'IDEA vers Java 8, soit ajouter un mot finalau paramètre de méthode pour qu'il ressemble à ceci : validatePhoneNumber(final String number). Après cela, tout fonctionnera. Ceci est un petit programme – un validateur de numéro de téléphone. Sa méthode validatePhoneNumber()prend une chaîne en entrée et détermine s'il s'agit d'un numéro de téléphone. Et dans cette méthode, nous avons déclaré notre classe locale PhoneNumber. Vous pourriez avoir une question logique : pourquoi ? Pourquoi déclarer une classe dans une méthode ? Pourquoi ne pas utiliser une classe interne classique ? En effet, on pourrait faire ceci : rendre la classe PhoneNumberinterne. Une autre chose est que la décision finale dépend de la structure et de l'objectif de votre programme. Rappelons notre exemple du cours sur les classes internes :
public class Bicycle {

   private String model;
   private int mawWeight;

   public Bicycle(String model, int mawWeight) {
       this.model = model;
       this.mawWeight = mawWeight;
   }

   public void start() {
       System.out.println("Go!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steering wheel to the right!");
       }

       public void left() {

           System.out.println("Steering wheel to the left!");
       }
   }
}
Nous y avons créé HandleBar(le guidon) une classe interne du vélo. Quelle est la différence? Tout d’abord, dans l’utilisation de la classe. La classe HandleBardu deuxième exemple est une entité plus complexe que celle PhoneNumberdu premier. Premièrement, y HandleBara des méthodes publiques rightet left(ne sont ni setter ni getter). Deuxièmement, nous ne pouvons pas prédire à l'avance où Bicyclenous pourrions en avoir besoin ni sa classe externe - il peut s'agir de dizaines d'endroits et de méthodes différents, même au sein d'un même programme. Mais avec un cours, PhoneNumbertout est beaucoup plus simple. Notre programme est très simple. Il n'a qu'une seule fonction : vérifier si le numéro est un numéro de téléphone. Dans la plupart des cas, notre PhoneNumberValidatorprogramme ne sera même pas indépendant, mais simplement une partie de la logique d'autorisation du programme principal. Par exemple, sur différents sites Internet, lors de votre inscription, il vous est souvent demandé de saisir un numéro de téléphone. Et si vous tapez des bêtises à la place des chiffres, le site affichera une erreur : « Ce n'est pas un numéro de téléphone ! Pour le fonctionnement d'un tel site (ou plutôt du mécanisme d'autorisation des utilisateurs), ses développeurs peuvent inclure un analogue du nôtre dans le code PhoneNumberValidator. En d’autres termes, nous avons une classe externe avec une méthode qui sera utilisée à un endroit du programme et nulle part ailleurs. Et si c'est le cas, alors rien n'y changera : une méthode fait son travail, c'est tout. Dans ce cas, puisque toute la logique de travail est collectée dans une seule méthode, il sera beaucoup plus pratique et correct d'y encapsuler une classe supplémentaire. Il n'a pas ses propres méthodes autres que getter et setter. Nous n’avons essentiellement besoin que des données du constructeur. Il n'est pas utilisé dans d'autres méthodes. Il n’y a donc aucune raison d’étendre les informations à son sujet au-delà de la seule méthode dans laquelle elle est utilisée. Nous avons donné un exemple de déclaration d'une classe locale dans une méthode, mais ce n'est pas la seule possibilité. Il peut être déclaré simplement dans un bloc de code :
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

   }

   public void validatePhoneNumber(String phoneNumber) {


       //...code валидации номера
   }
}
Ou même en boucle for!
public class PhoneNumberValidator {


   public void validatePhoneNumber(String phoneNumber) {

       for (int i = 0; i < 10; i++) {

           class PhoneNumber {

               private String phoneNumber;

               public PhoneNumber(String phoneNumber) {
                   this.phoneNumber = phoneNumber;
               }
           }

           //...Howая-то логика
       }

       //...code валидации номера
   }
}
Mais de tels cas sont extrêmement rares. Dans la plupart des cas, la déclaration aura toujours lieu à l'intérieur de la méthode. Nous avons donc traité de l'annonce, nous avons également parlé de « philosophie » :) Quelles autres caractéristiques et différences les classes locales ont-elles par rapport aux classes internes ? Un objet de classe locale ne peut pas être créé en dehors de la méthode ou du bloc dans lequel il est déclaré. Imaginez que nous ayons besoin d'une méthode generatePhoneNumber()qui génère un numéro de téléphone aléatoire et renvoie un PhoneNumber. Nous ne pourrons pas créer une telle méthode dans notre classe validateur dans la situation actuelle :
public class PhoneNumberValidator {

   public void validatePhoneNumber(String number) {

        class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       //...code валидации номера
   }

   //ошибка! компилятор не понимает, что это за класс - PhoneNumber
   public PhoneNumber generatePhoneNumber() {

   }

}
Une autre caractéristique importante des classes locales est la possibilité d'accéder aux variables locales et aux paramètres de méthode. Au cas où vous l'auriez oublié, « local » est une variable déclarée dans une méthode. String russianCountryCodeAutrement dit, si nous créons une variable locale dans une méthode pour certains de nos objectifs validatePhoneNumber(), nous pouvons y accéder depuis la classe locale PhoneNumber. Cependant, il existe ici de nombreuses subtilités qui dépendent de la version du langage utilisé dans le programme. Au début de la conférence, nous avons noté que le code de l'un des exemples peut ne pas être compilé en Java 7, vous vous souvenez ? Voyons maintenant les raisons de cela :) Dans Java 7, une classe locale ne peut accéder à une variable locale ou à un paramètre de méthode que si ceux-ci sont déclarés dans la méthode commefinal :
public void validatePhoneNumber(String number) {

   String russianCountryCode = "+7";

   class PhoneNumber {

       private String phoneNumber;

       //ошибка! параметр метода должен быть объявлен How final!
       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           //ошибка! локальная переменная должна быть объявлена How final!
           System.out.println(russianCountryCode);
       }

   }

   //...code валидации номера
}
Ici, le compilateur a généré deux erreurs. Mais ici tout est en ordre :
public void validatePhoneNumber(final String number) {

   final String russianCountryCode = "+7";

    class PhoneNumber {

       private String phoneNumber;


       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Vous connaissez maintenant la raison pour laquelle le code du début du cours n'a pas été compilé : une classe locale dans Java 7 n'a accès qu'aux finalparamètres de méthode et finalaux variables locales. Dans Java 8, le comportement des classes locales a changé. Dans cette version du langage, la classe locale a accès non seulement aux finalvariables et paramètres -local, mais également aux fichiers effective-final. Effective-finalest une variable dont la valeur n'a pas changé depuis l'initialisation. Par exemple, dans Java 8, nous pouvons facilement afficher une variable sur la console russianCountryCode, même si ce n'est pas le cas final. L'essentiel est que cela ne change pas son sens. Dans cet exemple, tout fonctionne comme il se doit :
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //в Java 7 здесь была бы ошибка
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Mais si nous modifions la valeur de la variable immédiatement après l'initialisation, le code ne sera pas compilé.
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";
  russianCountryCode = "+8";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //error!
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Mais ce n’est pas pour rien qu’une classe locale est un sous-type d’une classe interne ! Ils ont aussi des points communs. Une classe locale a accès à tous les champs et méthodes (même privés) de la classe externe : statiques et non statiques. Par exemple, ajoutons un champ statique à notre classe validateurString phoneNumberRegex :
public class PhoneNumberValidator {

   private static String phoneNumberRegex = "[^0-9]";

   public void validatePhoneNumber(String phoneNumber) {
       class PhoneNumber {

           //......
       }
   }
}
La validation sera effectuée à l'aide de cette variable statique. La méthode vérifie si la chaîne qui lui est transmise contient des caractères qui ne correspondent pas à l'expression régulière " [^0-9]" (c'est-à-dire que le caractère n'est pas un nombre compris entre 0 et 9). Nous pouvons facilement accéder à cette variable depuis la classe locale PhoneNumber. Par exemple, écrivez un getter :
public String getPhoneNumberRegex() {

   return phoneNumberRegex;
}
Les classes locales sont similaires aux classes internes car elles ne peuvent pas définir ou déclarer de membres statiques. Les classes locales dans les méthodes statiques ne peuvent référencer que les membres statiques de la classe englobante. Par exemple, si vous ne définissez pas une variable (champ) de la classe englobante comme statique, le compilateur Java génère une erreur : « Une variable non statique ne peut pas être référencée à partir d'un contexte statique. » Les classes locales ne sont pas statiques car elles ont accès aux membres de l'instance du bloc conteneur. Par conséquent, ils ne peuvent pas contenir la plupart des types de déclarations statiques. Vous ne pouvez pas déclarer une interface à l’intérieur d’un bloc ; les interfaces sont de nature statique. Ce code ne sera pas compilé :
public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Mais si une interface est déclarée dans une classe externe, la classe PhoneNumberpeut l'implémenter :
public class PhoneNumberValidator {
   interface I {}

   public static void validatePhoneNumber(String number) {

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Les classes locales ne peuvent pas déclarer d'initialiseurs statiques (blocs d'initialisation) ou d'interfaces. Mais les classes locales peuvent avoir des membres statiques, à condition qu'il s'agisse de variables constantes ( static final). C'est ça, des cours locaux ! Comme vous pouvez le constater, elles présentent de nombreuses différences par rapport aux classes internes. Nous avons même dû nous plonger dans les fonctionnalités de la version linguistique pour comprendre comment elles fonctionnent :) Dans la prochaine leçon, nous parlerons des classes internes anonymes - le dernier groupe de classes imbriquées. Bonne chance dans tes études ! :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION