JavaRush /Blog Java /Random-FR /Classes, types de classes imbriquées avec exemples
Ярослав
Niveau 40
Днепр

Classes, types de classes imbriquées avec exemples

Publié dans le groupe Random-FR
Salut tout le monde. Dans cette rubrique, je souhaite parler en détail des classes Java et de leurs types afin d'aider les débutants à comprendre ce sujet, et peut-être que les non-débutants apprennent quelque chose de nouveau. Dans la mesure du possible, tout sera montré à l’aide d’exemples réels accompagnés d’exemples de code. Commençons. Classes, types de classes imbriquées avec exemples - 1Et je voudrais noter que l'essentiel est de comprendre les deux premiers types de classes, et que local et anonyme ne sont que des sous-types de classe interne.

Qu'est-ce qu'un cours ?

Une classe est une description logique de quelque chose, un modèle avec lequel vous pouvez créer des instances réelles de cette chose. En d’autres termes, il s’agit simplement d’une description de ce à quoi devraient ressembler les entités créées : quelles propriétés et méthodes elles devraient avoir. Les propriétés sont des caractéristiques d'une entité, les méthodes sont des actions qu'elle peut effectuer. Un bon exemple de cours tiré de la vie réelle, qui permet de comprendre ce qu'est un cours, peut être considéré comme le dessin : les dessins sont utilisés pour décrire des structures (catapulte, tournevis), mais un dessin n'est pas un dessin. Tout comme les ingénieurs utilisent des plans pour créer des conceptions, la programmation utilise des classes pour créer des objets dotés de propriétés et de méthodes décrites.
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
Dans cet exemple, nous avons créé une classe Java qui décrit l'entité « étudiant » : chaque étudiant a un nom, un groupe et une spécialité. Désormais, à d’autres endroits du programme, nous pouvons créer des exemples réels de cette classe. En d’autres termes : si la classe Studentest un portrait de ce qu’un étudiant devrait être, alors l’instance créée est l’étudiant lui-même. Un exemple de création d'un nouvel élève : new Student("Ivan", "KI-17-2", "Computer Engineering");L'opérateur newrecherche la classe Studentpuis appelle une méthode spéciale (constructeur) de cette classe. Le constructeur rend un objet de classe tout fait Student- notre cher étudiant affamé sans bourse :))

Types de cours en Java

En Java, il existe 4 types de classes à l'intérieur d'une autre classe :
  1. Les classes internes imbriquées sont des classes non statiques à l'intérieur d'une classe externe.

  2. Les classes statiques imbriquées sont des classes statiques situées à l'intérieur d'une classe externe.

  3. Les classes locales Java sont des classes au sein des méthodes.

  4. Les classes Java anonymes sont des classes créées à la volée.

Nous parlerons de chacun d'eux séparément.

Classes non statiques à l'intérieur d'une classe externe

