Java >> Tutoriel Java >  >> Tag >> class

Introduction à la structure de classe en Java

Enfin, nous avons enfin atteint le point où nous pouvons commencer à écrire notre propre code. Pour commencer, nous allons apprendre la structure de classe en implémentant quelques programmes :Hello World en Java et une classe de points à deux dimensions.

Concepts

Avant de faire quoi que ce soit, parlons théorie.

Portée

Lorsque nous avons introduit les méthodes, nous avons expliqué comment les méthodes d'instance pouvaient utiliser des variables externes pour accomplir une tâche. A l'époque, on évitait cette notion de classes en utilisant le volet interactions et les Strings. Maintenant que nous prévoyons de nous attaquer à une classe réelle, cela pourrait aider à comprendre un peu la portée.

Portée définit une région où une variable est accessible. Par exemple, une classe peut contenir des variables un peu comme une méthode. Ces variables sont appelées champs et elles sont accessibles par n'importe quelle méthode de la classe.

Parfois, les champs sont appelés variables globales car leur portée englobe toute la classe. De même, une variable locale à l'intérieur d'une méthode n'est disponible qu'à l'intérieur de cette méthode.

Si nous repensons à la leçon sur les piles, la portée commence à avoir beaucoup de sens. Une fois qu'une méthode est terminée, elle est retirée de la pile. Toutes les variables locales associées à cette méthode sont également perdues.

La portée aura des conséquences assez intéressantes à mesure que nous avancerons avec le flux de contrôle et les boucles. Pour l'instant, la portée a une fonctionnalité très importante :elle nous permet d'avoir plusieurs variables du même nom.

Comme nous le verrons plus tard, une variable locale peut partager un nom avec une variable globale. La façon dont nous différencions les deux est avec un mot-clé spécial appelé this . Le this Le mot-clé nous permet de modifier la variable globale alors qu'une variable locale partage le même nom.

Tout comme la surcharge de méthode, this nous permet de maintenir un code propre. Cependant, this peut parfois prêter à confusion et ne doit être utilisé que dans certains scénarios.

Initialisation de l'objet

Maintenant que nous sommes à l'aise avec la portée, nous devrions faire la lumière sur la façon dont l'initialisation de l'objet est réellement effectuée.

Lorsque nous avons découvert les objets pour la première fois, nous avons expérimenté les chaînes. À l'époque, Strings offrait une belle transition par rapport aux types primitifs et servait d'excellente introduction aux méthodes.

Cependant, les chaînes sont de mauvais exemples d'objets car elles empruntent la syntaxe de type primitif pour l'initialisation des variables. Par exemple :

int batCount = 7;
String batName = "Wayne";

Dans cet exemple, nous voyons que nous pouvons créer un objet String de la même manière que nous pouvons créer un entier. La syntaxe est type name = value .

Pendant ce temps, les objets sont généralement définis en utilisant le new opérateur. Par exemple :

String batName = new String("Wayne");

Dans cet extrait, nous avons créé la même variable de chaîne en utilisant une syntaxe légèrement différente. Cependant, pour les chaînes, cette syntaxe peut devenir assez lourde.

Par exemple, disons que nous voulions imprimer un message d'erreur détaillé - une phrase devrait suffire. La première syntaxe nous permet de supprimer une partie du code passe-partout pour rendre la ligne plus lisible. Alors que la deuxième syntaxe est tout à fait valide, nous ne verrons probablement que la syntaxe abrégée dans le code source réel.

Revenons en arrière une seconde. Le new L'opérateur que nous venons de mentionner est exactement la façon dont chaque objet sera initialisé à l'avenir. En fait, nous allons bientôt passer en revue une classe d'exemple où nous pouvons créer une instance d'un point en utilisant la syntaxe suivante :

Point2D point = new Point2D(5, 7);

Maintenant que nous avons couvert les bases, plongeons-y !

Collecte des ordures

En plus de la portée et de l'initialisation des objets, nous devrions aborder brièvement la récupération de la mémoire . Lorsque nous déclarons un nouvel objet, une référence à cet objet est placée sur la pile. L'objet lui-même est placé dans un emplacement de mémoire différent appelé le tas.

