1. Propriétés : getters et setters

Lorsqu'un grand projet est développé par des dizaines de programmeurs en même temps, des problèmes surgissent souvent s'ils traitent différemment les données stockées dans les champs de classe.

Peut-être que les gens n'étudient pas la documentation de la classe en détail, ou peut-être qu'elle ne décrit pas tous les cas. En conséquence, il existe des situations fréquentes où les données internes d'un objet peuvent être "corrompues", rendant l'objet invalide.

Pour éviter ces situations, il est d'usage de rendre tous les champs de classe privés en Java . Seules les méthodes de la classe peuvent modifier les variables de la classe. Aucune méthode d'autres classes ne peut accéder directement aux variables.

Si vous voulez que d'autres classes puissent obtenir ou modifier les données à l'intérieur des objets de votre classe, vous devez ajouter deux méthodes à votre classe : une méthode get et une méthode set. Exemple:

Code Note
class Person
{
   private String name;

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

   public String getName()
   {
      return name;
   }

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


privatename field



Initialisation du champ via le constructeur


getName()— Cette méthode renvoie la valeur du champ name




setName()— Cette méthode modifie la valeur du champ name

Aucune autre classe ne peut modifier directement la valeur du champ de nom. Si quelqu'un a besoin d'obtenir la valeur du champ name, il devra appeler la getName() méthode sur un Personobjet. Si du code veut changer la valeur du champ name, il devra appeler la setName() méthode sur un Personobjet.

La getName()méthode est également appelée " getter pour le champ de nom " et la setName()méthode est appelée " setter pour le champ de nom ".

C'est une approche très courante. Dans 80 à 90 % de tout le code Java, vous ne verrez jamais de variables publiques dans une classe. Au lieu de cela, ils seront déclarés private(ou protected), et chaque variable aura des getters et des setters publics.

Cette approche rend le code plus long, mais plus fiable.

Accéder directement à une variable de classe revient à faire passer votre voiture par des doubles lignes jaunes : c'est plus facile et plus rapide, mais si tout le monde le fait, les choses empirent pour tout le monde.

Supposons que vous souhaitiez créer une classe décrivant un point ( x, y). Voici comment un programmeur novice procéderait :

class Point
{
   public int x;
   public int y;
}

Voici comment un programmeur Java expérimenté le ferait :

Code
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

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

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

Le code est-il plus long ? Indubitablement.

Mais vous pouvez ajouter la validation des paramètres aux getters et aux setters. Par exemple, vous pouvez vous assurer que xet ysont toujours supérieurs à zéro (ou non inférieurs à zéro). Exemple:

Code Note
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}


2. Durée de vie de l'objet

Vous savez déjà que les objets sont créés à l'aide de l' newopérateur, mais comment les objets sont-ils supprimés ? Ils n'existent pas éternellement. Il n'y a pas assez de mémoire pour cela.

Dans de nombreux langages de programmation, tels que C++, il existe un deleteopérateur spécial pour supprimer des objets. Mais comment cela fonctionne-t-il en Java ?

En Java, tout est arrangé un peu différemment. Java n'a pas d'opérateur de suppression. Cela signifie-t-il que les objets ne sont pas supprimés en Java ? Non, ils sont supprimés, bien sûr. Sinon, les applications Java manqueraient rapidement de mémoire et il ne serait pas question de programmes fonctionnant sans interruption pendant des mois.

En Java, la suppression d'objets est complètement automatisée. La machine Java gère elle-même la suppression des objets. Ce processus est appelé ramasse-miettes, et le mécanisme qui collecte les ordures s'appelle le ramasse-miettes ( GC ).

Alors, comment la machine Java sait-elle quand supprimer un objet ?

Le ramasse-miettes divise tous les objets en "accessibles" et "inaccessibles". S'il existe au moins une référence à un objet, il est considéré comme accessible. S'il n'y a pas de variable faisant référence à un objet, l'objet est considéré comme inaccessible et est déclaré poubelle, ce qui signifie qu'il peut être supprimé.

En Java, vous ne pouvez pas créer de référence à un objet existant — vous ne pouvez attribuer que des références que vous avez déjà. Si nous effaçons toutes les références à un objet, alors il est perdu à jamais.

Références circulaires

Cette logique sonne bien jusqu'à ce que nous tombions sur un contre-exemple simple : supposons que nous ayons deux objets qui se référencent (stockent des références l'un à l'autre). Aucun autre objet ne stocke de références à ces objets.

Ces objets ne sont pas accessibles depuis le code, mais ils sont toujours référencés.

C'est pourquoi le ramasse-miettes divise les objets en accessibles et inaccessibles plutôt qu'en "référencés" et "non référencés".

Objets accessibles

Tout d'abord, les objets qui sont 100% actifs sont ajoutés à la liste accessible. Par exemple, le thread actuel ( Thread.current()) ou la console InputStream ( System.in).

Ensuite, la liste des objets accessibles s'étend pour inclure les objets qui sont référencés par l'ensemble initial d'objets accessibles. Ensuite, il est à nouveau développé pour inclure les objets référencés par cet ensemble élargi, et ainsi de suite.

Cela signifie que s'il y a des objets qui se réfèrent uniquement les uns aux autres, mais qu'il n'y a aucun moyen de les atteindre à partir d'objets accessibles, alors ces objets seront considérés comme des ordures et seront supprimés.


3. Collecte des ordures

Fragmentation de la mémoire

Un autre point important lié à la suppression d'objets est la fragmentation de la mémoire. Si vous créez et supprimez constamment des objets, la mémoire sera bientôt fortement fragmentée : les zones de mémoire occupées seront entrecoupées de zones de mémoire inoccupées.

En conséquence, nous pouvons facilement nous retrouver dans une situation où nous ne pouvons pas créer un objet volumineux (par exemple, un tableau avec un million d'éléments), car il n'y a pas beaucoup de mémoire libre. En d'autres termes, il peut y avoir de la mémoire libre, même beaucoup, mais il peut ne pas y avoir un grand bloc contigu de mémoire libre

Optimisation de la mémoire (défragmentation)

La machine Java résout ce problème d'une manière spécifique. Cela ressemble à ceci :

La mémoire est divisée en deux parties. Tous les objets sont créés (et supprimés) dans seulement la moitié de la mémoire. Lorsque vient le temps de nettoyer les trous dans la mémoire, tous les objets de la première moitié sont copiés dans la seconde moitié. Mais ils sont copiés les uns à côté des autres afin qu'il n'y ait pas de trous.

Le processus ressemble à peu près à ceci :

Étape 1 : après avoir créé des objets

Ramassage des ordures en Java

Étape 2 : Apparition de "trous"

Garbage collection en Java 2

Étape 3 : Élimination des "trous"

Garbage collection en Java 3

Et c'est pourquoi vous n'avez pas besoin de supprimer des objets. La machine Java copie simplement tous les objets accessibles vers un nouvel emplacement et libère toute la zone de mémoire où les objets étaient stockés.