Tout d’abord, je veux que vous compreniez ce que c’est avec un exemple réel, car cela rend les choses beaucoup plus faciles à comprendre. Alors maintenant, nous allons décomposer un très gros objet en composants plus petits, et nous allons démonter un avion ! Cependant, à titre d'exemple, il suffira de le montrer un peu, nous ne le décomposerons pas complètement. Pour visualiser ce processus, nous utiliserons un schéma d'avion. Classes, types de classes imbriquées avec exemples - 2 Tout d'abord, nous devons créer une classe Airplanedans laquelle nous pouvons ajouter une petite description : nom de l'avion, code d'identification, vol.
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
Nous voulons maintenant ajouter des ailes. Créer une classe séparée ? C'est peut-être la logique si nous avons un programme complexe de conception d'avions et où nous devons créer un grand nombre de classes dérivées (des classes qui ont la même logique que la classe parent, c'est-à-dire la classe dont elles héritent, mais ils étendent donc la classe parent en ajoutant de la logique ou des caractéristiques plus détaillées), mais que se passe-t-il si nous avons juste un jeu dans lequel nous n'avons qu'un seul avion ? Il sera alors plus rationnel pour nous de terminer toute la structure en un seul endroit (dans une seule classe). C’est là que les classes imbriquées non statiques entrent en jeu. Il s’agit essentiellement d’une description plus détaillée de certains détails de notre classe externe. Dans cet exemple, nous devons créer des ailes pour un avion – gauche et droite. Créons !
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
Nous avons donc créé une classe imbriquée non statique Wing(aile) à l'intérieur d'une classe Airplane(avion) ​​et ajouté deux variables : l'aile gauche et l'aile droite. Et chaque aile a ses propres propriétés (couleur, modèle) que l'on peut modifier. De cette façon, vous pouvez doter les structures en personnel autant que nécessaire. Et remarque : plus tôt sur le schéma, il y avait pas mal de pièces pour l'avion, et, en fait, on peut diviser toutes les pièces en classes internes, mais un tel processus n'est pas toujours conseillé. Ces moments doivent être retracés en fonction de la tâche. Vous n’aurez peut-être pas besoin d’ailes du tout pour résoudre le problème. Il n’est alors pas nécessaire de les faire. C'est comme couper une personne en jambes, bras, torse et tête - c'est possible, mais pourquoi si cette classe n'est utilisée que pour stocker des données sur les personnes ? Caractéristiques des classes Java imbriquées non statiques :
  1. Ils n'existent que dans les objets, donc pour les créer, vous avez besoin d'un objet. En d'autres termes : nous avons conçu notre aile pour qu'elle fasse partie d'un avion, donc pour créer une aile, nous avons besoin d'un avion, sinon nous n'en avons pas besoin.
  2. Il ne peut pas y avoir de variables statiques dans une classe Java. Si vous avez besoin de constantes ou de tout autre élément statique, vous devez les déplacer vers une classe externe. Cela est dû au couplage étroit de la classe imbriquée non statique avec la classe externe.
  3. La classe a un accès complet à tous les champs privés de la classe externe. Cette fonctionnalité fonctionne de deux manières.
  4. Vous pouvez obtenir une référence à une instance d'une classe externe. Exemple : Avion. Ceci est un lien vers un avion, ceci est un lien vers une aile.

Classes statiques à l'intérieur d'une classe externe

Ce type de classe n'est pas différent d'une classe externe classique, à une exception près : pour créer une instance d'une telle classe, vous devez lister le chemin complet de la classe externe à celle souhaitée, séparé par un point. Par exemple : Building.Plaftorm platform = new Building.Platform(); les classes statiques sont utilisées pour mettre côte à côte des classes liées afin de faciliter l'utilisation de la structure logique. Par exemple : nous pouvons créer une classe externe Building, où il y aura une liste spécifique de classes qui représenteront un bâtiment spécifique.
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
Cet exemple montre comment les classes statiques vous permettent de regrouper une structure logique sous une forme plus pratique. S’ils n’existaient pas, il faudrait créer 4 classes complètement différentes. Les avantages de cette approche :
  1. Le nombre de classes a diminué.
  2. Toutes les classes se trouvent dans leur classe parent. Nous sommes capables de retracer toute la hiérarchie sans ouvrir chaque classe séparément.
  3. Nous pouvons nous référer à la classe Building, et l'EDI affichera déjà la liste complète de toutes les sous-classes de cette classe. Cela facilitera la recherche des cours dont vous avez besoin et montrera l’ensemble de la situation de manière plus globale.
Un exemple de création d'une instance d'une classe statique imbriquée :Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); je voudrais également noter que cette stratégie est utilisée dans les classes AWT 2D pour décrire des formes, telles que Line2D, Arc2D, Ellipse2D et autres.

Cours locaux