Tant que l'objet est dans la portée, nous sommes libres de manipuler l'objet selon les besoins via sa référence. Une fois que nous en avons fini avec l'objet, le Garbage Collector le détruit.

À ce stade, nous ne pouvons plus accéder à notre objet. Cependant, tant que nous maintenons au moins une référence à l'objet, le Garbage Collector laissera notre objet seul.

La récupération de place est un excellent avantage du développement Java car elle nous permet de nous concentrer sur les concepts et les algorithmes plutôt que sur les détails d'implémentation. Cependant, toutes les langues ne sont pas équipées d'un Garbage Collector.

En C++, les objets doivent être nettoyés manuellement. Cela signifie que l'objet doit être supprimé via le code avant que la dernière référence à l'objet ne sorte de la portée. Sinon, l'objet continue à contenir de l'espace en mémoire, également connu sous le nom de fuite de mémoire et voici un exemple de ce qu'ils peuvent faire.

Au fil du temps, les fuites de mémoire peuvent entraîner une réduction de l'offre globale de mémoire. Dans le pire des cas, la fuite de mémoire peut ralentir le programme et finalement le bloquer ou le planter.

Surcharge

Dans un tutoriel précédent, nous avons brièvement parlé de la surcharge de méthodes qui nous permettait d'avoir plusieurs méthodes avec le même nom mais des ensembles de paramètres différents. Il s'avère que la surcharge s'étend au-delà des méthodes. En fait, c'est quelque chose que nous pouvons même faire avec les constructeurs, nous en reparlerons plus tard.

Exemple de structure de classe Hello World

Si vous n'êtes pas familier avec Hello World, cela implique généralement d'imprimer la phrase "Hello, World!" à la console. Il est largement utilisé comme moyen d'introduire un langage car il est simple à mettre en œuvre. En fait, j'ai lancé toute une série intitulée Hello World in Every Language où vous pouvez voir de nombreux exemples de ce programme en action.

Dans des langages comme C et Python, nous pouvons réaliser Hello World en quelques lignes seulement. Cependant, en Java, cela nécessite pas mal de connaissances de base. Si nous avions choisi d'introduire Java de cette manière, nous aurions probablement effrayé beaucoup de nouveaux développeurs. Mais en tout cas, commençons !

En Java, Hello World nécessite une connaissance de base de la structure des classes, de la méthode principale, des méthodes statiques, des tableaux et des chaînes. L'extrait de code suivant est l'implémentation Java de Hello World. Voyez si vous pouvez comprendre comment cela fonctionne en vous basant sur ce que vous savez déjà.

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Maintenant que nous avons vu le programme, décortiquons-le un peu.

La déclaration imprimée

En partant de la portée la plus interne, nous remarquerons la ligne de code suivante :

System.out.println("Hello, World!");

Dans cette ligne, nous avons une méthode appelée println qui prend une chaîne en entrée. On peut probablement imaginer que println imprime une ligne en utilisant l'entrée.

Pour les besoins de cette leçon, System.out récupère la console pour l'impression. Par conséquent, la ligne 3 doit imprimer notre chaîne attendue sur la console.

La méthode principale

Ensuite, jetons un coup d'œil à la méthode d'emballage de notre instruction d'impression :

public static void main(String[] args) {
    // ...
}

En Java, la méthode main sert de point d'entrée à un programme. Nous pouvons spécifier tout le comportement d'une classe, mais cela n'accomplira rien tant que nous n'aurons pas inclus une méthode principale. Sinon, le programme générera une erreur lors de l'exécution.

Si nous regardons attentivement, nous remarquerons que la méthode principale est statique, ce qui signifie que la méthode appartient à la classe et non à une instance de la classe. En d'autres termes, nous pouvons exécuter ce programme en utilisant HelloWorld.main(…) . Entre parenthèses, nous spécifierions une entrée qui correspond au type attendu.

On pourrait penser qu'on pourrait passer un String en tant qu'entrée, mais nous ne pouvons pas. C'est parce que l'entrée attend un tableau de chaînes (notez les crochets, [] ). Nous n'allons pas nous soucier des tableaux pour l'instant.

Au lieu de cela, revoyons cette idée d'appeler la méthode principale en utilisant un appel de méthode statique normal. En règle générale, nous ne pouvons pas exécuter un programme comme celui-ci en dehors de DrJava. C'est parce que le volet des interactions de DrJava est essentiellement une méthode principale vivante.

