public class Test2 {
  /*
   * Cette "variable" est d'un type particulier. Puisqu'il s'agit d'une
   * constante (une variable qui ne peut changer de valeur), le compilateur
   * s'autorise à ne jamais faire référence à cette variable comme d'ordinaire
   * mais à en oublier le contenant pour ne plus utiliser que le contenu qui 
   * réside alors, à chaque utilisation, dans le code.
   */
  public static final int C = 100;
  /*
   * Cette variable a aussi un statut particulier. Elle préexiste avant l'appel
    * à main et réside donc dans une zone particulière, la zone des
    * variables statiques, distincte de la pile et du tas.
   */
  public static int v = 777;

  /*
   * Le passage d'argument est effectué par valeur. La variable x n'a rien
   * de particulier, concernant son existence, par rapport à la variable
   * locale y. Toutes les deux sont locales et résident dans la pile.
   * La différence réside dans l'initialisation, opération dans laquelle
   * le paramètre x est initialisé lors de l'appel à la fonction avec la
   * valeur du paramètre transmis. Les deux variables résident dans la pile.
   * Les variables locales sont créés lors de chaque appel à la fonction et
   * disparraissent lorsque le contrôle sort de la fonction.
   */
  public static void f(int x) {
    int y = 10;
    System.out.println(x);
    System.out.println(v);
    x = 9999;
    System.out.println("dans f() "+x);
  }

  /* Le passage d'argument est aussi par valeur (ou copie). On créé la variable
   * locale t initialisée avec la valeur du paramètre fourni à l'appel. La
   * différence réside dans le fait que l'objet qui est pointé par t est lui
   * "global" car son existence n'est pas liée à l'appel de cette fonction (a
   * priori), il existe par ailleurs (dans le tas) et est manipulé via une
   * nouvelle référence temporaire. Bien entendu toute modification de l'objet
   * pointé est visible par ailleurs...
   */
  public static void f(int []t) {
    System.out.println(t[0]);
    t[0] = 8888;
    System.out.println(t[0]);
  }

  /*
   * On peut donc dire enfin que main est une fonction comme une autre, elle
   * n'a aucune particularité en tant que fonction. La seule particularité
   * est celle de l'exécution des programmes qui commencent toujours (a priori)
   * par un appel initia à main.
   */
  public static void main(String []args) {
    System.out.println(args[0]);

    /*
     * Deux références vers un même objet. La modification du tableau via
     * l'une est visible de l'autre évidemment.
     */
    int []t = new int[5];
    int []t2;
    t2 = t;
    t[0] = 333;
    System.out.println(t[0]);
    System.out.println(t2[0]);

    // L'objet est recyclé lrosque les deux références ne pointent plus vers
    // l'objet.
    /*
      t = null;
      System.out.println(t2[0]);
      t2 = null;
    */
    
    int a = 666+C;
    int b = 766;

    /*
     * L'égalité est celle des valeurs de la variable. Pas de particularité
     * pour les types primitifs.
     */
    if (a==b) { System.out.println("vrai"); }
    else { System.out.println("faux"); }

    /*
     * Ici c'est la même chose. On compare le contenu des références, par
     * conséquent on teste si les deux références désignent ou non le
     * même objet.
     */
    if (t==t2) { System.out.println("vrai"); } 
    else { System.out.println("faux"); }
    
    t2 = new int[5];
    t2[0] = 333;
    
    if (t==t2) { System.out.println("vrai"); } 
    else { System.out.println("faux"); }

    /*
     * Un appel effectué avec la valeur de la variable a à ce moment.
     */
    f(a);
    System.out.println("apres f() "+a);
    /*
     * Un appel effectué avec une constante. On ne passe pas un lvalue...
     */
    f(500);
    
    /*
     * On passe la valeur de la référence. L'objet peut être modifié par
     * la fonction et l'effet est visible. Mais il est impossible que la
     * fonction modifie t elle-même.
     */
    f(t);
    System.out.println("apres f() "+t[0]);

    /*
     * Les tableaux à deux dimensions n'en sont pas. Il s'agit de référence
     * vers un tableau de références vers des tableaux d'entiers.
     */
    int [][]tab = new int[3][5];
    tab[0][3];
  }
}