Programmation
  Orientée
  Objets 1




Léa Raya DÉCORNOD <lea-raya.decornod@unistra.fr>

Plan

Modèles Impératifs

un exemple pris au hasard dans la libc

une structure de données

stdio.h
…
#include <bits/types/FILE.h>
#include &li;bits/types/struct_FILE.h>
…
            
FILE.h
…
typedef struct _IO_FILE FILE;
…
            
struct_FILE.h
struct _IO_FILE {
  int _flags;
  …
  int _fileno;
  …
  _IO_lock_t *_lock;
};
            

des fonctions associées

stdio.h
/* Open a file and create
   a new stream for it. */
extern
FILE *fopen (const char *__filename,
             const char *__modes);

/* Write formatted output to STREAM. */
extern
int fprintf (FILE *__stream,
             const char *__format,
             ...);

/* Close STREAM. */
extern
int fclose (FILE *__stream);
            
glibc.git:include/stdio.h
glibc.git:libio/bits/types/FILE.h
glibc.git:libio/bits/types/struct_FILE.h

un exemple pris au hasard dans la libc

  • Rien n'aide au “rangement” entre données et fonctions :
    les
    FILE* truc;
    sont associés aux fonctions
    f…(truc, …);
    un peu partout dans le code source, en particulier
    fopen()
    &
    fclose()
    .
  • Les détails internes de la structure de donnée n'intéressent que les fonctions associées, et pas vraiment le reste du programme (qui va fouiller dans
    struct _IO_FILE {…
    ?)
  • Les pointeurs et leur gestion :
    malloc
    ,
    free
    ,
    *
    ,
    &
    , etc.
  • Les variations introduisent façilement de la complexité :
    if
    ,
    switch
    ,
    union
    , etc.


En pratique

Par rapport au langage C

  • les types primitifs existent de façon similaire
    • int,
    • long,
    • float,
    • double,
    • char
      /!\ 16 bits unicode
  • il y a un vrai type boolean (true/false)
  • les tableaux sont dynamiques et portent leur taille
    • int[] tableau = new int[n];
    • tableau.length
  • les pointeurs sont remplacés par les références
    • plus besoin de *, &, etc.
    • pointeur->suivant->suivantreference.suivant.suivant
  • malloc(taille)new Type,
    free(…) → ∅

Par rapport au langage C

  • String remplace les tableaux de char terminés par '\0'
  • structclass
  • les fonctions sont rangées dans les class
  • chaque classe class est rangée dans
    un fichier .java de même nom
  • #include <math.h>import java.lang.Math;
    • … ou pas, import java.lang.*; est par défaut
  • printf("m=%f\n",m);System.out.println("m="+m);