Lorsque nous ajoutons des lignes au volet des interactions, le volet des interactions sélectionne ces lignes et les exécute. C'est très pratique pour apprendre, mais cela cache le fonctionnement réel de Java.

En réalité, un programme Java exécutable doit contenir une et une seule méthode principale. Cela indique à la machine virtuelle Java où commencer à exécuter le code.

La déclaration de classe

La dernière information dont nous avons besoin pour créer notre propre classe est le bloc le plus externe :

public class HelloWorld {
    // ...
}

Remarquez comment il enveloppe tout dans la classe avec deux crochets et déclare la classe comme suit :

  1. public :indique le modificateur d'accès pour la classe (le même que les méthodes)
  2. class :déclare que le bloc de code est une classe
  3. HelloWorld :spécifie le nom de la classe

Cette structure de classe est exactement la façon dont nous créerions notre propre classe. En fait, pour le prouver, nous allons essayer de créer notre propre Point classe ci-dessous.

Comme petite note sur le style, soyez conscient de l'indentation, des points-virgules, des parenthèses et des accolades. Notez leur emplacement et leur format. Java nous permettra d'écrire un programme entier sur une seule ligne, mais cela ne nous sera d'aucune utilité, ni à quiconque travaille avec notre code. À l'avenir, nous discuterons plus profondément du style. Pour l'instant, suivez les extraits de code comme guide.

Comment exécuter Hello World

Avant que nous ayons de bons IDE pour écrire et exécuter du code, nous avions des éditeurs de texte et des interfaces de ligne de commande. La bonne chose à propos d'une interface de ligne de commande est qu'elle nous donne généralement une meilleure idée de la façon dont notre code est exécuté. Par exemple, nous pouvons exécuter notre fichier HelloWorld.java en utilisant la syntaxe de ligne de commande suivante :

javac HelloWorld.java 
java HelloWorld

À l'aide d'une interface de ligne de commande, nous pouvons naviguer vers le répertoire contenant notre code. Ensuite, nous pouvons exécuter le morceau de code ci-dessus. Si tout se passe bien, la console devrait afficher "Hello, World !".

Compilation

Cela peut sembler un peu bizarre qu'il faille deux commandes pour exécuter notre programme. Il s'avère qu'il existe une étape intermédiaire entre le codage et l'exécution appelée compilation :

javac HelloWorld.java

La compilation est l'acte de convertir le code source en quelque chose de plus utile à l'ordinateur. Pour Java en particulier, la compilation consiste à convertir le code source en bytecode qui peut ensuite être transmis à la machine virtuelle Java pour exécution.

Le fonctionnement de la compilation sort un peu du cadre de cette leçon, mais voici quelques étapes de base.

Le compilateur :

  1. Vérifie que le code source a la bonne syntaxe
  2. Assure que tous les types de variables sont alignés
  3. Convertit le code source en bytecode

Bien sûr, les étapes sont plus compliquées que cela. Par exemple, le compilateur effectuera souvent certaines optimisations pour que le programme s'exécute plus rapidement ou utilise moins d'espace. Encore une fois, tout cela sort un peu du cadre de cette leçon.

Exécution

La plupart des IDE comme DrJava masquent les commandes de compilation et d'exécution avec des boutons. Cependant, même au niveau de la ligne de commande, la compilation et l'exécution sont assez abstraites.

En réalité, la compilation génère un fichier, HelloWorld , qui contient le bytecode Java. Le bytecode est une représentation intermédiaire du code d'origine. Par conséquent, il est beaucoup plus proche du processeur, mais il ne dispose pas d'informations sur l'architecture du processeur.

Une fois la compilation terminée, nous pouvons exécuter la solution :

java HelloWorld

À ce stade, la JVM est responsable de la conversion à la volée du bytecode en binaire spécifique au processeur.

Si nous rappelons notre première leçon, nous avons déclaré que la puissance de Java réside dans sa portabilité. C'est la vérité. Compilez un programme une fois, et nous pouvons l'exécuter presque n'importe où.

Utiliser un IDE

