Trop tard

(mais bon tu peux les mettre, ça peut compléter). N'hésitez pas à souligner si un truc est pas clair, j'ai du mal à définir la barrière "ceci est évident"/"ceci demande certaines connaissances préalables".
Leçon 0 : le langage Java
Un langage de programmation est un langage dans lequel s'exprime le développeur pour donner des ordres à la machine, afin d'automatiser certaines tâches.
A l'origine (moderne, donc Unix) de la programmation était le C.
C pas compliquéLe C est un langage à programmation impérative classique. La motivation à la base de la création du C est d'avoir une manière facile, puissante et efficace de donner des ordres à la machine. Le C est la base de Unix.
Il se caractérise principalement par les particularités suivantes.
Le développeur écrit des fichiers en texte clair (de l'anglais simplifié et un peu bizarre). On appelle ceux-là les fichiers sources.
La machine ne comprend pas directement ce qu'écrit le développeur dans ces fichiers (sinon on lui donnerait des ordres directement à la voix). Il faut d'abord les transformer dans le seul langage que comprend un ordinateur : le code assembleur (ce sont directement une suite d'appels à des instructions du processeur). Le traducteur, qui s'occupe de produire ce code assembleur à partir des fichiers sources est un compilateur.
Pour le C, un fichier source a pour extension ".c" et un fichier source compilé ".o" (en général).
Rappel : une fonction, en mathématique comme en programmation est une boîte noire qui prend un certain nombre de paramètres pour produire un retour à parti de ceux-ci. Par exemple, on peut définir que une fonction "somme" qui prend deux paramètres a et b, et dont le retour est a+b.
Le C n'est qu'une suite d'appels de fonctions : il existe une fonction spéciale (main(...)) dont le nom, les paramètres et le retour sont toujours les mêmes, par convention. Cette fonction sera toujours le point d'entrée d'une application en C : chaque fois qu'on demande l'exécution d'un code compilé C, c'est sa méthode main(...) qui est appelée.
Donc un programme C se décompose comme cela :
- on demande l'exécution du code compilé
- cela appelle la fonction main(...) du code compilé
- les différentes instructions à l'intérieur de la méthode main(...) sont exécutées
- la méthode main(...) renvoie sa valeur de retour, qui constitue le code retour du code compilé (on peut par exemple trouver ce code retour écrit dans la console lorsqu'une application plante).
Le but d'un programme est d'effectuer un traitement d'informations de manière automatique (c'est de là que vient le terme français "informatique"). Or les informations ne sont pas abstraites, elles se traduisent en types simples (entier, chaînes de caractères) ou plus compliqués (un ensemble de types simples).
En C, par défaut on ne trouve que des types simples (int pour un entier, char pour un caractère) et une manière de définir des types compliqués à partir de ces types simples.
A ce propos, que sont les instructions? En fait il s'agit de tout ordre complet, donc presque tout en C. Les instructions sont séparées par un ";" en général
(sauf quelques unes qui ne nécessitent pas de séparateur).
"int a;" est une instruction qui définit une variable de type entier (une variable est une boîte où stocker une valeur)
"a = 4;" est une instruction qui affecte la valeur 4 à la variable a de type entier.
De la même manière l'appel à une fonction est une instruction :
"int c; c = somme(3,5);" en définissant la fonction somme(...) comme expliqué ci-dessus. On peut aussi écrire "c = somme(a,5);" en réutilisant la valeur qui est stockée en a (4) pour produire la somme de 4 et de 5 et la stocker dans la variable c.
On peut séparer ses fichiers sources en plusieurs fichiers ".c", puis ensuite appeler des méthodes d'un autre fichier, une fois qu'on l'a importé (c'est-à-dire qu'on a dit au début du fichier qu'on allait l'utiliser).
Bien sûr on peut donc utiliser des types plus compliqués en c, par exemple on peut définir un type "point" comme étant un float (nombre à virgule) pour l'abscisse et un float pour l'ordonnée. Pour cela on utilise le mot-clef "struct" :
struct point {
float abscisse;
float ordonnee;
}
On peut même aller plus loin en créant un type compliqué qui utilise d'autres types compliqués. Par exemle, un cercle peut être défini comme un point et un float pour le rayon.
Les limites du C
Les problèmes du C sont les suivants :
- très peu de conventions : les conventions ne sont pas des contraintes en programmation, mais des garde-fous qui permettent au développeur d'être plus direct en le guidant plus efficacement. Il est évident qu'il est plus facile d'utiliser le code c d'un autre développeur si son code se rapproche du nôtre
- il n'est pas évident de créer une documentation claire et formattée
- dans le même esprit de collaboration entre développeurs, lorsqu'on veut utiliser un type compliqué C développé par un autre, il faut déjà récupérer la définition du type, puis les fonctions qui les utilisent (souvent dans un autre fichier). Et le pire est que la moindre adaptation est impossible : si un développeur a défini le type "rectangle" et a créé les fonctions de calcul basique associés (périmètre, surface,...), si on créé le type "carré" on aimerait bien pouvoir réutiliser les fonctions de calcul des rectangles mais on ne peut pas : le compilateur C nous dira que le carré n'est pas un rectangle du point de vue des types C
- problème plus technique : la gestion des réservations mémoires (car il faut bien stocker les informations quelque part dans l'ordinateur pendant l'exécution du code) est lourde et contraignante, surtout à une époque où la mémoire coule à flot dans nos ordinateurs. En plus dès qu'on se trompe, ou si on oublie de réserver la place ou assez de place, l'application se plante avec un message d'erreur incompréhensible. En effet le c ne fournit pas de vrai moyen de gérer les erreurs pendant l'exécution du code
Le langage Java est une réponse à ces défauts.
Les caractéristiques de base du Java
Java est un langage objet. Un objet est à comprendre au sens de composant, comme des pièces de Lego : il est facile d'utiliser ensemble les composants, et il est facile de s'approprier un composant défini par quelqu'un d'autre pour le spécialiser. Un exemple près de nous : le composant "champ de texte" Cocoa (écrit en Objective-C, un autre langage objet) est utilisé dans les applications Cocoa. Il suffit à Apple de l'enrichir d'une fonction de vérification de l'orthographe, pour qu'une simple recompilation de notre application hérite de la fonctionnalité.
Le maître mot ici est "hériter". En fait en Java tous les types compliqués seront en relation de filiation avec un autre type compliqué. Ce sont ces types compliqués qu'on appelle des objets (le code définissant ces objets étant une classe, l'équivalent du code source simple de C) (par la suite on ne distinguera plus trop une classe d'un objet, la classe étant plutôt le type, et un objet l'instanciation de la classe, c'est-à-dire une variable de type la classe).
L'ancêtre commun à tous ces objets, puisqu'il en faut bien un est la classe Object. Il n'a pas beaucoup de code associé réutilisable puisqu'il ne fait pas grand chose. Une autre classe intéressante, qui descend directement de Object, est String, qui représente une chaîne de caractères. Par exemple, on va pouvoir en Java définir l'objet MyString, une chaîne de caractère dont la première lettre serait toujours en majuscule. En indiquant que la classe MyString hérite de la classe String, on peut en particulier utiliser la méthode qui calcule la longueur d'une String sur un objet MyString. C'est donc beaucoup plus facile de réutiliser du code existant pour l'enrichir et l'adapter à nos besoins particuliers. Une classe Java, c'est donc un peu à la fois le struct C, plus les fonctions associées directement intégrées dans le même fichier, plus la possibilité de réutiliser les fonctions pour une classe fille. En Java, les fonctions s'appellent plutôt des méthodes (essentiellement par convention).
Les conventions en Java ont été définies depuis le début :
- les noms de classe commencent par une majuscule : Object
- les noms des variables, des méthodes commencent par une minuscule : Object monObjet;
-...
Un outil est directement intégré à Java pour facilement produire une documentation HTML de son code : la Javadoc. Pour moi c'est la clarté et la complétude de la Javadoc produite par Sun (qui a inventé le Java) pour les très très nombreuses classes de base du langage qui a facilité son développement : pour savoir comment marche la méthode substring de la classe String, il suffit de taper "java String substring" dans google pour tomber en une demi-seconde sur la documentation.
Enfin la gestion des erreurs à l'exécution est directement intégrée dans le système. Comment est-ce possible? En fait la compilation Java ne produit pas un code dans un langage compréhensible par l'ordinateur (il produit du byte code et pas du code assembleur), la machine a besoin d'un traducteur intermédiaire qui s'appelle la JVM (Java Virtual Machine). En fait, sous le capot, la JVM n'est qu'un petit programme, qui lit les fichiers classes compilés (les .class) comme s'il s'agissait de fichiers textes comportant des suite d'instructions qu'il a à exécuter. Et ce petit programme n'est pas bête : si les instructions qu'on lui demande d'exécuter plantent, il nous avertit en langage presque humain. Quand on oublie d'initialiser un objet, au lieu d'un "segmentation fault" à la C, il nous dit "NullPointerException" et nous indique dans quel endroit du code le problème est survenu. On dit que Java intègre la gestion des Exceptions.
Concernant la réservation mémoire, Java simplifie à moitié le problème : en C il faut allouer et libérer la mémoire à la main. En Java on a juste à allouer la mémoire (avec une syntaxe simplifiée par rapport au C), la libération de la mémoire se fait automatiquement (en fait un process de la JVM, le garbage collector (ou ramasse-miettes en français), regarde de temps en temps les objets en mémoire : ceux qui ne sont plus utilisables sont détruits). La syntaxe pour allouer de la mémoire est la suivante (par exemple pour un objet Object) : "Object objet = new Object();".
Mais me direz-vous, tout est donc objet en Java? En fait pour des raisons de performances, Sun a laissé dans le système quelques types simples à la C (ils sont appelés types primitifs en Java pour les distinguer des objets, et sont une poignée seulement). Les types primitifs s'appellent en général comme en C : int, float, char,... On les distingue, en tant que type, des objets car ils sont écrits en minuscules (alors que le type d'un objet aura sa première lettre en majuscule). Pour les types simples, comme en C, il n'est pas question de méthodes ou d'allocation mémoire : ils sont identiques en fonctionnalités et en utilisation aux mêmes types simples en C. Il est un peu compliqué quand on commence le Java à comprendre cette bivalence entre types primitifs et objets. Par exemple, on a à la fois un type primitif "int" et un objet "Integer" : le premier est un type primitif, le second un objet à part entière (qui est en fait défini en interne comme un attribut de type int et un ensemble de méthode de travail sur les Integer). Dans la classe Integer, on a des méthodes pour récupérer un int à partir d'un Integer et inversement.
Prochaine leçon : rapide présentation des différentes librairies utiles fournies avec Java et réalisation d'un premier programme Java avec Eclipse.
[edit]J'avais oublié quelques trucs à la fin