compilation
JDK — Java Development Kit
exécution
JRE — Java Runtime Environment
digraph PlaformeJava {
  bgcolor=transparent
  id="\G"
  node [ id="\G-\N" ]
  edge [ id="\G-\E" ]

    { rank = same
      Dev [ label=<👩
🖮>, fontname="Symbola", fontsize=32, fontcolor=blue3, shape=plaintext ] Class1 [ label=<Classe1.class
byte-code
���␀4;↲"#⇥$%↲&⇥$(↲)*…>, shape="component", style=filled, fillcolor="white"] Class2 [ label=<Classe2.class
byte-code
���␀4C↲(⇥*@,-⇥./↲0⇥.2↲…>, shape="component", style=filled, fillcolor="white"] joint1 [ width=0, height=0, shape=none, label=""] } { rank = same Src1 [ label=<Classe1.java
code source
public class Classe1 { …
>, shape="note", style=filled, fillcolor="#dcf0ff"] } { rank = same Src2 [ label=<Classe2.java
code source
public class Classe2 { …
>, shape="note", style=filled, fillcolor="#dcf0ff"] javac [ label=<javac Classe1.java Classe2.java
compilateur>, shape="rect", style=filled, fillcolor="#dcf0ff"] } javac -> joint1 [ dir=none ] { Src1; Src2 } -> javac [ arrowhead=vee ] Dev -> { Src1;Src2 } [style=invis] JVM [ label=<java Class1
machine virtuelle (JVM)>, shape="rect", style=filled, fillcolor="white"] joint1 -> { Class1; Class2 } [ arrowhead=vee, constraint=false ] { Class1; Class2 } -> JVM [ arrowhead=vee ] Client [ label=<🖳
👱>, fontname="Symbola", fontsize=32, fontcolor=darkgreen, shape=plaintext ] JVM -> Client [dir=none] }

Exemple

CamelCase

  • mettre en majuscule la première lettre des mots liés
    exemple : PlayStation
    • les variables et les fonctions : minuscule au départ
      double zeroAbsoluEnDegresCelsius = -273.15;
      ,
      "XXX".equalsIgnoreCase("xxx")
      ,
      in.nextDouble()
    • les classes : en commençant par une majuscule
      public class EauChaude {
      ,
      new FileOutputStream("resultats.txt")
      ,
      } catch (ArrayIndexOutOfBoundsException err) {
  • sauf : les constantes sont entièrement en majuscules et _
    public static final double ZERO_ABSOLU_EN_DEGRES_CELSIUS = -273.15;

Éditeur — IDE

l'usage d'un environnement de développement intégré (IDE)
est fortement recommandé (lorsque cela est possible).


deux décennies de conception orientée objet

20 ans de — naissance

  • 1990
    James Gosling développe OAK chez Sun Microsystems
    un le langage de programmation indépendant de la machine
    ciblé vers les systèmes embarqués
  • 1993
    naissance du World Wide Web @CERN
  • 1994
    Changement de stratégie au sein du green project
    re-ciblage pour WWW avec la promesse des navigateurs graphiques interactifs
    Sun renomme Oak (dont le nom était sous la coupe d'un brevet)
    en Java (en référence à la boisson prisée des programmeurs : le café)
  • 1995
    naissance de Amazon, Ebay & Yahoo
  • 1995 (23 mai)
    Java 1.0a2 est publié : „Write once, run anywhere”
    avec le navigateur internet HotJava
  • 1996
    première conférence JavaOne (6 000 personnes)
  • 1996
    Netscape annonce le support de Java dans ses navigateurs
  • 1997
    JDK 1.1 → JavaBeans, RMI, JIT, Inner‑Classes, JDBC
  • 1997
    Sun poursuit Microsoft pour son implémentation incomplète et pervertie de Java 1.1
    en janvier 2001 Microsoft paiera 20 millions de dollards
    et clotûrera sa version en 2003 (avec le SP1a de WindowsXP)
  • décembre 1998
    JDK 1.2 → Swing, Collections
    Désormais le nom sera « Java 2 Platform »
    et se déclinera en trois éditions :
    • Standard Edition (J2SE),
    • Enterprise Edition (J2EE)
    • & Micro Edition (J2ME)
  • 2000
    J2SE 1.3 → HotSpot, JNDI
  • 2001
    lancement du projet open‑source Eclipse (IBM)
    en remplacement de Visual Age
  • 2002
    J2SE 1.4 → JAXP, NIO, Logging, assert, expressions rationnelles
  • 2004
    J2SE 5.0 → génériques, annotations, autoboxing, vararg, foreach
    changement de numéros de versions : 1.5.0 s'appellera 5.0 (et de même par la suite)
  • 2005
    Sun lance Glassfish
  • 2006
    Java SE 6 → scripting (dont javascript), WebServices
    fin de la désignation J2SE (abandon du '2')
  • 2006-2007
    Sun publie le code source du compilateur javac et de la machine virtuelle HotSpot sous licence libre GPL
    → OpenJDK
  • 2008
    le HTC G1 (Dream) sort : le premier smartphone Android
  • 2009
    Oracle rachète Sun pour 7,4 milliards de dollards
  • Sun aura été un contributeur majeur du logiciel libre
    • libération de Java sous licence GPL
    • libération du source de StarOffice qui formera le projet OpenOffice
    • poursuite du développement de MySQL sous double licence
    • la libération d'une partie de Solaris → OpenSolaris
    • le développement de VirtualBox sous licence GPL
  • 2007,2010‑2011
    RedHat, IBM, Apple & SAP
    rejoignent successivement le projet OpenJDK
  • 2011
    Java7 → dynamic languages support
  • 2014
    Java8 → lambda, Streams, PermGen
  • sept 2017
    Java9 → JDK modulaire, Jshell, compilation AoT, …
  • mars 2018
    Java10 → inférence de type var, …
  • sept 2018
    Java11 → paramètres de lambda var, ZGC, …
  • mars 2019
    Java12 → améliorations G1, Shenandoah GC, …
  • sept 2019
    Java13 → heredoc, …
  • mars 2020
    Java14 → expressions switch, …
  • sept 2020
    Java15 → classes scellées, …
  • mars 2021
    Java16 → records, instanceof pattern variables, mercurial → github, …
  • mars 2018
    Java10 → inférence de type pour les variables locales, parallel G1, …
  • septembre 2018
    Java11 → LTS (jusqu'en 2023), no-op GC, local var dans les lambdas, …
  • mars 2019
    Java12

Principes de la Programmation
Orientée Objet

principes de POO (on y reviendra)

L'objet

regroupe état : données
& comportement : méthodes

L'encapsulation

les détails internes sont cachés

Le polymorphisme

un objet peut adopter plusieurs comportements
par exemple l'eau se comporte aussi comme
un solvant, un conducteur, un acide ou une base

La surcharge

redéfinition
de comportements existants
par exemple l'eau lourde
gèle à 3,81°C au lieu de 0°C

un exemple pris au hasard dans Java SE

programmation
modélisation
digraph FileOutputStream {
  bgcolor=transparent
  id="\G"
  node [ fontname = "Courier", fontsize = 12, id="\G-\N", style=filled ]
  
  FileOutputStream [ shape=plain,label=<
FileOutputStream
- fd: FileDescriptor
- path: String
- closed: boolean
+ FileOutputStream(String)
+ write(…)
+ close()
> ] OutputStream [ shape=box,label=<OutputStream> ] OutputStream -> FileOutputStream [dir=back, arrowtail=empty] }
① l'objet contient :
l'état
① l'objet contient :
le comportement
② une partie est
cachée :
private
③ adhère à plusieurs
comportements
surcharge des
comportements
java/io/FileOutputStream.java
package java.io;

public
class FileOutputStream extends OutputStream {
  private final FileDescriptor fd;
  private final String path;
  private boolean closed;

  public FileOutputStream(String name) {
    …
  }
  public void write(…) {
    …
  }
  public void close() {
    …
  }
}
           
https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/java/io/FileOutputStream.java#L69

deux principales classes de languages objets

Orienté Prototype
javascript
digraph ModelePrototype {
  bgcolor=transparent
  node [ fontname = "Courier", fontsize = 12, id="\G-\N", style=filled ]
  edge [ fontname = "Courier", fontsize = 11, id="\G-\E" ]
  
  value1 [ shape=box,label=<:Number
1> ] value15 [ shape=box,label=<:Number
1.5> ] value30 [ shape=box,label=<:Number
30> ] Number [ shape=plain,label=<
Number«prototype»
toExponential()
toFixed()

> ] Object [ shape=plain,label=<
Object«prototype»
watch()

> ] { value1; value15; value30 } -> Number -> Object [arrowhead=vee, arrowtail=odiamond, dir=both, style=plain, arrowsize=.75] }
Orienté Classes
java, .net, c++
digraph ModeleClasses {
  bgcolor=transparent
  node [ fontname = "Courier", fontsize = 12, id="\G-\N", style=filled ]
  edge [ fontname = "Courier", fontsize = 11, id="\G-\E" ]
  
  subgraph values {
  value1 [ shape=box,label=<:Integer
1> ] value15 [ shape=box,label=<:Float
1.5> ] value30 [ shape=box,label=<:Integer
30> ] value1 -> value30 -> value15 [ style=invis ] } Integer [ shape=plain,label=<
Integer
parseInt(…)
> ] Float [ shape=plain,label=<
Float
parseFloat(…)
> ] Number [ shape=plain,label=<
Number
intValue()
> ] Object [ shape=plain,label=<
Object
getClass()
> ] { value1; value30 } -> Integer [constraint=false, arrowhead=vee, style=dashed, arrowsize=.75] { value15; } -> Float [constraint=false, arrowhead=vee, style=dashed, arrowsize=.75] Object -> Number -> {Integer; Float} [dir=back, arrowtail=empty] }
digraph ClassesInstances {
  bgcolor=transparent
  fontname="Brill"
  fontsize=26
  node [ fontname = "Courier", fontsize = 12, shape="box", id="\G-\N", style=filled ]
  edge [ fontname = "Courier", fontsize = 11, id="\G-\E" ]
  
  subgraph cluster_References {
    label="Références"
    bgcolor="#dcf0ff"
    posX [ shape=box,label=<posX: Number> ]
    posY [ shape=box,label=<posY: Number> ]
    distance [ shape=box,label=< distance: Float> ]
    posX -> posY -> distance [ style=invis ]
  }

  subgraph cluster_Instances {
    label="Instances"
    bgcolor="#dcf0ff"
    node [shape="rect"]
    value1 [ label=<1> ]
    value15 [ label=<1.5> ]
    value30 [ label=<30> ]
    value1 -> value30 -> value15 [ style=invis ]
  }
  {
    edge [constraint=false, dir=both, arrowtail=odiamond,arrowhead=vee,style=solid, arrowsize=.75]
    posX -> value1
    posY -> value30
    distance -> value15
  }

  subgraph cluster_Classes {
    label="Classes"
    Integer [ shape=plain,label=<
Integer
parseInt(…)
> ] //bgcolor="#def7e3" bgcolor=white Float [ shape=plain,label=<
Float
parseFloat(…)
> ] Number [ shape=plain,label=<
Number
intValue()
> ] Object [ shape=plain,label=<
Object
getClass()
> ] } { value1; value30 } -> Integer [constraint=false, arrowhead=vee, style=dashed, arrowsize=.75] { value15; } -> Float [constraint=false, arrowhead=vee, style=dashed, arrowsize=.75] Object -> Number -> {Integer; Float} [dir=back, arrowtail=empty] }

Éléments de vocabulaire en POO

digraph Vocabulaire {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill" ]
  
  { rank=same
    est [label="", width=0, height=0, shape=none, class="Vocabulaire-red", fillcolor=red, color=red]
    Parent [ label= "Classe Parente" ]
  }
  { rank=same
    Object [ shape=box,label=<Objet: Type> ]
    Child [ shape=plain,label=<
Classe Fille
attribut: Type
variable d'instance
+ visibilité publique
- visibilité privée
membre(Type,Type): Type
méthode(…)
méthode d'instance()
> ] Instance [ shape=box,label=<Instance
attribut = "valeur"> ] } //Object -> Instance [style=invis] Parent -> Child [dir=back, arrowtail=empty] Object -> Child [arrowhead=vee, style=dashed] Child -> Instance [arrowtail=vee, style=dashed, dir=back] Child-> Parent [constraint=false, arrowhead=vee, style=dashed, class="Vocabulaire-blue", color=blue, fontcolor=blue, label="spécialise\létends\lhérite de\ldérive de\l"] Parent-> Child [constraint=false, arrowhead=vee, style=dashed, class="Vocabulaire-green", color=green,fontcolor=green,label="généralise\lest la superclasse de\l \l "] Object -> est [constraint=false, dir=none, style=dashed, class="Vocabulaire-red", color=red,fontcolor=red,headlabel="est un\rinstance de\n"] est -> { Parent; Child } [constraint=false, arrowhead=vee, style=dashed, class="Vocabulaire-red", color=red,fontcolor=red] }

Principes de la Programmation
Orientée Objet


l'objet


regroupe état
et comportements

POJO = Plain Old Java Object

digraph EauChaude1 {
  bgcolor=transparent
  id="uml\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  EauChaude1 [ shape=plain,label=<
EauChaude1
temperature: double
etatφ(): String
> ] eau [ label= <eau
temperature = 25.0> ] EauChaude1 -> eau [arrowtail=vee, style=dashed, dir=back] }

variables d'instance vs variables de classe

digraph umlEauChaudeStatic {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  EauChaudeS [ shape=plain,label=<
EauChaudeS
temperature : double
ZERO_K = -273.15 : double
pointFusion = 0 : double
pointEbulition = 100 : double
etatφ() : String
main(String[])
>; shape=none, fillcolor=transparent ] eau1 [ label= <eau1
temperature = 25.0> ] eau2 [ label= <eau2
temperature = -5.0> ] EauChaudeS -> { eau1; eau2 } [arrowtail=vee, style=dashed, dir=back] }

Principes de la Programmation
Orientée Objet


l'encapsulation


les détails internes
sont cachés

digraph EauChaude2 {
  bgcolor=transparent
  id="uml\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  EauChaude2 [ shape=plain,label=<
EauChaude2
-temperature: double
+setTemperature(double)
+getEtatφ(): String
> ] }
digraph umlEauChaude2Bis {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  EauChaude2Bis [ shape=plain,label=<
EauChaude2Bis
-ZERO_K: double
-temperature: double
+setTemperature(double)
+getEtatφ(): String
> ] }
digraph umlEauChaude2Ter {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  EauChaude2Ter [ shape=plain,label=<
EauChaude2Ter
-obs: Observe
-temperature: double
+setObservateur(Observe)
+setTemperature(double)
+getEtatφ(): String
> ] Observe [ shape=plain,label=<
Observe
+aChangee()
> ] Lambda [ shape=plain,label=<
 λ
> ] EauChaude2Ter -> Observe [arrowtail=odiamond, arrowhead=none, dir=both, constraint=false] Observe -> Lambda [arrowtail=empty, dir=back] }

Scanner in = new Scanner(System.in);
EauChaude2Ter eau = new EauChaude2Ter();
((EauChaude2Ter) eau).setObservateur(λ);
  ((EauChaude2Ter) eau).obs = λ;
System.out.println("température ?");
double t = in.nextDouble();
((EauChaude2Ter) eau).setTemperature(t);
  ((EauChaude2Ter) eau).temperature = t;
  Observe λ = ((EauChaude2Ter) eau).obs;
  ((Observe) λ).aChangee();
      String e = ((EauChaude2Ter) eau).getEtatφ();
      System.out.println(e);
	        

Java Bean

Un bean au sens java, est :
  • une classe
  • disposant d'un constructeur sans arguments :
    new MonBean()
  • disposant de propriétés :
    • définies par leurs accesseurs :
      public Type getMaPropriete() {…}
    • et mutateurs :
      public void setMaPropriete(Type valeur) {…}
    • en genéral liées à des variables d'instances privées
  • et étant « Sérializable » et non
    final
    (hors du champ de ce cours)

Java Bean

le nommage des accesseurs/mutateurs est important en java :
  • pour une propriété
    private Type propriétéTruc;
    • l'accesseur est
      public Type getPropriétéTruc() {…}
    • sauf si la propriété est booléenne,
      auquel cas l'accesseur est
      public boolean isPropriétéTruc() {…}
    • le mutateur est
      public void setPropriétéTruc(Type …) {…}

Mutabilité / immutabilité

  • une classe dont les instances ne peuvent pas changer d'état :
    • n'a pas de variables d'instances accessibles
      private Type xxx;

      et idéalement
      final
    • n'a pas de de mutateurs
      public void setXxx(…) {…}
    • ne contiens pas variables elles-mêmes mutables
      ou s'assure qu'elles ne seront pas modifiées :
      • n'offre pas de méthodes permettant leur mofidication
      • ne partage aucune référence vers ceux-ci (attention aux getters)
    est dite immutable (et les autres mutable)

Immutabilité

  • C'est notamment le cas de
    String
    • String hello = "Hello" + " " + "World";

      fait intervenir 5 instances différentes
    • les méthodes de String renvoient
      de nouvelles copies/instances à chaque fois
  • C'est le cas de même pour les classes « wrapper » des types primitifs
    • Integer
    • Long
    • Float
    • Double
    • Character
    • Short
    • Byte
    • Boolean

Immutabilité

Avantages :
  • sont simples à créer,
    tester & utiliser
  • sont naturellement Thread‑safe
  • sont de bonnes clefs de Hash/Set
Inconvénients :
  • consomment
    de l'allocation (new)
  • consomment
    du temps (copie)

StringBuffer / StringBuilder

  • StringBuffer
    &
    StringBuilder
    sont des classes mutables destinées
    à construire des chaines de caractères String
    • 100 × plus performantes que
      la concaténation de chaines
      +
      par lots
    • StringBuffer
      est Thead‑safe
    • StringBuilder
      n'est pas Thead‑safe
      (~10 % plus rapide que sa consœur)

Encapsulation des types primitifs

  • Rappel :
    en Java il existe deux types de variables :
    • les références vers des objets
      Type maVariable;
    • les types primitifs
      • byte b;
        (8bits)
      • short s;
        (16bits)
      • int i;
        (32bits)
      • long l;
        (64bits)
      • float f;

        (32bits IEEE‑754)
      • double d;

        (64bits IEEE‑754)
      • boolean p;
      • char c;

        (16bits unicode)
  • les types primitif ne sont pas des objets
  • cependant Java fournit une classe “wrapper” immutable encapsulant chaque valeur de type primitif

Encapsulation des types primitifs

  • digraph umlBoxing {
      bgcolor=transparent
      id="\G"
      concentrate=true
      node [ fontname = "Courier", fontsize = 12, id="\G-\N" ]
      edge [ fontname = "Brill", id="\G-\E" ]
    
      subgraph cluster_primitive {
        color=transparent
        node [ shape = "plaintext" ]
        byte;  short;  int;  long;
        float;  double;
        boolean;  char;
      }
      { node   [ shape = "record", style=filled ]
        edge   [ arrowtail=empty, dir=back ]
        Byte   [ shape=plain,label=<
    Byte
    -value: byte
    > ]; Short [ shape=plain,label=<
    Short
    -value: short
    > ]; Integer[ shape=plain,label=<
    Integer
    -value: int
    > ]; Long [ shape=plain,label=<
    Long
    -value: long
    > ]; Float [ shape=plain,label=<
    Float
    -value: float
    > ]; Double [ shape=plain,label=<
    Double
    -value: double
    > ]; Boolean[ shape=plain,label=<
    Boolean
    -value: boolean
    > ]; Char [ shape=plain,label=<
    Char
    -value: char
    > ]; Object -> Number -> { Byte; Short; Integer; Long; Float; Double; } Object -> { Boolean; Char } } { edge [style=invis] Integer -> Float; Long -> Double; } { edge [ dir=both, style=dotted, arrowhead=vee, arrowtail=vee] Byte->byte Short->short Integer->int Long->long Float->float Double->double Boolean->boolean Char->char } }

Encapsulation des types primitifs — autoboxing

  • passer d'une valeur primitive à un objet “wrapper”
    est appelé boxing
    Integer obj = new Integer(8);
  • passer d'un objet “wrapper” à une valeur primitive
    est appelé unboxing
    int primitif = obj.intValue();
  • le compilateur Java insère automatiquement les boxing
    et unboxing dans le bytecode
    
    public int somme(Integer... valeurs) {
      Integer somme = 0;
      for(Integer valeur : valeurs)
        somme += valeur;
      return somme;
    }
    	        
     → 
    
    public int somme(Integer... valeurs) {
      Integer somme = new Integer(0);
      for(Integer valeur : valeurs)
        somme = new Integer(
                     somme.intValue()
                   + valeur.intValue()
                );
      return somme.intValue();
    }
    	        

Principes de la Programmation
Orientée Objet


le polymorphisme


adopter plusieurs
comportements

digraph umlEauChaude3 {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Temperature3 [ shape=plain,label=<
Temperature3
-temperature: double
+setTemperature(double)
+getTemperature(): double
> ] EauChaude3 [ shape=plain,label=<
EauChaude3
+getEtatφ(): String
> ] Temperature3 -> EauChaude3 [arrowtail=empty, dir=back] }

Transtypage / Type Cast

  • Le transtypage (cast) est la conversion entre types
  • peut-être implicite dans le sens de l'élargissement :
    • byte
      short
      int
      long
      float
      double
    • Fille
      Parente
      Grandmere
      Object
  • explicite dans le sens du rétrécissement :
    • double
      float
      long
      int
      short
      byte
    • Object
      Grandmere
      Parente
      Fille

      peut lever une exception
      ClassCastException
    • instanceof
      permet de tester le type :
      
      Parent obj;
      …
      if (obj instanceof Fille) {
        Fille objAsFille = (Fille) obj; 
        …
      }
                      

Principes de la Programmation
Orientée Objet


la surcharge


redéfinition
de comportements
existants

digraph umlEauSalee4 {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Temperature3 [ shape=plain,label=<
Temperature3
-temperature: double
+setTemperature(double)
+getTemperature(): double
> ] EauChaude3 [ shape=plain,label=<
EauChaude3
+getEtatφ(): String
> ] EauSalee4 [ shape=plain,label=<
EauSalee4
+getEtatφ(): String
> ] Temperature3 -> EauChaude3 -> EauSalee4 [arrowtail=empty, dir=back] }

Héritage multiple

Peut-on hériter de plusieurs classes parentes ?
digraph umlHeritageMultiple {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Temperature [ shape=plain,label=<
Temperature
-temperature: double
+setTemperature(double)
+getTemperature(): double
> ] Pression [ shape=plain,label=<
Pression
-pression: double
+setPression(double)
+getPression(): double
> ] Eau [ shape=plain,label=<
Eau
+getEtatφ(): String
> ] { Temperature; Pression } -> Eau [arrowtail=empty, dir=back] }

Héritage multiple — problème du diamant

new Melange().getEtatφ()
= ?
digraph umlHeritageMultipleDiamant {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Matiere [ shape=plain,label=<
Matiere
+getEtatφ(): String
> ] Eau [ shape=plain,label=<
Eau
+getEtatφ(): String
> ] EauLourde [ shape=plain,label=<
EauLourde
+getEtatφ(): String
> ] Melange [ shape=plain,label=<
Melange
> ] Matiere -> { Eau; EauLourde } -> Melange [arrowtail=empty, dir=back] }

Contrats d'API

J'aimerai quand même écrire des choses comme :

Matiere5[] diversesEaux = …;
for (Matiere5 eau : diversesEaux) {
  eau.setTemperature(temp);
  System.out.println(eau.getEtatφ());
}
       	    

mais
public String getEtatφ()
n'a pas d'implémentation (code)
dans
Matière5
alors que chacune des sous-classes a la sienne.

→ on a besoin d'un contrat
qui définisse
public String getEtatφ()
dans
Matière5

sans implémentation propre
→ qui oblige les sous-classes
à posséder une implémentation concrète.

Classe abstraite – Méthode abstraite

  • une classe abstraite est une classe dont l'implémentation n'est pas complète :
    • marquée par
      abstract
    • n'est pas instanciable :
      new
      est interdit
    • possède une ou plusieurs méthodes abstraites
      • marquée par
        abstract
      • sans implémentation : pas de
        {}
  • les sous-classes
    class ClasseImpl extends ClassAbstraite
    • doivent fournir une implémentation
      @Overridde
    • ou être
      abstract
      elles aussi
digraph umlEauChaude5 {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Matiere5 [ shape=plain,label=<
Matiere5
#temperature : double
+setTemperature(double)
+getTemperature() : double
+etatφ() : String
>; shape=none, fillcolor=transparent ] EauChaude5 [ shape=plain,label=<
EauChaude5
+getEtatφ(): String
> ] EauSalee5 [ shape=plain,label=<
EauSalee5
+getEtatφ(): String
> ] Matiere5 -> { EauChaude5; EauSalee5 } [arrowtail=empty, dir=back] }

Classe “purement” abstraite — Interface

  • une classe abstraite ne contenant
    • ni implémentation (code)
    • ni variables
    → composée exclusivement de méthodes abstraites
    échappe au problème du diamant.

  • une
    interface
    décrit un contrat (ensemble de signatures de méthodes)
    • que les sous classes
      implements
      doivent honorer
    • forment des hierachies de types abstraits
    • une classse (et ses filles) peut en implémenter 0..*
    • peuvent étendre plusieures autres interfaces

Surcharge des signatures de methodes

  • plusieurs méthodes portant le même nom sont autorisées dans la mesure où les signatures sont disjointes
    (non-ambigües)

Cycle de vie
des objets

Phase de création

À l'instanciation d'un objet (c.-à-d. à l'appel de
new MaClasse();
)
ou d'une classe (juste avant sa première utilisation),
une phase de construction <init>/<clinit> a lieu :
  • Les variables d'instance et/ou de classes
    static

    peuvent être initialisées
    =
    ,
  • un bloc de code
    { … }
    peut être exécuté
    (très rarement utilisé, à part dans les classes anonymes),
  • une méthode particulière “constructeur
    est invoquée

un Constructeur est

  • une méthode qui porte exactement le même nom
    que sa classe,
  • n'a pas de retour, pas même dans sa signature
    (pas de mot clef
    void
    )
  • peut éventuellement recevoir des arguments (passés à
    new
    )
  • n'est pas invoquable autrement que depuis
    new

    ou un autre constructeur :
    this(arguments);

Constructeur et héritage

  • un constructeur par défaut vide et sans argument
    est créé automatiquement si aucun constructeur
    n'est fourni par le développeur,
  • si le constructeur utilisé ne fait pas référence explicite à un constructeur de sa classe parente
    super(arguments);
    , le constructeur sans arguments de cette dernière est invoqué automatiquement

Ordre de la phase de construction

Phase de destruction

C'est Java qui s'occupe automagiquement de libérer la mémoire allouée pour les objets lorsque cela est nécessaire
  • ce processus porte le nom
    de Garbage Collector / Ramasse Miettes
  • repose sur le comptage de références vers un objet,
    lorsqu'il tombe à zero, l'objet n'est plus utilisé
    et peut être libéré/détruit
  • il en existe plusieurs variantes (dont une utilisée par défaut)
    notamment quatre dans openJDK :
    • Serial
    • Parallel
    • CMS
    • G1

Hypothèse générationnelle

  • Les ramasse miettes de la JVM reposent sur l'hypothèse :
    “la plupart des objets meurent jeunes”

    • range les objets en fonction de leur “génération” :
      • jeune
        young generation
      • vieille
        old/tenured generation
      • permanente
        PermGen
    • des cycles de collecte examinent régulièrement les générations à la recherche d'objets inutilisés ,
    • les nouveaux objets sont créés dans la jeune génération (Éden) et s'ils y survivent plusieurs cycles (Survivor 1 & 2), ils sont transférés (Tenured) dans la vielle génération,

Cycles de collecte

  • lors d'une collecte, il y a une (ou deux) phase dite de stop-the-world qui bloquent l'application
  • plus la génération est vieille, plus elle est coûteuse
    donc idéalement moins fréquemment collectée
  • certains GC “compactent” la mémoire en rassemblant les objets dans la mémoire, ce qui augmente les performances d'allocations de nouveaux objets

java.lang.Object#finalize()

  • avant destruction d'un objet, le garbage collector s'arrange pour invoquer la méthode
    protected void finalize() {…}
  • n'utilisez pas cette méthode
    (autrement que pour avertir le développeur que des ressources n'ont pas été libérées)
    • on ne sait pas quand elle est invoquée
    • elle l'est depuis un thread pénalisant pour l'application

@Override
void finalize() {
  if (!this.closed)
    System.err.println("ATTENTION: ressource non libérée !");
}
	        

AutoClosable

  • pour libérer des ressources à la fin d'un bloc,
    il existe une interface :
    
    public interface AutoCloseable {
        void close() throws Exception;
    }
    	        
  • et une syntaxe try with :
    
    try (
      InputStream in = new FileInputStream("donnees.txt");
      OutputStream out = new FileOutputStream("resultats.txt");
    ) {
      …
      in.read(…);
      …
      out.writeln(…);
      …
    }
    	        
  • qui invoquera les méthodes
    close()
    à la fin du bloc

Gestion des erreurs

  • Lorsqu'une erreur surgit, une exception est levée :
    • c'est un objet de la hiérarchie
      Throwable
    • porteuse d'une description
    • gardant une trace de la pile d'appel
    • éventuellement une réaction en chaîne
digraph umlThrowable {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Throwable [ shape=plain,label=<
Throwable
+getMessage(): String
+printStackTrace()
+getCause(): Throwable
> ] Throwable -> Throwable [arrowtail=odiamond, dir=back] { edge [arrowtail=empty, dir=back]; Throwable -> { Error; Exception } Exception -> RuntimeException; } }
  • Error
    est reservé aux erreurs graves de la JVM
digraph umlError {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Throwable [ shape=plain,label=<
Throwable
+getMessage(): String
+printStackTrace()
+getCause(): Throwable
> ] Throwable -> Throwable [arrowtail=odiamond, dir=back] { edge [arrowtail=empty, dir=back]; { node [ fillcolor=orange ]; Error -> OutOfMemoryError; } Exception -> RuntimeException; Throwable -> { Error; Exception } } }
  • Exception
    est la classe de base pour les erreurs pouvant facilement être saisies et prises en compte
  • doivent être explicitement
    • indiquées
      throws
    • ou attrapées
      catch
  • s'appellent …Exception par convention
digraph umlException {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Throwable [ shape=plain,label=<
Throwable
+getMessage(): String
+printStackTrace()
+getCause(): Throwable
> ] Throwable -> Throwable [arrowtail=odiamond, dir=back] { edge [arrowtail=empty, dir=back]; { node [ fillcolor=orange ]; Exception -> IOException IOException -> { EOFException; FileSystemException } FileSystemException -> { NoSuchFileException; AccessDeniedException } } Throwable -> { Error; Exception } Exception -> RuntimeException; } }
  • RuntimeException
    est la classe de base pour les erreurs non controlées
  • échappent à l'obligation
    throws
    /
    catch
digraph umlException {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Throwable [ shape=plain,label=<
Throwable
+getMessage(): String
+printStackTrace()
+getCause(): Throwable
> ] Throwable -> Throwable [arrowtail=odiamond, dir=back] { edge [arrowtail=empty, dir=back]; Throwable -> { Error; Exception } { node [ fillcolor=orange ]; { rank = same; ArithmeticException -> RuntimeException [arrowhead=empty, dir=forward]; RuntimeException -> NoSuchElementException; } Exception -> RuntimeException; RuntimeException -> { IllegalArgumentException ; IndexOutOfBoundsException ; }; IllegalArgumentException -> { NumberFormatException; } IndexOutOfBoundsException -> { ArrayIndexOutOfBoundsException } } } }
} catch (Exception e) {}
est une TRÈS TRÈS TRÈS mauvaise idée

Principes de Conception
Orientée Objet

Motifs de conception

  • ingle Responsibility
    responsabilité unique
  • pen/Closed
    ouvert/fermé
  • iskov Substitution
    substitution
  • nterface Segregation
    ségrégation
  • ependency Inversion
    inversion des dépendances

  •  ⓈⓄⓁⒾⒹ
    robustesse    

ingle Responsibility

Principe de responsabilité unique

Un acteur doit avoir une et une seule responsabilité
Une classe doit avoir une et une seule raison de changer

pen/Closed

Principe Ouvert/Fermé

Une classe doit être à la fois
ouverte à l'extension
et fermée à la modification

iskov Substitution

Principe de substitution de Liskov

Tout objet doit pouvoir être remplacé
par un autre d'un sous-type

nterface Segregation

Ségrégation des interfaces

préférer plusieurs interfaces spécifiques
pour chaque client plutôt qu'une seule interface générale

ependency Inversion

Inversion des dépendances

il faut dépendre des abstractions, pas des implémentations

Notions Supplémentaires

Introspection java.lang.reflect

digraph umlReflect {
  bgcolor=transparent
  id="\G"
  concentrate=true
  scale=.5
  node [ fontname = "Courier", fontsize = 10, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  Object [ shape=plain,label=<
Object
+getClass()
> ] { rank=same; Class [ shape=plain,label=<
Class
+forName(String)
+getSuperclass() +getInterfaces()
+getName() +getSimpleName()
+getPackage()
+getFields() +getField(String nom)
+getMethods() +getMethod(String nom,Class… args)
+getConstructors() +getConstructor(Class… args)
> ] Executable [ shape=plain,label=<
Executable
+getName()
+getParameters()
+getParameterCount()
+getParameterTypes()
+getExceptionTypes()
> ] } { rank=same; AccessibleObject Member [ shape=plain,label=<
Member
+getName()
+getDeclaringClass()
> ] Member -> AccessibleObject [style="invis"] } Class -> Executable [style="invis"] { rank=same; Constructor [ shape=plain,label=<
Constructor
+newInstance(Object… args)
> ] Method [ shape=plain,label=<
Method
+getReturnType()
+invoke(Object obj, Object… args)
> ] Field [ shape=plain,label=<
Field
+getType()
+get(Object obj)
+set(Object obj, Object value)
> ] Constructor -> Method -> Field [style="invis"] } { edge [arrowtail=empty, dir=back]; Type -> Class [style=dashed]; AccessibleObject -> { Executable, Field }; Executable -> { Method, Constructor }; Member -> { Executable, Field } [style=dashed]; } Object -> Class [arrowtail=odiamond, dir=back]; Class -> Class [arrowtail=odiamond, dir=back, headlabel="1"]; Class -> Class [arrowtail=odiamond, dir=back, headlabel="*"]; { edge [arrowtail=diamond, dir=back]; Class -> Constructor; Class -> Method; Class -> Field; } }

Generiques

Generiques

Generiques

Boucles


           public static void main(String[] args) {
             Eau[] eaux = { … };
             for(Eau eau: eaux)
               System.out.println(eau.getEtatφ());
           }
           

           public static void main(String[] args) {
             Eau[] eaux = { … };
             for(int i=0; i<eaux.length; i++)
             {
               Eau eau = eaux[i];
               System.out.println(eau.getEtatφ());
             }
           }
           

           public static void main(String[] args) {
             Eau[] eaux = { … };
             int i=0; // démarrer itération
             while(i<eaux.length) // tant qu'il y en a
             {
               Eau eau = eaux[i++]; // obtenir le suivant
               System.out.println(eau.getEtatφ());
             }
           }
           

Boucles

digraph umlReflect {
  bgcolor=transparent
  id="\G"
  concentrate=true
  scale=.5
  node [ fontname = "Courier", fontsize = 10, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  
  ParcourirTableau [ shape=plain,label=<
ParcourirTableau
-eaux:Eau[]
-i:int
+isFini():boolean
+suivant():Eau
> ] Eau [ shape=plain,label=<
Eau
+getEtatφ()
> ] Eau -> ParcourirTableau [taillabel="*",arrowhead="odiamond"] }

Boucles

digraph umlReflect {
  bgcolor=transparent
  id="\G"
  concentrate=true
  scale=.5
  node [ fontname = "Courier", fontsize = 10, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  { rank=same;
  Tableau [ shape=plain,label=<
Tableau
-eaux:Eau[]
> ] Parcourir [ shape=plain,label=<
Parcourir
-i:int
+isFini():boolean
+suivant():Eau
> ] Tableau -> Parcourir [arrowhead="vee",label="+parcourir()",style="dashed"]; Tableau -> Parcourir [arrowhead="diamond",label=" "]; } Eau [ shape=plain,label=<
Eau
+getEtatφ()
> ] Eau -> Tableau [taillabel="*",arrowhead="odiamond"] }

Iterable / Iterator

digraph umlReflect {
  bgcolor=transparent
  id="\G"
  concentrate=true
  scale=.5
  node [ fontname = "Courier", fontsize = 10, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  { rank=same;
  Iterable [ shape=plain,label=<
Iterable‹Eau›
> ] Iterator [ shape=plain,label=<
Iterator‹Eau›
+hasNext()
+next()
> ] Iterable -> Iterator [arrowhead="vee",label="+iterator()",style="dashed"]; } { rank=same; Eau [ shape=plain,label=<
Eau
+getEtatφ()
> ] Eaux [ shape=plain,label=<
Eaux
-eaux:Eau[]
> ] Parcourir [ shape=plain,label=<
Parcourir
-i:int
> ] Eaux -> Parcourir [arrowhead="diamond",color=gray]; } Eau -> Eaux [taillabel="*",arrowhead="odiamond"] Iterable -> Eaux [arrowtail="empty",dir="back",style="dashed"]; Iterator -> Parcourir [arrowtail="empty",dir="back",style="dashed"]; }

Iterable / Iterator

digraph umlReflect {
  bgcolor=transparent
  id="\G"
  concentrate=true
  scale=.5
  node [ fontname = "Courier", fontsize = 10, shape = "record", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  { rank=same;
  Iterable [ shape=plain,label=<
Iterable‹Eau›
> ] Iterator [ shape=plain,label=<
Iterator‹Eau›
+hasNext()
+next()
> ] Iterable -> Iterator [arrowhead="vee",label="+iterator()",style="dashed"]; } { rank=same; EauxPlage [ shape=plain,label=<
EauxPlage
-départ,incr,fin:double
> ] Parcourir [ shape=plain,label=<
Parcourir
-temp:double
> ] EauxPlage -> Parcourir [arrowhead="diamond",color=gray]; } Eau [ shape=plain,label=<
Eau
+getEtatφ()
> ] Iterable -> EauxPlage [arrowtail="empty",dir="back",style="dashed"]; Iterator -> Parcourir [arrowtail="empty",dir="back",style="dashed"]; Parcourir -> Eau [headlabel="*",arrowhead="vee"] }

Iterable / Iterator

digraph umlReflect {
  bgcolor=transparent
  id="\G"
  concentrate=false
  scale=.5
  node [ fontname = "Courier", fontsize = 10, shape = "box", id="\G-\N", style=filled ]
  edge [ fontname = "Brill", id="\G-\E" ]
  { rank=same;
  Iterator [ shape=plain,label=<
Iterator
+hasNext()
+next()
> ] Iterable -> Iterator [arrowhead="vee",label="+iterator()",style="dashed"]; } { rank=same; Premiers -> PremiersIter [arrowhead="vee",label="+iterator()",style="dashed"]; } Iterable -> Premiers [arrowtail="empty",dir="back",style="dashed",label=""]; Premiers -> Iterable [arrowtail="odiamond",dir="back",style="solid"]; Iterator -> PremiersIter [arrowtail="empty",dir="back",style="dashed"]; PremiersIter -> Iterator [arrowtail="odiamond",dir="back"]; Infini -> Iterator [arrowhead="empty",style="dashed",color=White] }

Collections

Collections

Collections

Collections

Annexes

Bibliographie

Introductions à Java & POO
  • Java in a Nutshell 6ᵗʰ ed
    2014 –
    978-1-4493-7082-4/978-1-4493-7081-7
  • Java en concentré 5ᵉ ed
    2006 –
    978-2-84177-371-8
  • Head First Object‑Oriented Analysis & Design
    2006 –
    978-0596008673
  • Analyse et conception orientées objet
    Tête la première

    2007 –
    978-2841774319
Pour aller plus loin
  • Head First Design Patterns
    2004 / 2014 –
    978-0-596-00712-6/978-0-596-55656-3
  • Design Patterns – Tête la première
    2005 –
    978-2-84177-350-3
  • Head First Servlets & JSP 2ⁿᵈ ed
    2008 –
    978-0-596-00540-5/978-0-596-55633-4
  • Design Patterns: Elements of Reusable Object-Oriented SoftwareGoF
    1994 – Addison&Wesley
    1999 – Vuibert (traduction)

Javadoc

  • Les spécifications s'expriment dans un format/outillage appelé “javadoc” :
  • s'écrit avant les classes/méthodes/membres en commentaire commençant par deux étoiles
    /** … */

    (l'étoile des lignes suivantes est ignorée)
  • en HTML agrémenté de tag spécifiques
    • block tags :
      @param …
    • inline tags :
      {@code …}
  • l'outil
    javadoc
    produit un site web
  • exploité directement par les IDE

Javadoc

Packages

Afin d'organiser les classes, on dispose de la notion de package :
  • un package est nommé comme en DNS mais à l'envers :
    • commence avec un prefixe : fr.unistra par ex
    • suivi d'identifants regrouppant les ≠ parties
      fr.unistra.monapplication.model, fr.unistra.monapplication.api, …
  • chaque fichier source doit préciser son emplacement au début :
    
    package fr.unistra.eau.model;
    import fr.unistra.eau.api.Etatφ;
    class EauChaude extends Temperature implements Etatφ { … }
           	      
  • et se situer dans un sous-répertoire pour chaque element
    fr/unistra/eau/model

Visibilité

Classe Package Classe
fille
le reste
du monde
private
protected
public

Compléments

Automatisation de la compilation & construction

Make

Apache ANT

MakefileCC = gcc

all: prog

prog: main.o module1.o module2.o
	$(CC) -g -lm -o $@ $^

%.o: %c
	$(CC) -o $@ -c $<

clean:
	rm -f prog *.o

.PHONY: all clean
build.xml

  
    <javac srcdir="." destdir="."/>
  

  
    
      <fileset file="prog" />
      <fileset dir="." includes="**/*.class" />
    
  

„Write once, run anywhere”

Principe CoC : Convention Over Configuration

Apache ANT

script
build.xml

  
    <javac srcdir="." destdir="." />
  

  
    
      <fileset file="prog" />
      <fileset dir="." includes="**/*.class" />
    
  

Apache

description
pom.xml<project>
  <modelVersion>4.0.0</modelVersion>

  <groupId>fr.unistra.app</groupId>
  <artifactId>mon-projet</artifactId>
  <version>1</version>
</project>
convention
  • src/main/java
  • src/main/resources
  • src/test/java
  • src/test/resources
  • target/classes
  • target/mon-projet-1.jar

Principe CoC : Convention Over Configuration

Apache

Project Object Model (XML)
pom.xml<project>
  <modelVersion>4.0.0</modelVersion>

  <groupId>fr.unistra.app</groupId>
  <artifactId>mon-projet</artifactId>
  <version>1</version>
</project>
digraph mavenLifecycle {
  bgcolor=transparent
  id="\G"
  concentrate=true
  node [ fontname = "Courier", fontsize = 12, id="\G-\N", shape=plain, style=filled, fillcolor=ivory ]
  edge [ fontname = "Brill", id="\G-\E", arrowhead=inv, arrowsize=.6]

  { rank = same
    compile -> clean [style=invis];
  }
  compile -> test -> package;
  { rank = same;
    package -> verify;
  }
  deploy -> install -> verify [ dir = back, arrowtail=inv];

}

Gradle

DSL groovy
build.gradleplugins {
    id 'application'
}

version = '1.0.0'

application {
    mainClassName = 'fr.unistra.app.Programme'
}

task helloWorld() {
  doLast {
    println 'Hello World'
  }
}
digraph gradleLifecycle {
  bgcolor=transparent
  id="\G"
  concentrate=true
  rankdir=LR
  ranksep=0.2
  nodesep=0.2
  node [ fontname = "Courier", fontsize = 12, id="\G-\N", shape=plain, style=filled, fillcolor=ivory ]
  edge [ fontname = "Brill", id="\G-\E", arrowtail=inv, dir=back, arrowsize=.6]

  { rank = same;
    clean -> build [style=invis];
  }
  build -> check -> test -> { classes; testClasses };
  build -> assemble -> jar -> classes;
  { rank = same;
    compileTestJava [fontsize = 8];
    compileJava [fontsize = 8];
    testClasses -> classes -> compileJava;
    compileTestJava -> testClasses [dir=forward, arrowhead=inv]
  }
    processTestResources [fontsize=8];
    processResources [fontsize=8];
    classes -> processResources
    compileTestJava -> processTestResources [style=invis]
    processTestResources -> testClasses [dir=forward, arrowhead=inv]
    compileJava -> processResources [style=invis]
  run [fillcolor=palegreen];
  run -> classes;
  javadoc -> classes;
  run -> javadoc [style=invis];
  distZip [fillcolor=palegreen, fontsize=8];
  distZip -> jar;
  startScripts [fillcolor=palegreen, fontsize=6];
  startScripts -> distZip [dir=forward, arrowhead=inv];

}

JAR — Java Archive

Le format d'archive utilisé par java est le format ZIP.

  • .jar regroupe la plupart du temps des fichier bytecode .class
    • pris en charge directement par le ClassLoader
      java -jar prog.jar fr.unistra.Programme
    • le fichier META-INF/MANIFEST.MF porte des méta données
      par ex.  Main-Class: fr.unistra.Programme
    • peut aussi rassembler des fichier source .java
      ou de la documentation javadoc générée (.html)
  • .war ou Web Archive : destiné à déployer des applications web
    au sein d'un conteneur de servlets J2EE (Tomcat, Jetty, GlassFish, JBoss, WebSphere, …)
    • WEB-INF/web.xml configure le déploiement
    • WEB-INF/classes contient les fichiers bytecode .class
    • WEB-INF/lib contient les .jar chargés par le ClassLoader
    • les reste est majoritairement des ressources
      comme des JavaServer Pages (JSP) par exemple.
  • l'outil en ligne de commande
    jar
    permet de manipuler des java archives
    avec une syntaxe similaire à la commande
    tar

Entrepôt (repository)

pom.xml<project>
  <modelVersion>4.0.0</modelVersion>

  <groupId>fr.unistra.app</groupId>
  <artifactId>mon-projet</artifactId>
  <version>1</version>

  <dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>libphonenumber</artifactId>
    <version>8.12.18</version>
  </dependency>
</project>
build.gradleplugins {
  id 'application'
}

version = '1.0.0'

repositories {
    mavenCentral()
}

dependencies {
  implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.18'
}

application {
  mainClassName = 'fr.unistra.app.Programme'
}