Si vous utilisez encore DrJava, continuez et copiez le code source de Hello World dans la fenêtre au-dessus du volet des interactions. Cette fenêtre est l'éditeur de code.

Accédez à la partie supérieure droite de la fenêtre et sélectionnez compiler. Une fois compilé, nous pouvons simplement appuyer sur Exécuter pour exécuter notre premier programme.

Si vous avez déjà migré vers un autre IDE comme Eclipse, vous êtes seul. Cependant, nous passerons probablement à Eclipse à l'avenir pour commencer à nous familiariser avec d'autres ensembles d'outils.

Maintenant que nous savons comment exécuter le programme, passons à un autre exemple.

Exemple de structure de classe Point2D

Avec Hello World à l'écart, essayons d'écrire quelque chose d'un peu plus compliqué. En fait, nous allons créer une classe pour modéliser un point en deux dimensions :

/**
 * The Point2D class represents a two dimensional point.
 */
public class Point2D {

  // The x value of the point
  private double x;

  // The y value of the point
  private double y;

  /**
   * The class constructor.
   */
  public Point2D(double x, double y) {
    this.x = x;
    this.y = y;
  }

  /**
   * Retreives the x value of this point.
   */
  public double getX() {
    return x;
  }

  /**
   * Retrieves the y value of this point.
   */
  public double getY() {
    return y;
  }
}

Prenez un moment pour regarder ce code. Sur la base de ce que nous avons couvert jusqu'à présent, nous devrions être en mesure de reconnaître la syntaxe de la classe. A l'intérieur de la classe, on devrait aussi pouvoir pointer les deux méthodes :getX() et getY() .

Nous pouvons probablement même comprendre ce que font ces méthodes simplement en jetant un coup d'œil aux commentaires. Cependant, il y a une section de code qui devrait nous paraître un peu nouvelle. Cette section de code s'appelle le constructeur.

Constructeurs

Dans les langages orientés objet, les objets sont créés à l'aide d'un constructeur. Un constructeur est une méthode spéciale qui partage le nom de la classe mais n'a pas le mot-clé de type de retour.

Généralement, les constructeurs sont utilisés pour attribuer un état initial à un objet. Par exemple, notre Point2D example a un constructeur qui prend les deux coordonnées et les affecte à notre nouveau Point2D instance :

public Point2D(double x, double y) {
    this.x = x;
    this.y = y;
}

Nous pouvons tester cela en créant notre propre Point2D objet comme avant :

Point2D p1 = new Point2D(5, 7);

Cela crée un point où l'abscisse est 5 et l'ordonnée est 7. Pour le prouver, nous pouvons vérifier les valeurs de x et y champs—nous y reviendrons sous peu.

Pour un défi supplémentaire, essayez d'ajouter plus de comportements à Point2D un peu comme nous l'avons fait avec le fichier HelloWorld.java. Par exemple, il peut être judicieux d'ajouter une méthode d'instance à Point2D qui calcule la distance entre lui-même et un autre point :

p1.distanceTo(p2);

Si vous rencontrez des difficultés, n'hésitez pas à utiliser les commentaires ci-dessous pour poser des questions.

Champs

Ci-dessus, nous avons brièvement mentionné que le constructeur stocke ses entrées dans les champs de classe, mais que sont exactement les champs ?

Un champ est membre d'une classe un peu comme une variable locale est membre d'une méthode. En termes de Point2D , nous avons deux champs principaux :

private double x;
private double y;

Ces champs servent de coordonnées pour la classe et nous interagissons avec ces champs via des méthodes d'instance.

Lorsqu'un Point2D est créé à l'aide du constructeur, ces deux champs sont renseignés. Ensuite, nous pouvons accéder à ces champs en utilisant le getX() et getY() méthodes. Ces méthodes sont appelées getters, également appelées accesseurs, et nous les aborderons ensuite.

Accepteurs

Maintenant que nous sommes familiarisés avec les constructeurs et les champs, parlons getters .

Tant que les champs sont public , nous pouvons y accéder directement. Par exemple, supposons que nous voulions connaître la valeur de l'abscisse du point suivant :

Point2D point = new Point2D(1, 2);