Ces classes sont déclarées dans d’autres méthodes. En fait, ils ont toutes les propriétés d'une classe imbriquée non statique, seules leurs instances ne peuvent être créées que dans une méthode, et la méthode ne peut pas être statique (pour les créer il faut une instance d'une classe externe, une référence à un instance de l'objet appelant est implicitement transmise aux méthodes non statiques, et dans une méthode statique, il n'y a pas de méthode pour ce lien). Mais ils ont leurs propres caractéristiques :
  1. Les classes locales ne peuvent fonctionner qu'avec les variables de la méthode finale. Le fait est que les instances de classes locales peuvent être stockées dans le tas une fois la méthode terminée et que la variable peut être effacée. Si la variable est déclarée finale, le compilateur peut enregistrer une copie de la variable pour une utilisation ultérieure par l'objet. Et encore une chose : depuis les versions 8+ de Java, vous pouvez utiliser des variables non finales dans les classes locales, mais uniquement à condition qu'elles ne changent pas.
  2. Les classes locales ne peuvent pas être déclarées avec des modificateurs d'accès.
  3. Les classes locales ont accès aux variables de méthode.
Les classes locales peuvent être trouvées extrêmement rarement, car elles rendent le code difficile à lire et n'ont aucun avantage, sauf un : l'accès aux variables de méthode. Je ne sais pas quel exemple de classe locale peut être pris pour montrer leur utilisation efficace, alors je vais juste montrer mon exemple. Disons que nous avons une classe Person(on supposera qu'il s'agit d'une personne) avec des propriétés street(rue), house(maison). Nous aimerions restituer un objet pour accéder uniquement à l'emplacement de la personne. Pour ce faire, nous avons créé l’interface AddressContainer, qui implique le stockage de données sur la localisation d’une personne.
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
Comme vous pouvez le voir, à l'intérieur de la méthode, nous avons créé une classe qui implémente le stockage de l'emplacement d'une personne, y avons créé des variables constantes (de sorte qu'après avoir quitté la méthode, les variables soient stockées dans un objet) et implémenté une méthode pour obtenir l'adresse et maison. Nous pouvons désormais utiliser cet objet à d’autres endroits du programme pour obtenir la localisation d’une personne. Je comprends que cet exemple n'est pas idéal et qu'il serait plus correct de le faire simplement en laissant les getters dans la classe Person, cependant, la création de cette classe et son utilisation possible ont été montrées, et ensuite c'est à vous de décider.

Cours anonymes

Sous le capot, les classes anonymes ne sont que des classes imbriquées non statiques ordinaires. Leur particularité est leur facilité d’utilisation. Vous pouvez écrire votre classe directement lors de la création d'une instance d'une autre classe.
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
Essentiellement, nous combinons simplement deux choses en un seul endroit : créer une instance d'une classe ( Animal) et créer une instance de sa classe interne héritière ( Tiger). Sinon, nous devons créer la classe séparément et utiliser des constructions plus longues pour obtenir le même résultat. Le recours à des classes anonymes se justifie dans de nombreux cas, notamment lorsque :
  • le corps de classe est très petit ;
  • une seule instance de la classe est nécessaire ;
  • la classe est utilisée à l'endroit où elle a été créée ou immédiatement après ;
  • Le nom de la classe n’a pas d’importance et ne facilite pas la compréhension du code.
Les classes anonymes sont souvent utilisées dans les interfaces graphiques pour créer des gestionnaires d'événements. Par exemple, pour créer un bouton et réagir à son clic :
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
Cependant, après Java 8, ils ont commencé à utiliser des expressions lambda, mais beaucoup de code a quand même été écrit avant la version 8 et vous pouvez rencontrer (et rencontrerez lors de votre formation à JavaRush) de telles inscriptions.\ Analogue avec les lambdas :
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Fin de l'article Merci à tous pour votre attention et j'espère que vous avez appris quelque chose de nouveau ou compris quelque chose que vous n'aviez pas compris auparavant. Je tiens également à préciser que cet article appartient à la catégorie « souci du détail » . C'est mon premier travail, j'espère donc qu'il a été utile à quelqu'un. Dans un futur proche, quand de nouvelles idées viendront, j'essaierai d'écrire autre chose, je n'ai qu'une idée... Bonne chance à tous et réussite en programmation :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION