diff --git a/TP1/Java/Analyzer.java b/TP1/Java/Analyzer.java
new file mode 100644
index 0000000000000000000000000000000000000000..53cffadb583c29be7d8636f391b402ecd2cb677f
--- /dev/null
+++ b/TP1/Java/Analyzer.java
@@ -0,0 +1,132 @@
+import java.io.*;
+import java.util.ArrayList;
+
+/**
+    Classe utilisée pour faire des statistiques élémentaires
+    sur une séquence d'opérations.
+ */
+public class Analyzer {
+
+    /**
+        Constructeur de la classe analyse
+        Complexité en temps/espace, pire et meilleur cas : O(1)
+     */
+    public Analyzer() {
+        cost = new ArrayList<Double>();
+        cumulative_cost = new ArrayList<Double>();
+        cumulative_square = 0.;
+    }
+
+    /**
+        Ajoute un coût, une valeur à l'analyse.
+        Complexité en temps/espace, pire cas : O(size)
+        Complexité en temps/espace, meilleur cas : O(1)
+        Complexité amortie : O(1)
+        @param x est la valeur que l'on souhaite ajouter à l'analyse.
+     */
+    void append(double  x){
+        cost.add(x);
+        cumulative_cost.add( (!cumulative_cost.isEmpty()) ? cumulative_cost.get(cumulative_cost.size()-1)+x : x);
+        cumulative_square += x*x;
+    }
+
+    /**
+        Renvoie la somme des coûts enregistrés dans cette analyse.
+        Complexité en temps/espace, meilleur cas : O(1)
+        @returns la somme des coûts enregistrés dans cette analyse.
+     */
+    double get_total_cost(){
+        return cumulative_cost.get(cumulative_cost.size()-1);
+    }
+
+    /**
+        Renvoie le coût amorti d'une opération.
+        Complexité en temps/espace, meilleur cas : O(1)
+        @param pos est l'indice de l'opération pour laquelle on veut connaître le coût amorti.
+        @returns le coût amorti d'une opération.
+     */
+    double get_amortized_cost(int pos){
+        return (pos > 0)? cumulative_cost.get(pos)/pos : cumulative_cost.get(pos);
+    }
+
+    /**
+        Renvoie la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
+        Complexité en temps/espace, meilleur cas : O(1)
+        @returns la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
+     */
+    double get_average_cost(){
+        if(cumulative_cost.isEmpty())
+            throw new RuntimeException("List is empty");
+        return cumulative_cost.get(cumulative_cost.size()-1)/cumulative_cost.size();
+    }
+
+    /**
+        Renvoie la variance des coûts de toutes les opérations enregistrées dans l'analyse.
+        Complexité en temps/espace, meilleur cas : O(1)
+        @returns la variance des coûts de toutes les opérations enregistrées dans l'analyse.
+     */
+    double get_variance(){
+        double mean, mean_square;
+        mean = get_average_cost();
+        mean_square = mean * mean;
+        return cumulative_square - mean_square;
+    }
+
+    /**
+        Renvoie l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
+        Complexité en temps/espace, meilleur cas : O(1)
+        @returns l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
+     */
+    double get_standard_deviation(){
+        return Math.sqrt(get_variance());
+    }
+
+    /**
+        Sauvegarde la liste des coûts et des coûts amortis dans un fichier.
+        Complexité en temps, meilleur/pire cas : O(size)
+        @param path est le chemin du fichier dans lequel la sauvegarde est faite.
+     */
+    void save_values(String path){
+        int i;
+        File file = new File(path);
+        FileWriter fr = null;
+        try {
+            fr = new FileWriter(file);
+            for (i = 0; i < cost.size(); ++i){
+                fr.write(i+" "+cost.get(i)+" "+get_amortized_cost(i)+"\n");
+            }
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }finally{
+            //close resources
+            try {
+                fr.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+        Affiche la liste des coûts et des coûts amortis sur la sortie standard.
+        Complexité en temps, meilleur/pire cas : O(size)
+     */
+    void plot_values(){
+        int i;
+        for (i = 0; i < cost.size(); ++i){
+            System.out.println(i+" "+cost.get(i)+" "+get_amortized_cost(i));
+        }
+    }
+
+
+    // Coût de chaque opération. Peut représenter du temps ou une autre mesure.
+    private ArrayList<Double> cost;
+    // Coût cumulatif. La case i contient la somme des coûts des i premières opérations.
+    // Permet de calculer le coût amorti d'une opération.
+    private ArrayList<Double> cumulative_cost;
+    // Carré du coût cumulatif. Sert à calculer la variance. On ne garde que la dernière valeur.
+    private double cumulative_square;
+
+
+}
diff --git a/TP1/Java/ArrayListProxy.java b/TP1/Java/ArrayListProxy.java
new file mode 100644
index 0000000000000000000000000000000000000000..33a69553e80d945f48de97adba2602e79258ee52
--- /dev/null
+++ b/TP1/Java/ArrayListProxy.java
@@ -0,0 +1,96 @@
+import java.util.ArrayList;
+
+/**
+ Cette classe est un proxy pour les ArrayList, c'est à dire les tableaux dynamiques en Java.
+ On utilise cette classe afin d'avoir le contrôle sur la gestion de la mémoire.
+ */
+public class ArrayListProxy<T> {
+
+    /**
+        Constructeur de la classe des tableaux dynamiques.
+        Complexité en temps/espace, pire et meilleur cas : O(1)
+     */
+    public ArrayListProxy() {
+        this.capacity = 4;
+        this.data = new ArrayList<T>(this.capacity);
+    }
+
+    /**
+     Ajoute une valeur dans le tableau.
+     Complexité en temps/espace, pire cas : O(size)
+     Complexité en temps/espace, meilleur cas : O(1)
+     Complexité amortie : O(1)
+     @param x est la valeur que l'on souhaite ajouter.
+     @returns true si le tableau a été agrandit, false sinon
+     */
+    boolean append(T x){
+        boolean memory_allocation = false;
+        if( enlarging_capacity() ){
+            memory_allocation = true;
+            capacity *= 2;
+            data.ensureCapacity( capacity );
+        }
+        data.add(x);
+        return memory_allocation;
+    }
+
+    /**
+     Supprime la dernière valeur du tableau.
+     Complexité en temps, pire cas : O(size)
+     Complexité en temps, meilleur cas : O(1)
+     Complexité amortie : O(1)
+     @returns true si le tableau a été réduit, false sinon
+     */
+    boolean pop_back(){
+        boolean memory_reduction = false;
+        if(!data.isEmpty()){
+            if( reducing_capacity() ){
+                memory_reduction = true;
+                capacity /= 2;
+                data.ensureCapacity( capacity );
+            }
+            data.remove(data.size()-1);
+        }
+        return memory_reduction;
+    }
+
+    /**
+     Renvoie la valeur située à la position donnée par l'utilisateur.
+     Complexité en temps/espace, pire cas : O(1)
+     @param pos est la l'indice de la case on l'utilisateur veut connaître la valeur.
+     @returns la valeur située à la position donnée par l'utilisateur.
+     */
+    T get(int pos){
+        return data.get(pos);
+    }
+
+    /**
+     Renvoie le nombre d'éléments stockés dans le tableau.
+     Complexité en temps/espace, pire cas : O(1)
+     @returns le nombre d'éléments stockés dans le tableau.
+     */
+    int get_size(){
+        return data.size();
+    }
+
+    /**
+     Cette fonction détermine la règle selon laquelle un espace mémoire plus grand sera alloué ou non.
+     @returns true si le tableau doit être agrandi, false sinon.
+     */
+    private boolean enlarging_capacity() {
+        return data.size() >= (capacity * 3)/4;
+    }
+
+    /**
+     Cette fonction détermine la règle selon laquelle un espace mémoire plus petit sera alloué ou non.
+     @returns true si le tableau doit être réduit, false sinon.
+     */
+    private boolean reducing_capacity(){
+        return data.size() <= capacity/4 && data.size() >4;
+    }
+
+    // Tableau dynamique en Java. Sa capacité réelle est masquée, mais on peut avoir un contrôle dessus.
+    private ArrayList<T> data;
+    // Capacité réelle du tableau data.
+    private int capacity;
+}
\ No newline at end of file
diff --git a/TP1/Java/Main.java b/TP1/Java/Main.java
new file mode 100644
index 0000000000000000000000000000000000000000..f504dd54684a2253a6fb13be0469b0f230a4da13
--- /dev/null
+++ b/TP1/Java/Main.java
@@ -0,0 +1,42 @@
+import java.util.Random;
+
+public class Main {
+
+    public static void main(String[] args) {
+        int i, time_ind = 0, pop_ind = 0;
+        // Tableau dynamique.
+        ArrayListProxy<Integer> a = new ArrayListProxy<Integer>();
+        // Analyse du temps pris par les opérations.
+        Analyzer time_analysis = new Analyzer();
+        // Analyse du nombre de copies faites par les opérations.
+        Analyzer copy_analysis = new Analyzer();
+        long before, after;
+        // Booléen permettant de savoir si une allocation a été effectuée.
+        boolean memory_allocation;
+
+
+        for(i = 0; i < 1000000 ; i++){
+            // Ajout d'un élément et mesure du temps pris par l'opération.
+            before = System.nanoTime();
+            memory_allocation = a.append(i);
+            after = System.nanoTime();
+
+            // Enregistrement du temps pris par l'opération
+            time_analysis.append(after - before);
+            // Enregistrement du nombre de copies efféctuées par l'opération.
+            // S'il y a eu réallocation de mémoire, il a fallu recopier tout le tableau.
+            copy_analysis.append( (memory_allocation == true)? i: 1);
+        }
+
+        // Affichage de quelques statistiques sur l'expérience.
+        System.err.println("Total cost : "+time_analysis.get_total_cost());
+        System.err.println("Average cost : "+time_analysis.get_average_cost());
+        System.err.println("Variance :"+time_analysis.get_variance());
+        System.err.println("Standard deviation :"+time_analysis.get_standard_deviation());
+
+        // Sauvegarde les données de l'expérience: temps et nombre de copies effectuées par opération.
+        time_analysis.save_values("../dynamic_array_time_java.plot");
+        copy_analysis.save_values("../dynamic_array_copy_java.plot");
+
+    }
+}