Nous pourrions essayer d'appeler le point.x où x est le nom du champ de coordonnées x. Cependant, cela échoue car x est un private champ. En d'autres termes, nous avons choisi de masquer x par souci d'encapsulation (plus d'informations à ce sujet dans le futur).

Au lieu de cela, nous pouvons utiliser le public méthode getter, getX() , ce qui nous permet d'accéder indirectement au private x champ. C'est la manière normale d'exposer un champ pour lecture à un utilisateur. Nous appelons ces types de méthodes getters.

Setters

Pouvoir lire un champ privé c'est bien, mais parfois on aimerait changer de champ privé. Pour ce faire, nous utilisons ce qu'on appelle un setter .

Actuellement, notre Point2D les instances sont en lecture seule, ce qui signifie que nous n'avons aucun mécanisme pour modifier les coordonnées. Par conséquent, nous sommes obligés de créer un nouveau point chaque fois que nous voulons de nouvelles coordonnées.

Alternativement, nous pourrions créer ce que l'on appelle une méthode de définition publique pour exposer l'une des coordonnées à l'écriture. Nous pourrions le faire en utilisant la méthode suivante :

public void setX(int x) {
    this.x = x;
}

Les setters introduisent pas mal de nouvelles syntaxes. Tout d'abord, nous remarquerons que le type de retour est quelque chose que nous n'avons pas encore examiné. Notre setX() la méthode semble renvoyer void ce qui signifie en fait que nous ne retournons rien. C'est assez typique pour les méthodes qui n'ont pas besoin de retourner quoi que ce soit.

Ensuite, nous remarquerons que la méthode prend une entrée entière. Si nous voulons définir notre coordonnée x, nous aurons besoin d'une valeur de l'utilisateur.

Malheureusement, le bit déroutant est ce qui se passe dans le corps de la méthode :this.x = x . Nous semblons stocker x dans une variable appelée this.x . Si on s'en souvient, le this mot-clé fait référence à une instance de lui-même. En d'autres termes, this fait référence à l'instance courante du point. Ici, nous pouvons définir la valeur x du point sur la valeur de l'entrée x.

Nous aurions pu rendre le setter un peu plus explicite si nous avions écrit la méthode comme suit :

public void setX(int inputX) {
    x = inputX;
}

Ici, nous pouvons clairement voir que la valeur x de notre point est écrasée par le paramètre d'entrée. Quoi qu'il en soit, les deux méthodes accomplissent la même tâche.

Pour plus de clarté, il peut être préférable d'utiliser l'option deux. Cependant, la plupart des constructeurs et des setters utiliseront la première option. De nombreux IDE s'en chargeront pour nous, nous n'aurons donc pas trop à nous en soucier.

Entraînement supplémentaire

Maintenant, nous avons deux classes complètes créées :HelloWorld et Point2D .

Depuis Point2D ne peut pas être exécuté seul, essayez de créer une méthode main qui modifie quelques points avec des getters et des setters. Une fois que vous serez à l'aise avec cela, vous aurez une compréhension assez solide des cours dans l'ensemble.

Malheureusement, nous n'avons couvert que la surface même des classes à ce stade. À un moment donné, nous devrons couvrir les hiérarchies de classes, mais nous pourrons néanmoins naviguer dans une bonne partie du code.

Avec cette leçon sur les classes dans les livres, pourquoi ne pas revenir à l'API Strings. Nous devrions maintenant être beaucoup plus équipés pour parcourir la documentation. Jetez un œil à chaque section, comme les champs, les constructeurs et les méthodes.

De plus, notez l'utilisation intensive de la surcharge à la fois pour les constructeurs et les méthodes. N'oubliez pas de vérifier également la poignée de méthodes statiques.

Familiarisez-vous avec la présentation de l'API. À l'avenir, nous référencerons diverses bibliothèques Java en plus de Strings. Une fois arrivés aux boucles, nous commencerons probablement à utiliser le StringBuilder bibliothèque.

Ensuite, nous commencerons à nous attaquer au flux de contrôle. En attendant, merci d'avoir appris Java avec The Renegade Coder. Comme toujours, n'hésitez pas à nous contacter par e-mail ou par les commentaires ci-dessous. Si vous voulez rester à jour avec les derniers tutoriels, veuillez vous abonner. Jusqu'à la prochaine fois !


Balise Java