Java avancé
Transcription
Java avancé
Java avancé Modèle d'exécution Modèle d'exécution en mémoire ● Différents types de mémoire d'un programme – Données read-only : ● – données r/w : ● – variables globales. Pile : ● ● – code du programme, constantes une par thread exécute opération courante Tas : ● objets alloués (par malloc ou new) Allocation en Java ● ● ● En Java, les variables locales (variables de types primitifs et références) sont allouées sur la pile (ou dans les registres) et les objets dans le tas. Le développeur ne contrôle pas la zone d'allocation ni quand sera effectuée la désallocation. En C++, il est possible d'allouer des objets sur la pile, pas en Java. Sur la pile ● ● La pile, l'ensemble des valeurs courantes d'une exécution : Sur la pile : – Un type primitif est manipulé par sa valeur (sur 32bits ou 64bits) – Un type objet est manipulé par sa référence Pile int i; Point p; i=3; p=new Point(); i 3 p Variables locales Tas Point La référence null ● Java possède une référence spéciale null, qui correspond à aucune référence. Point p; p=null; Holder h; h=null; System.out.println(p.x); // lève une exception NullPointerException ● ● null est une référence de n'importe quel type null instanceof Truc renvoie toujours faux Référence != Pointeur ● ● Une référence (Java) est une adresse d'un objet en mémoire Un pointeur (C) est une référence plus une arithmétique associée Point p; // Java p=new Point(); p++; // illegal Point *p; p=new Point(); p++; // legal // C ● Une référence ne permet pas de parcourir la mémoire, ● elle pointe toujours soit sur un objet, soit est null. Variable et type ● Simulons l'exécution du code : int i=3; int j=i; j=4; Truck t=new Truck(); t.wheel=3; Truck u=t; u.wheel=4; ● Variables locales i 3 j 43 champs wheel 4 3 Variables locales t u u contient la même référence que t. Passage de paramètres ● Les paramètres sont passés par copie private static void f(int i,String s,Truck t) { i=4; s="toto"; t.wheel=3; Variables locales t=new Truck(); i 4 2 } ss t ● Les objets sont manipulés par des références copiées public static void main(String[] args) { String arg="zut"; int value=2; Truck truck=new Truck(); f(value,arg,truck); System.out.printf("%d %s %h %d\n", value,arg,truck,truck.wheel); } toto wheel wheel 3 0 Variables locales arg value truck 0 2 zut Objets mutables et non mutables ● ● Une objet est mutable s'il est possible de modifier son état après sa création Sinon il est non-mutable – champs final ou privés sans setter pour les types primitifs – méthode ne permettant que la consultation – objets levant une exception quand on essaye de les modifier (e.g. Collection.unmodifiable*) Objets mutables et non mutables public class Point { private final int x,y; public int getX() {return x;} public int getY() {return y;} } public class UnmutableList { private final ArrayList<String> list; public String get(int index) { return list.get(index); } public class UnmutableList<T> implements List<T> { public boolean add(T member) { throw new UnsupportedOperationException(); } } Objets mutables et non mutables ● Pour effectuer des opérations sur les objets non mutable, il faut créer un nouvel objet: String name = "JULIETTE"; String lowName = name.toLowerCase(); String entry = name.replace('T','N'); System.out.println(name) // JULIETTE System.out.println(lowName) // juliette System.out.println(entry) // JULIENNE ● L'objet « chaîne de caractères mutable » est l'objet StringBuilder Protection des données ● ● En fournissant une référence en appelant une méthode ou comme valeur de retour, ou acceptant une référence en étant appelé, on prend le risque que l'objet appelant modifie la valeur de l'objet pendant ou après l'appel de la méthode Pour palier cela – passer une copie/effectuer une copie de l'argument (lourd, surtout si l'objet extérieur fait de même) – passer/accepter un objet non mutable (lourd, surtout si les données changent souvent) Tests d'égalité ● Les opérateurs de comparaison == et != testent les valeurs des variables : – Pour les types primitifs, on test leurs valeurs – Pour les types objets, on test les valeurs des références Truck a=new Truck b=a; Truck a; Truck(); b; c=new Truck(); a==b; // true b==c; // false a==c; // false Variables locales a b c wheel 4 wheel 4 Tests d'égalité ● ● ● Pour comparer sémantiquement deux objets, la classe correspondante doit redéfinir la méthode Object.equals(Object) La méthode equals de Object teste les références La plupart des classes de données de l'API redéfinissent la méthode equals Point a; a=new Point(2,2); Point b=new Point(2,2); a.equals(b); // true a==b; // false Tests d'égalité ● ● ● Tout objet redéfinissant equals doit redéfinir hashcode si l'objet doit être utilisé dans les collections basées sur un hachage (donc tout le temps) equals doit être symétrique, transitive, réflexive, et ne doit pas lever d'exception. Éviter de surcharger equals class Point { private final int x,y; @Override public boolean equals(Object o) { if (! (o instanceof Point)) return false; Point p = (Point)o; return x==p.x && y==p.y // accès aux champs privés // d'une autre instance } } Tests d'égalité ● equals et hashcode doivent vérifier – ● ● ● x.equals(y) implique x.hashcode()==y.hashcode() les valeurs de hashcode doivent de préférence être différentes pour les valeurs des objets utilisés par le programme hashcode ne doit pas changer si l'objet ne change pas (et il ne doit pas changer pendant qu'il est dans une collection) hashcode doit être rapide à calculer (éventuellement précalculée pour les objets non mutables). hashcode class Point { private final int x,y; @Override public boolean equals(Object o) { if (! (o instanceof Point)) return false; Point p = (Point)o; return x==p.x && y==p.y } /* mauvais hashcode : @Override public int hashcode() { return x-y; } */ } @Override public int hashcode() { return x^Integer.reverseBytes(y); } Désallocation en Java ● ● ● ● Les objets qui ne sont plus référencés vont être collectés (plus tard) par le GC pour que leur emplacement mémoire soit réutilisé. Façons d'avoir un objet non référencé : – Si on assigne une nouvelle référence à une variable (l'ancienne référence “meurt”) – Si l'on sort d'un bloc, les variables locales “meurent”. Il faut qu'il n'y ait plus aucune référence sur un objet pour qu'il puisse être réclamé Mécanisme de références faibles. Désallocation en Java ● Un objet sera réclamé par le GC si aucune référence sur lui ne persiste. { Point p; p=new Point(); { Point p; p=new Point(); } p=null; } Pile p ● @Point Point p2; p2=p; p=null; Pile p p2 @Point Penser à mettre les références des gros objets à null quand ils ne sont plus utilisés (pas la peine de mettre leurs champs à null)