Académique Documents
Professionnel Documents
Culture Documents
Paix-Travail-Patrie Peace-Work-Fatherland
---------------------- ----------------------
Université de Yaoundé I University of Yaounde I
Sapentia-Collativia-Cognito Sapentia–Collativia–Cognito
---------------------- ----------------------
École Nationale Supérieure National Advanced
Polytechnique de Yaoundé School of Engineering
---------------------- ----------------------
Département du Génie Civil Department of Civil Engineering
3GC
REMERCIEMENTS
Au terme de ce travail, nous tenons à exprimer notre profonde gratitude envers tous
ceux qui ont participé au bon déroulement de cet exposé. Nos remerciements vont
particulièrement :
RAOUL ;
Pour conclure, nous souhaitons adresser nos remerciements à nos parents, amis, et
camarades de la filière Génie civil et urbanisme et aussi tous ceux qui de près ou de
loin, ont contribué à la réalisation de ce travail.
RESUMÉ
ABSTRACT
Data structures are a very important programming concept. They provide us with a
way to store, organize and retrieve data efficiently. Data structures are used to make working
with our data easier.
The journey of any beginner in programming starts with solving questions relating to
arrays which are used in all possible situations where one needs to collect objects in one
place. Whether it is simple or complex software or a web application, table is mainly used to
store and display data dynamically on web pages.
Data structures are essential for efficiently managing large amounts of data, such as
information stored in a database or indexing services. Proper management of a data system
requires the ability to identify allocated memory, data relationships, and data processes.
However, data structures facilitate these operations.
Furthermore, not only is it important to use data structures, but it is also essential to
choose the right structure for each task. Choosing a universal data structure could result in
slower processing times or unresponsive code. Several factors must be taken into account
when choosing a data structure: the type of information that will be stored, the storage
location of existing data, the method of storing the data, and the amount of memory to reserve
for data.
In a nut shell, we can therefore say that; by organizing the data in a certain way, we
enable automatic processing of the data more efficiently and quickly. Using a data structure
appropriate for computer processing can also significantly reduce the complexity of a
computer application and thus help to reduce the error rate. Hence the importance of data
structures in Java.
5
Exposé Informatique Et Programmation GCU 332 Rédigé Et Présenté Par :
Génie Civil Et Urbanisme : Promotion 2026 Groupe D’exposé No 3
Structures De Données En Java
Liste Des Figures
Tableau 1: Valeurs Limitées Des Types Byte, Short, Int, Et Long ............................................. 25
Tableau 2 : Valeurs Limites Des Types Float Et Double............................................................ 31
Tableau 3 : Utilisation Des Caractères En Java ......................................................................... 34
Tableau 4: Classes D'implémentations ........................................................................................ 42
INTRODUCTION
Une structure de données est un format spécial destiné à organiser, traiter, extraire et
stocker des données. S'il existe plusieurs types de structures plus ou moins complexes, tous
visent à organiser les données pour répondre à un besoin précis, afin de pouvoir y accéder et
les traiter de façon appropriée. Alors, la compréhension et le choix approprié des structures de
données sont essentiels pour garantir l'efficacité et la performance du système. En fonction
des besoins spécifiques du projet, il est important de choisir la structure de données la plus
adaptée pour optimiser les opérations de stockage et de manipulation des données. Une bonne
conception des structures de données peut contribuer à améliorer la qualité du code, à réduire
la complexité algorithmique et à augmenter l'efficacité globale du système. L'essence des
structures de données réside dans leur capacité à organiser et à manipuler efficacement des
données pour répondre aux besoins spécifiques d'une application ou d'un système
informatique. Les structures de données permettent de stocker des informations de manière
structurée, facilitant ainsi l'accès, la recherche, la modification et la suppression des données.
Les structures de données jouent un rôle crucial dans la résolution de problèmes informatiques
complexes en fournissant des moyens efficaces pour représenter et traiter les données. Elles
permettent aux programmeurs de choisir la structure la plus adaptée en fonction des
opérations à effectuer sur les données, de l'espace mémoire disponible et des contraintes de
performance. De ce fait, dans cet exposé, nous avons présenté dans l'ordre chronologique. La
présentation des différentes structures de donnés en Java, le choix approprié de la structure de
données selon les besoins spécifiques pour l'obtention d'une solution optimale des problèmes
rencontrés. Tout en nous apesantissant sur de nombreux cas pratiques.
_ Caractère : Ensemble des valeurs Unicode (valeurs de '\u0000' à '\uffff avec 4 chiffres
obligatoires après '\u' ) les 128 premiers caractères sont des codes ASCII et se notent entre
apostrophe: 'a', 'l', '\', '\n'.
_ Les types entiers : Les différents types entiers se distingue par la taille de leur
représentation.
_ Les conversions :
Un tableau est une structure de données qui stocke des éléments du même type. On peut le
considérer comme un ensemble de cellules numérotées dans lequel on peut mettre des
données dans chaque cellule (un élément de données par cellule). Le numéro d'un élément
dans le tableau est également appelé Index. En Java, un tableau est homogène c'est-à-dire que
toutes les cellules contiennent des éléments de même type. Ainsi un tableau d'entier ne
contient que des entiers (Int). Un tableau d'instances de chaine uniquement des chaines, un
tableau d'instances d'une classe dog que nous avons créée ne contiendra que des objets dog.
En d'autres termes, Java ne nous laissera pas mettre un entier dans la première cellule du
tableau et une chaine dans la seconde cellule.
Les tableaux en Java offrent plusieurs méthodes pour accéder et manipuler les éléments du
tableau, telles que l‟accès direct à un élément en utilisant son index, la boucle for pour
parcourir tous les éléments du tableau, et les méthodes de la classe Arrays pour effectuer des
opérations sur les tableaux.
Il est important de noter que les tableaux ont une taille fixe lors de leur création et ne peuvent
pas être redimensionnés. Si vous avez besoin d'une structure de données dynamique en Java,
vous pouvez utiliser des collections comme ArrayList.
Les collections sont des objets qui permettent de gérer des ensembles d'objets. Ces ensembles
de données peuvent être définis avec plusieurs caractéristiques : la possibilité de gérer des
doublons, de gérer un ordre de tri etc...
Une collection est un regroupement d'objets qui sont désignés sous le nom d'éléments.
L'API Collections propose un ensemble d'interfaces et de classe dont le but est de stocker de
multiples objets. Elle propose quatre grandes familles de collections, chacune définie par une
interface de base :
_List : collections d'éléments ordonnés qui accepte les doublons. Les implémentations les
plus courantes sont ArrayList et LinkedList
_ Set : collection d'éléments non ordonnés par défaut qui n'accepte pas les doublons. Les
implémentations les plus courantes sont HashSet, TreeSet et LinkedHashSet.
_Map : collection sous la forme d'une association de pair clé/valeur. Les implémentations les
plus courantes sont HashMap, TreeMap et LinkedHashMap.
_Queue et Deque : collections qui stockent des éléments dans un certain ordre avant qu'ils ²
En Java les structures de données non linéaires sont des collections d'objets qui ne sont pas
organisées de manière linéaire c'est-à-dire qu'elles ne suivent pas un ordre séquentiel comme
les tableaux e les lists mais plutôt un ordre trié. Pour cela, les éléments peuvent être attachés à
plus d'un élément présentant une relation hiérarchique. Dans une structure de données non
linéaire, le parcours de données et l'insertion ou la suppression ne sont pas effectuées de
manière séquentielle. Les structures de données les plus courantes en Java incluent :
_Graphes : Les graphes en Java sont des structures de données composées de sommets (ou
nœuds) reliés par des arêtes. Les graphes peuvent être dirigés (avec des arêtes orientées) ou
non dirigés (sans orientation).
Un graphe orienté
_Arbres : Les arbres en Java sont des structures de données hiérarchiques composées de
nœuds connectés les uns aux autres par des arêtes. Chaque nœud peut avoir un ou plusieurs
enfants, formant ainsi une structure arborescente.
Une Hashtable est une structure de données où les données sont stockées sous forme
de tableau. Chaque valeur de données à une valeur de clé unique. Si la clé est connue, tu peux
accéder aux données souhaitées très rapidement. Ainsi, les opérations d'insertion et de
recherche sont rapides et indépendantes de la taille des données.
Une table de hachage se compose d'un tableau pour conserver des données et d'une
fonction de hachage pour générer l'index où un élément doit être stocké.
En Java, il s'agit d'une règle qui mappe un objet sur un jeu de caractères (un code de
hachage). Habituellement, ce genre de fonction convertit un gros morceau de données en une
petite valeur entière. Les fonctions de hachage peuvent être variées, mais elles respectent
toutes certaines propriétés :
Classes et Objets
Une classe est un plan ou un prototype défini par l‟utilisateur à partir duquel des
objets sont créés. Il représente l‟ensemble des propriétés ou méthodes communes à tous les
objets d‟un type.
Un Objet est une unité de base de la programmation orientée objet et représente les
entités de la vie réelle. Un programme Java typique crée de nombreux objets qui, comme vous
le savez, interagissent en appelant des méthodes. Un objet est composé de :
Un flux est une séquence de données qui peut être lue ou écrite de manière
séquentielle. Les flux traitent toujours les données de façon séquentielle.
Les flux d'entrée (input stream) et les flux de sortie (output stream)
Les flux de traitement de caractères et les flux de traitement d'octets
Java définit des flux pour lire ou écrire des données mais aussi des classes qui permettent
de faire des traitements sur les données du flux. Ces classes doivent être associées à un flux de
lecture ou d'écriture et sont considérées comme des filtres. Par exemple, il existe des filtres
qui permettent de mettre les données traitées dans un tampon (buffer) pour les traiter par lots.
En Java, un fichier est une unité de stockage persistante qui peut contenir des données
sous forme de bytes ou de caractères. Les fichiers peuvent être utilisés pour stocker des
informations de manière permanente sur le disque dur.
Pour travailler avec des fichiers en Java, on utilise les classes du package java.io telles
que File, FileReader, FileWriter, etc.
- Les opérations courantes sur les fichiers en Java incluent la création, la lecture, l'écriture,
la suppression, le déplacement et la modification des fichiers.
Un type enregistrement est un type de données complexe (ou composé) représente une
donnée, elle-même composée d‟un ensemble de données. Chaque élément de cet ensemble
possède un nom et un type de données spécifique, et il ne doit pas y avoir de doublons dans
les noms des éléments.
Les éléments d‟un enregistrement sont appelés champs (fields), attributs (attributes) ou
encore propriétés (properties). Contrairement, aux valeurs individuelles d‟un tableau, les
valeurs des champs d‟un enregistrement ne sont pas indépendantes les unes des autres.
Ensemble, ces valeurs sont une description d‟un objet concret ou abstrait du monde réel.
Un type enregistrement est défini à l‟aide d‟une classe, dans laquelle les variables
membres représentent les champs de l‟enregistrement. Les variables membres sont déclarées
au début de la classe juste après l‟accolade ouvrante. La déclaration d‟une variable membre
est similaire à celle d‟une variable locale, mais elle est précédée du modificateur public.
efficace, en offrant différentes façons d'accéder et de gérer ces données. En Java, les
structures de données peuvent être utilisées pour résoudre une grande variété de problèmes,
que ce soit pour stocker des collections d'objets, gérer des informations complexes, ou
optimiser les performances des algorithmes.
Stockage efficace : Elles occupent moins d'espace mémoire que les objets. En
conséquence, l'utilisation de structures de données primitives permet d'économiser de
la mémoire et d'améliorer les performances en réduisant la surcharge liée à la gestion
des objets.
Performances optimisées : Elles offrent des performances optimisées par rapport aux
objets. Étant donné que les structures de données primitives sont stockées sur la pile
(stack) plutôt que dans le tas (heap), leur accès et leur manipulation sont plus rapides.
De plus, les opérations arithmétiques sur les types primitifs sont généralement plus
rapides que sur les objets correspondants.
Facilité de manipulation : Elles sont simples à manipuler car elles représentent des
valeurs de base. Les opérations sur les structures de données primitives sont directes et
ne nécessitent pas de méthodes spéciales comme pour les objets. Cela facilite la
manipulation des données et rend le code plus concis.
Compatibilité avec les types primitifs : Elles sont compatibles avec les types
primitifs du langage, ce qui facilite l'interopérabilité avec d'autres bibliothèques et API
Java. Les structures de données primitives peuvent être utilisées dans des tableaux, des
collections et d'autres structures de données standard sans nécessiter de conversion
vers des objets.
Utilisation dans les algorithmes et les opérations mathématiques : Elles sont
largement utilisées dans les algorithmes et les opérations mathématiques pour stocker
des valeurs numériques, des caractères, des booléens, etc. Leur utilisation permet
d'optimiser les performances des algorithmes en évitant les coûts supplémentaires liés
à la gestion des objets.
Les tableaux
En Java, les tableaux sont des structures de données utilisées pour stocker une
collection d'éléments de même type. Voici quelques-uns des rôles des tableaux en Java :
Les collections
En Java, les collections sont des structures de données plus flexibles et dynamiques
que les tableaux, offrant une variété de fonctionnalités pour stocker et manipuler des
éléments. Voici quelques-uns des rôles des collections en Java :
Stockage dynamique : Contrairement aux tableaux dont la taille est fixe, les
collections en Java peuvent grandir et rétrécir dynamiquement en fonction des besoins.
Gestion de la mémoire : Les collections en Java gèrent automatiquement la mémoire,
ce qui simplifie la gestion des ressources et évite les problèmes de dépassement de
capacité.
Types de données variés : Les collections en Java offrent une gamme de types de
données prédéfinis tels que les listes, les ensembles, les cartes, etc., permettant de
stocker différents types d'éléments.
En Java, les structures de données linéaires telles que les piles (Stack) et les files (Queue)
jouent un rôle important dans le stockage et la manipulation des éléments de manière
séquentielle. Voici quelques-uns des rôles des piles et des files en Java :
1. Piles (Stack)
LIFO (Last In First Out) : Les piles suivent le principe du dernier élément ajouté est le
premier à être retiré, ce qui les rend utiles pour des opérations telles que l'annulation (undo)
ou le suivi d'un historique.
Gestion de la pile d'appels : Les piles sont utilisées pour gérer les appels de fonctions
récursives ou les appels de méthodes dans la programmation orientée objet.
Évaluation d'expressions : Les piles sont utilisées pour évaluer des expressions
arithmétiques ou logiques en utilisant des algorithmes tels que l'algorithme de conversion en
notation polonaise inversée (RPN).
2. Files (Queue) :
FIFO (First In First Out) : Les files suivent le principe du premier élément ajouté est le
premier à être retiré, ce qui les rend utiles pour des opérations telles que la gestion des tâches
en attente ou la gestion des requêtes réseau.
Gestion des processus : Les files sont utilisées pour gérer les processus en attente
d'exécution, tels que l'ordonnancement des tâches dans un système d'exploitation.
En Java, les structures de données non linéaires telles que les arbres et les graphes jouent
un rôle crucial dans de nombreuses applications informatiques. Voici quelques-uns des rôles
des structures de données non linéaires en Java :
1. Arbres
- Représentation hiérarchique : Les arbres sont utilisés pour représenter des structures
hiérarchiques telles que les arbres généalogiques, les structures de dossiers et fichiers, les
arbres de décision, etc.
- Arbres binaires de recherche : Les arbres binaires de recherche sont utilisés pour stocker et
rechercher des données de manière efficace, en garantissant un temps de recherche
logarithmique.
- Arbres d'expressions : Les arbres d'expressions sont utilisés pour représenter des
expressions arithmétiques ou logiques de manière structurée, ce qui facilite leur évaluation et
leur manipulation.
2. Graphes
Modélisation des relations : Les graphes sont utilisés pour modéliser des relations
complexes entre des entités, telles que les réseaux sociaux, les réseaux de transport, les
réseaux informatiques, etc.
Algorithmes de parcours : Les graphes sont utilisés pour implémenter des algorithmes de
parcours tels que la recherche en profondeur (Depth First Search) et la recherche en largeur
(Breadth First Search), qui sont essentiels pour résoudre de nombreux problèmes liés aux
graphes.
Exposé Informatique Et Programmation GCU 332 Rédigé Et Présenté Par : 20
Algorithmes de plus court chemin : Les graphes sont utilisés pour résoudre des problèmes
de recherche du plus court chemin, tels que l'algorithme de Dijkstra ou l'algorithme de
Bellman-Ford, qui sont largement utilisés dans la planification des itinéraires, la logistique,
etc.
En Java, les structures de données de hachage jouent un rôle essentiel dans de nombreuses
applications informatiques en raison de leur efficacité en termes de recherche, d'insertion et de
suppression d'éléments. Voici quelques-uns des rôles des structures de données de hachage en
Java :
En Java, les classes et les objets jouent un rôle fondamental dans la programmation
orientée objet. Voici quelques-uns des rôles importants des classes et des objets en Java :
En Java, les flux et les fichiers jouent un rôle essentiel dans la manipulation des données
entrantes et sortantes, ainsi que dans le stockage et la lecture de données sur des supports de
stockage persistants tels que des fichiers. Voici quelques-uns des rôles importants des flux et
des fichiers en Java :
Exposé Informatique Et Programmation GCU 332 Rédigé Et Présenté Par : 22
Lecture et écriture de données : Les flux en Java permettent de lire des données à
partir de sources telles que des fichiers, des entrées utilisateur, des connexions réseau,
etc., et d'écrire des données vers des destinations telles que des fichiers, des sorties
système, des connexions réseau, etc. Les flux offrent une interface unifiée pour la
lecture et l'écriture de données de manière séquentielle.
Manipulation de fichiers : Les classes de gestion de fichiers en Java (comme File,
FileInputStream, FileOutputStream, FileReader, FileWriter, etc.) permettent de créer,
supprimer, renommer, copier, déplacer et inspecter des fichiers et des répertoires sur le
système de fichiers local. Elles offrent des fonctionnalités pour interagir avec les
fichiers et les répertoires de manière programmatique.
Persistance des données : Les fichiers en Java sont couramment utilisés pour stocker
des données de manière persistante sur le disque dur ou tout autre support de stockage.
Les applications Java peuvent lire et écrire des données dans des fichiers pour
sauvegarder des informations entre les exécutions du programme, partager des
données entre différentes parties de l'application ou échanger des données avec
d'autres applications.
Traitement de flux : Les flux en Java offrent une manière flexible et efficace de
traiter les données en transit. Les développeurs peuvent chaîner plusieurs flux
ensemble pour effectuer des opérations de transformation, de filtrage, de compression
ou de cryptage sur les données en transit. Cela permet de manipuler efficacement les
données sans avoir à les stocker entièrement en mémoire.
Communication réseau : Les flux en Java sont largement utilisés pour la
communication réseau via les sockets. Les développeurs peuvent créer des flux
d'entrée et de sortie pour envoyer et recevoir des données sur un réseau, ce qui facilite
le développement d'applications client-serveur, d'applications Web et d'autres
systèmes distribués.
Les enregistrements
En Java, les enregistrements sont une fonctionnalité introduite dans la version 16 de Java,
qui permet de définir des classes légères et immuables pour représenter des données de
manière concise et efficace. Voici quelques-uns des rôles importants des enregistrements en
Java :
long 8 -9 223 372 036 854 775 808 9 223 372 036 854 775 807
Pour transférer la valeur d'une variable entière dans une autre variable entière, il y a deux
possibilités :
Soit la taille de la variable dans laquelle on affecte est plus grande (ou égale) à la taille
de la variable initiale, et dans ce cas, le changement de type est implicitement autorisé.
Soit la taille de la variable dans laquelle on affecte est plus petite à la taille de la
variable initiale, et dans ce cas il peut y avoir une perte de précisions lors de
l'affectation. Du coup le changement de type devra être explicitement acté via un
Java permet d'utiliser plusieurs bases numériques pour exprimer vos valeurs entières. Il y
en a trois qui sont reprises du langage C : base octale, base décimale et base hexadécimale.
Depuis Java SE 7.0, une quatrième base, la base binaire, a été rajoutée au langage.
La base binaire : elle ne supporte que deux chiffres, le 0 et le 1. Pour exprimer une
valeur en base binaire, il est nécessaire de préfixer votre valeur par 0b.
La base octale : comme son nom l'indique, cette base numérique contient 8 chiffres
(de 0 à 7). Les chiffres 8 et 9 sont donc non autorisés : si vous les utilisez, une erreur
de compilation sera produite. Pour exprimer une valeur en base octale, il est nécessaire
de préfixer votre valeur par 0.
La base décimale : bien entendu dix chiffres de 0 à 9. Que dire de plus ....
La base hexadécimale : 16 chiffres de 0 à 9 puis de A à F. Cette base numérique est
très intéressante dans certains cas : communication avec un matériel électronique,
codification de couleurs ARGB, ...
Groupage de chiffres
Depuis Java SE 7.0, il est possible d'utiliser le caractère _ pour grouper les digits (les
chiffres) d'une valeur numérique. On peut aussi grouper les chiffres par blocs de taille
quelconque. On n'est même pas obligé de définir de groupes de tailles identiques : cela peut,
par exemple, s'avérer très pratique avec l'utilisation du binaire dans le cadre de la
communication avec un matériel électronique.
Il est possible d'utiliser le groupage de chiffres, quelle que soit la base numérique
utilisées. Voici quelques exemples d'utilisations.
précédent. La valeur négative vient du faire que le type int est signé (le bit 32 étant fixé à 1, la
valeur est affichée négativement).
Si vous utilisez une version de Java inférieur à Java 7.0, le groupage ne sera pas
supporté. Une erreur de compilation sera produite.
Si vous avez le moindre doute sur la priorité d'évaluation de vos opérateurs, utilisez
les parenthèses pour forcer les priorités. Voici un exemple, mais j'insiste bien sur le fait qu'ici
ce n'est pas nécessaire.
Dépassement d’étendue
L'ajout de deux variables de type byte produit un entier typé int. La raison est qu'on
peut très facilement dépasser de l'étendue du type byte étant donné le peu de place occupé. Il
est donc nécessaire de transtyper le résultat en byte si c'est ce que vous souhaitez récupérer. Il
en va de même pour les autres opérateurs arithmétiques (soustraction, ...). Dans le même ordre
d'idée, l'addition de deux short produit aussi un résultat typé int. L'exemple ci-dessous vous
montre comment réaliser les transtypages (conversions vers le type souhaité).
Le langage Java défini, comme en C, deux sortes d'opérateurs de division : vous avez
la possibilité de faire des divisions entières ou des divisions flottantes. Dans l'exemple ci-
dessous, il n'y a aucun doute à avoir, on divise deux entiers et on demande à récupérer un
entier : la division sera donc entière.
Operateurs de comparaison
Vous pouvez aussi comparer vos entiers. Pour ce faire, six opérateurs-vous sont
proposés : l'égalité (opérateur ==), la différence (opérateur !=), l'infériorité (opérateur <=),
l'infériorité stricte (opérateur <), la supériorité (opérateur >=), la supériorité stricte (opérateur
>). Voici un exemple d'utilisation.
Les types flottants en Java ont une précision limitée en raison de la façon dont les
nombres réels sont représentés en mémoire. Cela peut entraîner des approximations et des
erreurs de calcul, en particulier lors de l‟utilisation de valeurs très grandes ou très petites. Il
est important pour les programmeurs de comprendre ces limitations et de prendre des
précautions lors de l‟utilisation de types flottants pour des calculs critiques.
Ce format stocke le signe sur un bit puis le nombre sous une forme entière (la
mantisse) et l‟exposant en base 2 pour positionner la virgule. Il existe en Java deux types
primitifs permettant de représenter des nombres flottants, à savoir float et double, dont voici
les valeurs limites :
Float est dit en simple précision et tandis que double est dit en double précision.
En règle générale, il est recommandé d‟utiliser le type double pour les calculs impliquant
des valeurs flottantes, car il offre une meilleure précision que le type float. Le type float peut
être utilisé dans des cas où l‟espace mémoire est limité ou lorsque la précision accrue du type
double n‟est pas nécessaire.
Bien entendu, vous avez le droit d'utiliser des opérateurs pour réaliser les opérations
arithmétiques classiques : l'addition (opérateur +), la soustraction (opérateur -), la
multiplication (opérateur *) et la division flottante (opérateur /). Voici un petit exemple
d'utilisation de certains de ces opérateurs.
Operations comparaisons
Vous pouvez aussi comparer vos flottants. Pour ce faire, six opérateurs-vous sont proposés :
l'égalité (opérateur ==), la différence (opérateur !=), l'infériorité (opérateur <=), l'infériorité
stricte (opérateur <), la supériorité (opérateur >=), la supériorité stricte (opérateur >). Voici
un exemple d'utilisation.
3. Les caractères
Unicode
Unicode est une spécification qui vise à lister tous les caractères utilisés par les
langues humaines et à donner à chaque caractère son propre code unique. Les spécifications
Unicode sont continuellement révisées et mises à jour pour ajouter de nouvelles langues et de
nouveaux symboles.
Le standard Unicode décrit comment les caractères sont représentés par les points de
code. Une valeur de point de code est un nombre entier compris entre 0 et 0x10FFFF (environ
1,1 million de valeurs possibles, le nombre de valeurs réellement assignées est inférieur à ce
nombre). Dans le standard, un point de code est écrit en utilisant la notation U+265E pour
désigner le caractère avec la valeur 0x265e (9 822 en décimal).
En Java, les caractères sont représentés par le type primitif char, qui peut stocker un
seul caractère Unicode. Ce type de données est codé sur 16 bits et peut donc représenter des
caractères Unicode allant de U+0000 à U+FFFF. Il existe également d‟autres types de
données pour représenter des chaînes de caractères, telles que String, qui est une séquence de
caractères.
4. Le type booléen
Le type booléen est fondamental en programmation car il permet de représenter l‟état de
vérité dans les décisions et les conditions. Il ne peut prendre que deux valeurs : true ou false.
Les opérations logiques, les expressions conditionnelles et les structures de contrôle de flux
dépendent largement de ce type de données.
En Java, true et false sont des mots-clés réservés qui représentent les deux seules valeurs
possibles du type booléen : true est utilisé pour exprimer une condition vraie, tandis que false
est utilisé pour exprimer une condition fausse.
En interne, les valeurs booléennes sont stockées sous forme de bits dans la mémoire de
l‟ordinateur. Cependant, chaque valeur booléenne ne nécessite qu‟un seul bit pour être
stockée, où true peut être représenté par le bit 1 et false par le bit 0.
true peut être représenté par le bit 1 et false par le bit 0.
En Java, les variables booléennes sont déclarées en spécifiant le type booléen, suivi du
nom de la variable et éventuellement de sa valeur initiale. Voici la syntaxe générale pour
déclarer une variable booléenne : true peut être représenté par le bit 1 et false par le bit 0.
Opérations Logiques
En Java, les opérateurs logiques sont utilisés pour combiner ou modifier des valeurs
booléennes. Les opérateurs logiques les plus couramment utilisés sont l‟opérateur AND (&&),
l‟opérateur OR (||) et l‟opérateur NOT (!). Voici une brève explication de chaque opérateur :
Opérateur AND (&&) : Renvoie true si et seulement si les deux opérandes sont true,
sinon renvoie false.
Opérateur OR (||) : Renvoie true si au moins l‟un des opérandes est true, sinon renvoie
false.
Opérateur NOT (!) : Inverse la valeur de l‟opérande ; si l‟opérande est true, renvoie false,
et vice versa.
Expressions booléennes
En Java, une expression booléenne est une expression qui évalue à une valeur booléenne,
c‟est-à-dire soit true soit false. Ces expressions sont souvent utilisées dans des conditions, des
boucles et d‟autres situations où une évaluation logique est nécessaire.
Une expression booléenne peut être aussi simple qu‟une seule variable booléenne, ou aussi
complexe qu‟une combinaison d‟opérateurs logiques et de valeurs booléennes.
Comparaisons et Conditions
En Java, les valeurs booléennes sont souvent utilisées dans les comparaisons et les
conditions pour prendre des décisions en fonction de certaines conditions. Les opérateurs de
comparaison tels que ==,=, <, <=, >, >= permettent de comparer des valeurs et de produire des
résultats booléens.
Exemple d’utilisation des comparaisons dans des conditions :
En Java, les méthodes peuvent également retourner des valeurs booléennes. Cela signifie
qu‟une méthode peut effectuer une opération et renvoyer un résultat booléen, qui peut ensuite
être utilisé dans d‟autres parties du programme.
B. Les Tableaux
1. Les tableaux à une dimension
Déclaration et initialisation des tableaux
En Java, la déclaration d‟un tableau consiste à indiquer le type de données des
éléments qu‟il contiendra, suivi de son nom et des crochets [] pour indiquer qu‟il s‟agit d‟un
tableau. Voici un exemple simple de déclaration de tableau en Java :
Une fois déclaré, le tableau doit être initialisé avant de pouvoir y stocker des éléments. Il
existe plusieurs façons d‟initialiser un tableau en Java :
Ajout et Suppression d’Éléments : En Java, les tableaux ont une taille fixe une fois
qu‟ils sont créés. Cela signifie que vous ne pouvez pas ajouter ou supprimer
d‟éléments directement à partir d‟un tableau existant. Cependant, vous pouvez simuler
l‟ajout et la suppression en créant un nouveau tableau avec une taille différente et en
copiant les éléments de l‟ancien tableau. Voici un exemple :
Tri des Éléments : Le tri des éléments d‟un tableau est souvent nécessaire pour
organiser les données dans un ordre spécifique. En Java, vous pouvez trier les
éléments d‟un tableau en utilisant la méthode Arrays.sort(). Cette méthode trie les
éléments du tableau dans l‟ordre naturel de leurs valeurs. Voici un exemple :
Copie de Tableaux : Pour copier un tableau en Java, vous pouvez utiliser la méthode
Arrays.copyOf(). Cette méthode crée une nouvelle copie du tableau avec une taille
spécifiée. Voici un exemple :
En Java, un tableau à deux dimensions est stocké sous forme de lignes et de colonnes et
est représenté sous la forme d'une matrice.
Déclaration des tableaux bidimensionnels : la déclaration des tableaux peut se faire comme
suit :
Accès aux éléments du tableau : Pour accéder aux éléments d‟un tableau
multidimensionnel, on doit spécifier les indices de chaque dimension. Par exemple,
pour accéder à l‟élément à la première ligne et à la deuxième colonne d‟un tableau
bidimensionnel, vous pouvez utiliser :
C. Les Collections
Une collection : gère un groupe d'un ensemble d'objets d'un type donné ; ou bien c'est
un objet qui sert à stocker d'autres objets. Dans les premières versions de Java, les collections
étaient représentées par les "Array","Vector","Stack" etc. Puis avec Java 1.2 (Java 2), est
apparu le framWork de collections qui tout en gardant les principes de bases, il a apporté des
modifications dans la manière avec laquelle ces collections ont été réalisées et hiérarchisées.
Tout en collaborant entre elles, ces collections permettent de réaliser dans des catégories de
logiciels des conceptions réutilisables.
Interfaces
• Set : est ensemble ne contenant que des valeurs et ces valeurs ne sont pas dupliquées. Par
exemple l'ensemble A = {1,2,4,8}. Set hérite donc de Collection, mais n'autorise pas la
duplication. SortedSet est un Set trié.
• List : hérite aussi de collection, mais autorise la duplication. Dans cette interface, un
système d'indexation a été introduit pour permettre l'accès (rapide) aux éléments de la liste.
• Map : est un groupe de paires contenant une clé et une valeur associée à cette clé. Cette
interface n'hérite ni de Set ni de Collection. La raison est que Collection traite des données
simples alors que Map a des données composées (clé, valeur). SortedMap est un Map trié.
Implémentations
Classes d'implémentations
Par contre, il n'y a pas d'implémentation de l'interface Collection. Pour Set et Map
l'implémentation est soit sous la forme d'une table de hachage (HashSet/HashMap) ou bien
sous la forme d'un arbre (TreeSet/TreeMap). Pour la liste : soit sous la forme de tableau
(ArrayList) ou une liste chaînée (LinkedList).
Collection
Les interfaces contiennent des méthodes optionnelles. Cette approche permet de traiter
les collections particulières sans que nous soyons dans l'obligation de définir les méthodes
optionnelles. Ces méthodes optionnelles sont définies qu'en cas de besoin. Un Set non
modifiable n'a pas besoin de redéfinir la méthode add, puisque nous ne pouvons pas le
modifier !
Il y a des opérations réalisées sur un seul objet ou bien sur une collection (un ensemble
d'objets). Nous avons :
L'interface collection est dotée d'une instance d'une classe qui implante l'interface
Iterator. C'est l'outil utilisé pour parcourir une collection. L'interface Iterator contient ce qui
suit :
Exemple de code :
Collection collection = ... ;
Iterator iterator = collection.iterator(); while
(iterator.hasNext()) {
Object element = iterator.next();
if (removalCheck(element)) {
iterator.remove();
}
}
Les collections vues comme des ensembles réalisent les 3 opérations mathématiques
sur des ensembles :
Intersection : retainAll
Set
Exposé Informatique Et Programmation GCU 332 Rédigé Et Présenté Par : 44
Le set : est une interface identique à celle de Collection. Deux implémentations possibles :
Résultat du code
List
Liste est une collection ordonnée. Elle permet la duplication des éléments. L'interface
est renforcée par des méthodes permettant d'ajouter ou de retirer des éléments se trouvant à
une position donnée. Elle permet aussi de travailler sur des sous listes. On utilise le plus
souvent des ArrayList sauf s'il y a insertion d'élément(s) au milieu de la liste. Dans ce cas il
est préférable d'utiliser une LinkedList pour éviter ainsi les décalages.
// Positional Access
Object get(int index);
Object set(int index, Object element); // Optional
void add(int index, Object element); // Optional Object
remove(int index); // Optional boolean addAll(int
index, Collection c); // Optional
// Search int
indexOf(Object o); int
lastIndexOf(Object o);
// Iteration
ListIterator listIterator();
ListIterator listIterator(int index);
// Range-view
List subList(int fromIndex, int toIndex);
}
Les méthodes de l'interface List permettent d'agir sur un élément se trouvant à un index
donné ou bien un ensemble d'éléments à partir d'un index donné dans la liste.
- Code java
public interface ListIterator extends Iterator {
boolean hasNext();
Object next();
boolean hasPrevious();
Object previous();
int nextIndex();
int previousIndex();
void remove(); // Optional
void set(Object o); // Optional
void add(Object o); // Optional
}
Ceci permet donc de parcourir la liste dans les deux directions et de modifier un élément
(set) ou d'ajouter un nouvel élément.
- Code java
List list = ... ;
ListIterator iterator = list.listIterator(list.size()); while
(iterator.hasPrevious()) {
Object element = iterator.previous();
// traitement d'un élément
}
Voici un exemple de code complet pour la création des listes et la récupération des éléments
dans celle-ci.
Image 19: code de création d’une liste avec récupération d’élément
Map
Le Map : est un ensemble de paires, contenant une clé et une valeur (en réalité, nous
pouvons associer plusieurs valeurs. Dans ce cas-là, nous sommes en présence d'une
multimap).
L'interface interne Entry permet de manipuler les éléments d'une paire comme suit :
getKey & getValue : retournent respectivement la clé et la valeur associée à cette clé.
setValue : permet de modifier une valeur d'une paire. Remarque : faire attention de ne
pas modifier directement la valeur associée à une clé. Pour le faire, retirer l'ancienne
clé (et donc sa valeur aussi) et ajouter une nouvelle clé (avec cette nouvelle valeur).
- Exemple de code
public interface Map {
// Basic Operations
Object put(Object key, Object value);
Object get(Object key); Object
remove(Object key); boolean
containsKey(Object key); boolean
import java.util.*;
public class MapExample {
public static void main(String args[]) {
Map map = new HashMap();
Integer ONE = new Integer(1); for
(int i=0, n=args.length; i<n; i++) {
String key = args[i];
Integer frequency = (Integer)map.get(key);
if (frequency == null) {
frequency = ONE;
} else {
int value = frequency.intValue();
frequency = new Integer(value + 1);
}
map.put(key, frequency);
}
System.out.println(map);
Map sortedMap = new TreeMap(map);
System.out.println(sortedMap);
}
}
L'ensemble des algorithmes manipulant les collections se trouve dans la classe Collections
(à ne pas confondre avec l'interface Collection). Ces méthodes ont été définies statiques.
Trier :
Mélanger :
Manipuler :
Rechercher :
min (Collection)
max (Collection)
Interface Comparable
- Entier positif si l'objet qui fait l'appel est plus grand que obj,
- Zéro s'ils sont identiques,
- Négatif si l'objet qui fait l'appel est plus petit que obj.
Dans le cas d'une classe qui n'implante pas la classe Comparable, ou bien vous voulez
spécifier un autre ordre, vous devez implanter l'interface Comparator. Cette dernière permet
de comparer deux éléments de la collection. Pour trier, nous passons une instance de cette
classe à la méthode Sort ().
Pour le langage C++ il existe une bibliothèque appelée la STL (Standard Templates Library),
l'équivalent pour le langage java est la JGL (Generic Collections Library for Java) développée par
ObjectSpace. Vous pouvez la trouver à cette adresse :
http://www.objectspace.com/products/voyager/downloads.asp
L'utilisation de la JGL n'est pas conseillée vu sa complexité. Il est conseillé d'installer la
documentation associée. Il est à signaler que la JGL n'a pas été mise à jour depuis la version beta
de java 1.2 ; de ce fait, la version 1.2 de java n'est pas supportée.
1. Les Piles
Une pile est une structure de données linéaire basée sur le principe du dernier entré,
premier sorti (LIFO = Last In First Out). Imaginez un jeu de cartes ou une pile de livres dans
une boîte. Le livre que vous placez en premier dans la pile est en bas, et le premier que nous
sortirons de la boîte est le livre qui était en haut, c'est à-dire celui qui est entré en dernier dans
Exposé Informatique Et Programmation GCU 332 Rédigé Et Présenté Par : 52
Cette application est si importante pour la programmation que dans la plupart des processeurs,
la pile de retour est implémentée dans le matériel du jeu d'instructions.
• boolean empty() : la méthode vérifie si la pile est vide ou non. Renvoie vrai si la pile est
vide, faux sinon.
• Objet pop () : la méthode renvoie l'élément qui se trouve en haut de la pile et le supprime.
• Object push (objet element) : la méthode ajoute l'élément spécifié en haut de la pile.
• int search (Object element) : la méthode recherche dans la pile l'élément spécifié. Si
l'élément recherché est trouvé, sa « distance » par rapport au sommet (numéro de série) est
renvoyée. Si l'élément n'est pas trouvé, -1 est retourné.
Etant donné que Stack est hérité de vector Class et implémente l‟interface List, Stack, en
plus des opérations push et pop classiques pour cette structure de données pour l‟ajout de
l‟extraction d‟éléments, a également une norme pour les opérations add() et remove() de la
structure de liste.
- Code du programme
L'implémentation basée sur la baie est plus simple, plus efficace et plus économe en
mémoire, mais elle nécessite une connaissance préalable de la taille limite de la pile et peut
entraîner des bogues difficiles à trouver. L'implémentation basée sur des listes est plus robuste
mais moins efficace. Faisons une implémentation simple basée sur un tableau de la pile. Il
comprendra des fonctions.
• push : une méthode qui assurera l'ajout d'un élément (en position haute)
• pop : une méthode qui fournira la suppression d'un élément (de la position supérieure)
• readTop : une méthode qui renverra la valeur de l'élément qui est en position supérieure
• isFull : une méthode qui vérifiera si notre tableau dans lequel nous stockons la pile n'est pas
plein.
2. Les Files
Une file : est une autre structure de données courante. En plus des piles, de nombreux
langages de programmation, dont Java, implémentent également la structure de données de
file. Quelle est la différence entre une file et une pile ? Une file n'est pas basée sur le principe
LIFO, mais plutôt sur le principe FIFO ("premier entré, premier sorti"). Ce principe est facile
à comprendre en considérant, par exemple, une ligne ordinaire, ou file d'attente, dans la vraie
vie ! Par exemple, une ligne à l'épicerie. Le fonctionnement d'une file est très intuitif, car on
retrouve souvent des files d'attente dans la vraie vie. Il convient de noter séparément qu'en
Java, une file n'est pas représentée par « une classe, mais par une interface » : Queue. De
plus, il existe de nombreuses implémentations de cette interface de file d'attente en Java. Si
nous regardons la documentation d'Oracle, nous verrons que 4 interfaces différentes, ainsi
qu'une liste de classes extrêmement impressionnante, héritent de l'interface Queue. Les files
d'attente doubles sont largement utilisées dans le développement de logiciels.
Il peut y avoir n nombre de sous-arbres dans une arborescence générale. Dans l'arborescence
générale, les sous-arbres ne sont pas ordonnés car les nœuds du sous-arbre ne peuvent pas être
ordonnés.
Chaque arbre non vide possède un bord descendant, et ces bords sont connectés aux nœuds
appelés nœuds enfants. Le nœud racine porte le niveau 0. Les nœuds qui ont le même parent
sont appelés frères et sœurs.
*Arbre binaire : ici, le nom binaire lui-même suggère deux nombres, c'est-à-dire 0 et 1. Dans
un arbre binaire, chaque nœud d'un arbre peut avoir au maximum deux nœuds enfants. Ici,
maximum signifie si le nœud a 0 nœud, 1 nœud ou 2 nœuds.
*Arbre de recherche binaire : l'arbre de recherche binaire est une structure de données non
linéaire dans laquelle un nœud est connecté à n n nœuds. Il s'agit d'une structure de données
basée sur des nœuds. Un nœud peut être représenté dans un arbre de recherche binaire avec
trois champs, c'est-à-dire la partie données, l'enfant gauche et l'enfant droit. Un nœud peut être
connecté aux deux nœuds enfants les plus élevés dans un arbre de recherche binaire, de sorte
que le nœud contient deux pointeurs (enfant gauche et pointeur enfant droit).
Chaque nœud du sous-arbre de gauche doit contenir une valeur inférieure à la valeur du nœud
racine, et la valeur de chaque nœud du sous-arbre de droite doit être supérieure à la valeur du
nœud racine.
*Arbre AVL:
C'est l'un des types de l'arbre binaire, ou on peut dire que c'est une variante de l'arbre de
recherche binaire. L'arbre AVL satisfait à la propriété de l'arbre binaire ainsi qu'à celle de
l'arbre de recherche binaire. Il s'agit d'un arbre de recherche binaire auto-équilibré inventé
par Adelson Velsky Lindas. Ici, l‟auto-équilibrage signifie équilibrer les hauteurs du sous-
arbre gauche et du sous-arbre droit. Cet équilibrage est mesuré en termes de facteur
d'équilibrage.
On peut considérer un arbre comme un arbre AVL si l'arbre obéit à l'arbre de recherche
binaire ainsi qu'à un facteur d'équilibrage. Le facteur d'équilibrage peut être défini comme la
différence entre la hauteur du sous-arbre de gauche et la hauteur du sous-arbre de droite. La
valeur du facteur d'équilibrage doit être 0, -1 ou 1 ; par conséquent, chaque nœud de
l'arborescence AVL doit avoir la valeur du facteur d'équilibrage soit 0, -1 ou 1.
Les graphes
Les types de graphiques
Graphique pondéré : dans un graphique pondéré, chaque bord contient des données (poids)
telles que la distance, le poids, la taille, etc. Il est noté w(e). Il est utilisé pour calculer le coût
de déplacement d‟un sommet à un autre.
Graphique non pondéré : un graphique dans lequel les arêtes ne sont associées à aucune
valeur est appelé graphique non pondéré.
Graphique orienté : un graphique dans lequel les arêtes représentent la direction est appelé
un graphique orienté. Dans un graphique orienté, nous utilisons des flèches au lieu de lignes
(bords). La direction indique la manière d'atteindre d'un nœud à un autre nœud. Notez que
dans un graphe orienté, nous pouvons nous déplacer soit dans un sens, soit dans les deux sens.
La figure suivante représente un graphe orienté.
Graphique non orienté : un graphique dans lequel les arêtes sont bidirectionnelles est appelé
un graphique non orienté. Dans un graphe non orienté, nous pouvons parcourir dans n‟importe
quelle direction. Notez que nous pouvons utiliser le même chemin de retour par lequel nous
avons parcouru. Dans le graphe orienté, nous ne pouvons pas revenir du même chemin.
Graphique connecté : un graphe est dit connecté s'il existe au moins un chemin entre chaque
paire de sommets. Notez qu‟un graphe avec seulement un sommet est un graphe connexe.
--> Pour l'implémentation de graphiques en Java, nous utiliserons la classe générique. Pour
créer un objet de classe Java Generic, nous utilisons la syntaxe suivante):
BaseType <ParameterType> obj = new BaseType <ParameterType>();
Hash map
Déclaration :
La classe HashMap<K,V> est une implantation particulière de table (K est le type des clés, et
V le type des valeurs). La fonction de recherche de clé est réalisée en un temps presque
constant, grâce à l'utilisation d'une fonction dite de hachage, qui transforme la clé en un entier.
corps de la classe
Une classe peut être déclarée final, dans un but de sécurité ou d‟optimisation. Une classe
finale ne peut être étendue pour créer des sous-classes. Par conséquent, ses méthodes ne
peuvent pas être redéfinies et leur accès peut donc se faire sans recherche dynamique.
Une classe Java peut contenir, outre des primitives, des objets (du moins leurs références)
et des définitions de méthodes, des définitions de classe. Nous allons maintenant nous
intéresser de plus près à cette possibilité.
Il arrive fréquemment que certaines classes ne soient utilisées que par une seule autre
classe. Considérons l‟exemple suivant :
Class Animal {
// champs
boolean vivant ; int âge ;
Coordonnées position ;
// constructeurs
Animal() {
position = new Coordonnées() ;
}
}
Class Coordonnées {
// champs
int x = 0; int y = 0;
}
Toutes ces classes sont définies dans le même fichier, ce qui convient dans le cadre de
la démonstration mais certainement pas pour la pratique courante de la programmation
efficace. Chacune de ces classes pourrait être définie séparément dans un fichier et affectée à
un package.
Lorsque celle-ci concerne uniquement «la classe principale». Voyons pour notre exemple
:
Class Animal {
// champs
boolean vivant ; int âge ;
Coordonnées position ;
// classes imbriquées
static Class Coordonnées {
// champs
int x = 0; int y = 0;
}
// constructeurs
Animal() {
position = new Coordonnées() ;
}
}
import mesclasses.Animal.Coordonnées ;
import mesclasses.Animal.* ;
Les classes imbriquées peuvent elles-mêmes contenir d‟autres classes imbriquées, sans
limitation de profondeur, du moins du point de vue de Java.
La classe Coordonnées a été déclarée static, ce qui est obligatoire pour toute classe
imbriquée. En revanche, les interfaces imbriquées sont automatiquement déclarées static et il
n‟est donc pas nécessaire de les déclarer explicitement comme telles.
Tout objet java est une instance d‟une classe. Pour allouer la mémoire nécessaire à cet
objet, on utilise l‟opérateur new, qui lance l'exécution du constructeur.
- les constructeurs,
int a ;
Si cette déclaration se trouve dans une méthode, la variable n‟a pas de valeurs. Toute
tentative d‟y faire référence poduit une erreur de compilation.
Les variables de type numérique sont initialisées à 0. Le type booléen est initialisé à
false.
int a = 1 ;
int b = a*7 ;
float c = (b–c)/3 ;
boolean d = (a < b) ;
Un initialiseur d‟instance est tout simplement placé, comme les variables d‟instances,
à l‟extérieur de toute méthode ou constructeur.
class Exemple {
// champs
int a ;
int b ;
float c ;
boolean d ;
// initialiseurs
a=1;
b = a*7 ;
c = (b-a)/3 ;
d = (a < b);
}
Les initialiseurs comportent cependant des limitations. Il n‟est pas possible de leur
passer des paramètres comme dans le cas des constructeurs. De plus, ils sont exécutés avant
les constructeurs et ne peuvent donc utiliser les paramètres de ceux-ci.
class Voiture {
// champs
static int capacité ;
// initialiseurs
static {
capacité = 80;
println("La variable vient d’être initialisée.\n") ;
}
// constructeurs
Voiture() {
}
// méthodes
static int getCapacité() {
return capacité;
}
}
L‟initialiseur statique est exécuté au premier chargement de la classe, que ce soit pour
utiliser un membre statique, Voiture.getCapacité()ou pour l‟instancier, Voiture maVoiture =
new Voiture().
Les membres statiques (ici la variable capacité) doivent être déclarés avant
l‟initialiseur. Il est possible de placer plusieurs initialiseurs statiques, où l‟on souhaite dans la
classe. Ils seront tous exécutés au premier chargement de celle-ci, dans l‟ordre où ils
apparaissent.
De plus chaque classe dérive d‟une classe de niveau supérieur, appelée sur-classe. Cela est
vrai pour toutes les classes sauf une. Il s‟agit de la classe Object, qui est l‟ancêtre de toutes les classes.
Toute instance d‟une classe est un objet du type correspondant, mais aussi du type de toutes ses classes
ancêtres.
Une classe est toujours construite à partir d‟une autre classe dont elle est dérivée. Une classe
dérivée est une sous-classe d'une sur-classe.
• Extends
Lorsque le paramètre extends est omis, la classe déclarée est une sous classe de l'objet Objet.
b. Les objets
Un objet est une instance d‟une classe, qui est l‟outil fondamental de programmation.
Une classe peut aussi être considérée comme une description de ce qu‟il faut faire pour créer
un objet. Les classe sont composées de méthodes et d‟attributs qui peuvent être public, private
ou protected.
monObjet.nomAttribut = valeurAttribut;
Si une méthode n‟accède pas ou ne modifie pas les attributs de l‟objet, on dit que cette
méthode est static.
Il existe de nombreux objets prédéfinis en Java. Nous allons dans cette section
présenter l‟un d‟entre eux, incontournable
Le type “chaîne de caractères”, appelé String. Cet objet est le seul qui sera réellement
manipulé en première année.
Noter la présence de guillemets doubles pour distinguer les chaînes de caractères des
éléments du langage de programmation Java (mots du langage, nom de variables, nom de
méthodes).
Comme le type String est très utilisé, une particularité de ce type est que l‟on accède à
l‟attribut principal de l‟objet, la chaîne de caractères, comme si c‟était un type primitif :
Les objets de type String sont fournis avec un grand nombre de méthodes permettant
une manipulation facile de ces objets. Les quatre principales méthodes permettent d‟accéder à
chaque caractère de la chaîne, de connaître le nombre de caractères de la chaîne (sa longueur),
d‟extraire une partie de la chaîne et de comparer le contenu de deux chaînes :
Notez les parenthèses de la méthode length, parenthèses absentes lorsque l‟on appelle
cette méthode sur un tableau.
• String substring(int debut, int fin) : cette méthode renvoie un objet de type String qui
• equals(String s) : cette méthode renvoie une variable de type booléen qui vaut vrai si et
seulement si la chaîne de caractères s est la même que la chaîne de caractères de l‟objet sur
lequel on appelle la methode:
Il peut être nécessaire de pouvoir convertir un type primitif en une chaîne de caractères
ou réciproquement.
La conversion d‟un type primitif en une chaîne de caractères se fait à l‟aide de l‟instruction
String.valueOf(valeurPrimitive);
On peut également définir ses propres objets. C‟est ce que nous allons apprendre à
faire ici, en illustrant notre propos sur l‟exemple du début de section.
Les classes permettent de définir des types ou des catégories d‟objets (on pourra
prendre la métaphore du moule des objets). Elles contiennent la description des objets, (ex :
les abonnés), c‟est-à-dire métaphore du moule des objets). Elles contiennent la description des
objets, (ex : les abonnés), c‟est-à-dire qu‟elles définissent les attributs et les méthodes
communes aux objets d‟un certain type.
Les objets construits à partir de ces classes sont des instances. Les instances sont des
éléments créés depuis
class NomType {
// le corps de la classe vient ici
// les attributs
// les méthodes
}
class Abonne {
//les attributs de la classe Abonne
String nom;
String prenom;
int nbLivres;
int nbJours;
}
class Abonne {
//les attributs de la classe Abonne
String nom;
String prenom;
int nbLivres;
int nbJours;
Abonne() {
// premier constructeur
nom = new String("");
prenom = new String("");
nbLivres = 0;
nbJours = 0;
age = 0;
}
Abonne(String nom, String prenom, int nbLivres, int nbJours) {
// deuxième constructeur
this.nom = new String(nom);
this.prenom = new String(prenom);
this.nbLivres = nbLivres;
this.nbJours = nbJours;
}
}
Il peut exister plusieurs constructeurs qui se distinguent par leurs paramètres formels.
Ainsi, en fonction des paramètres effectifs (nombre de paramètres ou types des paramètres)
passés au constructeur au moment de l‟appel, l‟un ou l‟autre des constructeurs sera appelé.
Le mot clé this permet de spécifier que l‟attribut que l‟on référence est celui de l‟objet
en cours de con struction. En effet, l‟expression this.nom = nom; signifie que l‟attribut nom
de l‟objet en cours de con struction (this.nom) prend la valeur du paramètre formel nom de
type String du constructeur.
class EnsembleDesAbonnes {
//Attributs de la classe EnsembleDesAbonnes
Abonne[] lesAbonnes;
int nbAbonnes;
//Constructeur
EnsembleDesAbonnes(int nbAbonnes) {
lesAbonnes = new Abonne[nbAbonnes];
this.nbAbonnes = nbAbonnes;
int i;
for(i = 0; i < this.nbAbonnes; i++) {
lesAbonnes[i] = new Abonne(); // instancie chaque abonné
}
}
}
Enfin, la méthode estEnRetard, qui renvoie la liste des abonnés dont le dernier
emprunt a été effectué il y a plus de 21 jours, compte le nombre d‟abonnés en retard, puis crée
un nouvel objet EnsembleDesAbonnes pouvant contenir tous les abonnés en retard, puis
recopie l‟adresse des abonnés en retard dans l‟objet resultat pouvant contenir tous les abonnés
en retard, puis recopie l‟adresse des abonnés en retard dans l‟objet resultat :
EnsembleDesAbonnes estEnRetard() {
int i;
int nbEnRetard = 0;
for(i = 0; i < lesAbonnes.length; i++) {
if( (lesAbonnes[i].nbJoursEmprunts > 21)&&(lesAbonnes[i].nbLivresEmpruntes
> 0)) {
nbEnRetard = nbEnRetard + 1;
}
}
EnsembleDesAbonnes resultat = new Abonnes(nbEnRetard);
int j = 0;
for(i = 0; i < lesAbonnes.length; i++) {
if( (lesAbonnes[i].nbJoursEmprunts > 21)
&&(lesAbonnes[i].nbLivresEmpruntes > 0)) {
resultat.lesAbonnes[j] = this.lesAbonnes[i];
j = j + 1;
}
}
return resultat;
}
Le tableau lesAbonnes de l‟objet resultat contient des références vers les abonnés du
tableau lesAbonnes de l‟objet en cours de définition.
mesAbonnes.lesAbonnes[1].renseigneUnAbonne("Martin", "Jeanne",1,30);
mesAbonnes.lesAbonnes[2].renseigneUnAbonne("Vaus", "Paul",2,22);
mesAbonnes.lesAbonnes[3].renseigneUnAbonne("Bon", "Jean",0,27);
EnsembleDesAbonnes abonnesEnRetard = mesAbonnes.estEnRetard();
// abonnesEnRetard contient les références à Jeanne Martin et Paul Vaus
}
A. Les flux
Il existe plusieurs classes prédéfinies en Java permettant de créer et manipuler des flux.
On distingue les flux selon 2 critères :
• Les classes relatives aux flux sont pour la plupart regroupées dans le paquetage
java.io, mais aussi dans d‟autres paquetages (java.util, java.util.zip, java.security,
javax.crypto)
1. Flux d’octets
Deux hiérarchies de classes prédéfinies existent en Java pour les flux d‟octets.
2. Interface Closeable
Une seule méthode : ferme le flux et libère toutes les ressources systèmes associées au
flux. N‟a aucun effet si le flux est déjà fermé
InputStream (abstraite)
Méthodes de lecture
abstract int read() throws IOException lit et retourne l‟octet suivant. Retourne -1 si
EOF. levée Bloque jusqu‟à la lecture de l‟octet, EOF ou d‟une IOException.
int read(byte[] t) throws IOException lit jusqu‟à t.length octets, les range dans t et retourne
le nombre d‟octets lus ou -1 si EOF. Lève une NullPointerException si t vaut null.
• InputStream (abstraite)
int read(byte[] t, int d, int lg) throwsIOException lit jusqu‟à lg octets, les range dans t à
partir de l‟indice d et retourne le nombre d‟octets lus ou -1 si EOF. Lève une
NullPointerException si t vaut null.
• InputStream (abstraite)
Autres méthodes
int available() retourne le nombre d‟octets disponibles (pouvant être lus sans bloquer avec
read()).
• InputStream (abstraite)
void mark(int limite) throws IOException positionne une marque à laquelle il est possible
de revenir par un reset. limite indique le nombre d‟octets pouvant être lus avant que cette
marque soit invalidée.
void reset() throws IOException repositionne la lecture à la dernière marque placée dans le
flux. Une IOException est levée si aucune marque valide existe ou si les marques ne sont pas
autorisées par le flux.
• FileInputStream
Constructeurs
• FileInputStream
Méthodes additionnelles
BufferedInputStream
DataInputStream
• BufferedInputStream
Constructeurs
Constructeur
• DataInputStream
void readFully(byte[] tab) lit tab.length octets dans le flux et les place dans tab, méthode
bloquante.
void readFully(byte[] tab, int d, int l) lit l octets dans le flux et les place dans tab, à partir
de l‟indice d, méthode bloquante.
int skipBytes(int n) tente de sauter n octets dans la lecture du flux et retourne le nombre
d‟octets effectivement sautés.
• DataInputStream
boolean readBoolean() lit l‟octet suivant et retourne true s‟il est différent de 0, false sinon.
• DataInputStream
String readLine() lit plusieurs octets en les interprétant chacun comme des caractères
qui sont mis dans la String retournée. La lecture s‟arrête à une fin de ligne ou en fin de flux.
String readUTF() lit plusieurs octets constituant une chaîne de caractères au format
UTF8 modifié et retourne la String correspondante.
B.LES FICHIERS
Dans l'exemple précédent, le fichier a bien les droits d'écriture puisque ceux-ci ont été
donnés au propriétaire du fichier, ie l'utilisateur qui a lancé le programme. En revanche, le
fichier n'est pas considéré comme exécutable puisque personne n'a les droits d'exécution.
c. copier un fichier
La copie d'un fichier passe par la méthode Files.copy qui prends en paramètre les Path source
et destination de la copie :
c. Déplacer un fichier
Pour déplacer un fichier, il faut utiliser la méthode Files.move. Tout comme File.copy,
cette méthode prend en paramètre des Path sources et destinations.
Là encore, par défaut, cette méthode génère une exception si le Path de destination
existe déjà. Ce comportement se change en passant l'option
StandardCopyOption.REPLACE_EXISTING en dernier paramètre de la méthode :
e. supprimer un fichier
Il suffit d'appeler la méthode Files.delete pour supprimer un fichier :
Dans le cas où le fichier à supprimer n'existe pas, Files.delete génère une exception de type
NoSuchFileException. Pour ignorer ces cas, il faut utiliser la méthode deleteFileIfExists.
I. Les Enregistrements
En Java, un type enregistrement est défini à l'aide d'une classe, dans laquelle les
variables membres représentent les champs de l'enregistrement. Les variables membres sont
déclarées au début de la classe juste après l'accolade ouvrante.
• Le nom du type est libre (doit se conformer à la règle d‟écriture des identificateurs Java)
• Les noms des champs sont libres (idem : doivent être des identificateurs)
• Si m est le nom d‟un champ d‟un type enregistrement E et o un objet de type E, alors :
=> o.m permet de lire la valeur de la composante m de o
=> o.m = v est l‟affectation qui permet de modifier la valeur de la composante m de o.
• L‟opérateur new permet de créer un nouvel objet :
E o = new E();
• Tous les champs d‟un objet créé sont initialisés au zéro de leur type respectif.
d‟utilisateur qui se compose d‟un identifiant (un entier), d‟un nom d‟utilisateur (un texte) et
d‟un nom complet ? La réponse est : avec un type enregistrement (record type).
Nous pouvons, par exempe, déclarer ou définir une variable de type UserAccount,
déclarer paramètre formel du même type, ou encore définir une fonction qui renvoie un
enregistrement de ce type.
printDisplayName(myAccount);
}
Une première possibilité est de créer une fonction qui prend en paramètre les données
de l‟enregistrement et qui renvoie une nouvelle instance de l‟enregistrement initialisée.
public class App {
public static void main(String[] args) {
UserAccount myAccount = createUserAccount(1000, "lovelacea",
"Ada Lovelace");
printDisplayName(myAccount);
}
a.uid = uid;
a.userName = userName;
a.displayName = displayName;
return a;
}
}
(Encapsuler la création de l'instance, 2e essai)
Voilà qui est beaucoup mieux. Comme une telle méthode est nécessaire pour tous les
types enregistrement, on peut s‟attendre à ce que cela soit prévu par le langage. C‟est
effectivement le cas : en Java, une classe peut avoir un ou plusieurs constructeurs. Le code
suivant montre le même programme que le précédent, mais avec un constructeur à la place de
la méthode de création.
public class App {
public static void main(String[] args) {
// Pour invoquer le constructeur, on utilise la même syntaxe que pour
// instancier un enregitrement vide, mais en passant les valeurs des
// champs en paramètres.
UserAccount myAccount = new UserAccount(1000, "lovelacea",
"Ada Lovelace");
printDisplayName(myAccount);
}
public static void printDisplayName(UserAccount account) {
System.out.println(account.displayName);
}
}
package ch.epai.ict.exemples.record_types;
2. Besoins de recherche
Il est important de déterminer si vous devez effectuer des recherches basées sur des clés
ou des valeurs. Si vous avez besoin de recherches rapides en fonction de clés uniques, une
structure de données basée sur une table de hachage telle que HashMap peut être plus
adaptée. Si vous avez besoin de recherches basées sur des plages de valeurs ou d'itérer sur les
éléments dans un ordre spécifique, une structure de données triée comme TreeMap peut être
plus appropriée.
Si votre application nécessite l'élimination automatique des doublons, vous pouvez utiliser
des structures de données comme HashSet ou TreeSet, qui garantissent qu'aucun élément en
double ne sera stocké.
4. Taille de la collection
Considérez la taille estimée de la collection de données que vous devez stocker. Certaines
structures de données peuvent présenter des performances différentes en fonction de la taille
des données. Par exemple, l'insertion et la suppression d'éléments peuvent être coûteuses en
termes de performances dans une ArrayList lorsque la taille de la liste est très grande.
5. Complexité temporelle
6. Complexité spatiale
maintenir des informations de structure. Assurez-vous que la structure de données choisie est
adaptée à vos contraintes de mémoire.
7. Besoins de synchronisation
1. Besoin de stockage d’un grand nombre d’éléments dans un ordre trié et effectuer des
recherches fréquentes
2. Besoin de stockage d’un grand nombre d’éléments sans doublons et effectuer des
tests d’appartenance rapide
Pour un tel besoin, vous pouvez utiliser un ensemble au lieu d‟une liste car en termes
d‟élimination automatique des doublons, un ensemble garantit cette absence puisque, lorsque
Exposé Informatique Et Programmation GCU 332 Rédigé Et Présenté Par : 94
vous insérez un élément dans un ensemble, il vérifie automatiquement si cet élément existe
déjà dans la collection. Cela évite d‟avoir à effectuer manuellement des vérifications de
doublons, ce qui peut être couteux en termes de performances, surtout lorsque vous travaillez
avec un grand nombre d‟éléments.
On peut aussi ajouter que les ensembles offrent une interface simple et intuitive pour
travailler avec des éléments uniques. Ils fournissent des méthodes claires pour ajouter,
supprimer et tester la présence d‟éléments sans doublons, ce qui facilite considérablement la
gestion de données.
Si vous avez besoin d‟une liste dynamique qui permet l‟ajout et la suppression efficace
des éléments, il serait judicieux de choisir un ArrayList.
Pour un besoin d‟une table de hachage basée sur le principe clé-valeur, il est approprié de
choisir un HashMap ou un TreeMap. Cependant, le HashMap, est plus approprié lorsque
vous devez associer des valeurs à des clés uniques et rechercher rapidement des valeurs en
fonction de leurs clés. Tandis que le TreeMap sera plus approprié lorsque vous avez besoin
d‟une table de hachage triée selon les clés.
aux besoins fonctionnels du programme, tout en minimisant les coûts en termes de temps
d‟exécution et d‟utilisation de la mémoire.
Temps d'accès rapide : Le choix d'une structure de données appropriée peut réduire le
temps d'accès aux éléments. Par exemple, l'utilisation d'un tableau pour un accès
aléatoire rapide, ou d'un arbre de recherche binaire permettra de faire une recherche
efficace. Dès lors, l‟accès aux éléments devient plus rapide.
La complexité algorithmique : Les structures de données ont des performances
différentes en fonction des opérations effectuées. Par exemple, une liste chaînée peut être
plus efficace qu'un tableau pour des insertions fréquentes, tandis qu'un tableau trié peut
être plus rapide pour des recherches.
L’utilisation efficace de la mémoire : Certaines structures de données peuvent
consommer plus de mémoire que d'autres. En choisissant une structure de données
appropriée, vous pouvez minimiser l'utilisation de la mémoire et éviter les gaspillages
inutiles. Par exemple, vous pouvez utiliser le final mot-clé pour déclarer des constantes
qui ne changent pas, utilisez le bouton éphémère Mot-clé pour exclure les champs qui
n‟ont pas besoin d‟être sérialisés, utilisez le bouton faible ou mou les références pour
faire référence aux objets qui peuvent être ramassés et utiliser le System.gc() Méthode
pour demander l‟exécution du garbage collector.
Le parallélisme : Si votre programme peut bénéficier du traitement parallèle, certaines
structures de données, telles que les tableaux, peuvent offrir de meilleures performances
en permettant un accès simultané à différentes parties de la structure. Le parallélisme est
la capacité d‟effectuer plusieurs tâches ou opérations simultanément en utilisant plusieurs
processeurs ou cœurs. Le parallélisme peut améliorer les performances d‟un programme
en réduisant le temps d‟exécution global et en augmentant le débit. En Java, vous pouvez
utiliser diverses fonctionnalités et bibliothèques pour implémenter le parallélisme, telles
que les threads, les exécuteurs, les futures, les appelables, les exécutables, les
synchroniseurs, les verrous, les variables atomiques et les flux. Par exemple, vous
pouvez utiliser le parallelStream() Méthode permettant de créer un flux parallèle à partir
d‟une collection et d‟effectuer des opérations parallèles sur les éléments, telles que le filtrage,
le mappage, la réduction et la collecte. L‟exploitation du parallélisme peut augmenter
l‟efficacité et l‟évolutivité de votre programme et améliorer ses performances.
L’évolutivité : Si votre programme doit gérer une grande quantité de données ou une
évolution future, choisir alors une structure de données qui s'échelonne bien avec la taille
des données peut améliorer les performances globales.
Il est important de noter que l'optimisation des performances ne consiste pas seulement
à choisir les structures de données les plus performantes, mais aussi à comprendre les
caractéristiques de votre programme, les patrons d'utilisation des données et à effectuer
des tests et des mesures pour évaluer les performances réelles.
CONCLUSION
En résumé, l'essence des structures de données réside dans leur capacité à organiser et
à manipuler des données de manière efficace, ce qui contribue à améliorer la performance, la
fiabilité et la maintenabilité des systèmes informatiques. En outre, les structures de données
sont étroitement liées aux algorithmes, car ces derniers déterminent comment les opérations
sur les données sont effectuées. Une bonne compréhension des structures de données et des
algorithmes associés est essentielle pour concevoir des solutions efficaces et optimisées pour
divers problèmes informatiques.
LEXIQUE
Un accesseur : en Java est une méthode qui permet d‟accéder à la valeur d‟une
variable d‟instance privée d‟un objet depuis l‟extérieur de la classe.
Un Array : est une collection d‟un nombre fixe de types de données similaires.
Un doublon : fait référence à la présence répétée d‟un même élément dans une
collection telle qu‟une liste ou un tableau.
Un TreeSet est une collection d‟objets où chaque élément est unique et trié selon un
ordre spécifié.
Un hashMap : est une structure de données qui mappe les clés aux valeurs. On
l‟appelle également table de hachage, carte de hachage ou tableau associatif.
Un tree map (ou treemap) :est une technique de visualisation de données qui
représente des relations de partie à tout dans une hiérarchie de catégories.
Un InputStream : est une classe abstraite qui représente un flux d‟octets en entrée.
Un OutputStream : en Java est une classe abstraite qui représente un flux d‟octets en
entrée.
REFERENCES BIBLIOGRAPHIQUES
Ce document est inspiré grandement de la page web de SUN sur les collections, qui se trouve à
l’adresse :
http://developer.java.sun.com/developer/onlineTraining/collections/Collection.html 16h48 le
18/03/24
https://openclassrooms.com/fr/courses/6173501-apprenez-a-programmer-en-java/6458461-
gerez-les-piles-de-donnees-avec-la-bonne-collection à 17h22 le 17/03/24
https://eddirasa.com/wp-content/uploads/univ/ESI/esi-cours_files_piles.pdf à 14h22 le
17/03/24
Codegym.cc
miahs www.u-ga.fr
jmdoudoux.fr
docplayer.fr
www.epai-ict.ch>m22trecord-type