Les types primitifs et types références

Manipuler les references

Une variable r´ef´erence contient une adresse vers un objet d’un certain type. Comme toute autre variable, on peut lui donner une valeur par affectation. Comme Java est typ´e, on ne peut lui donner qu’une valeur de mˆeme type, c’est a` dire une adresse vers un objet de mˆeme type. Mais nous ne connaissons pas explicitement les adresses, donc les deux seules fac¸ons de donner une valeur a` une variable r´ef´erence sont d’utiliser new, comme nous venons de le voir, ou de lui affecter la valeur d’une autre variable r´ef´erence de mˆeme type.
A la suite des 2 premi`eres instructions, nous avons 2 r´ef´ rences et 2 objets. En ligne 3, nous avons 3 r´ef´erences mais seulement 2 objets : d3, prend comme valeur celle de d2, donc l’adresse de l’objet2. d2 et d3 r´ef´erencent le mˆeme objet. Ce sont deux fac¸ons diff´ere ntes d’acc´eder au mˆeme objet. En ligne 4, nous avons toujours 3 r´ef´erences et 2 objets : d2 prends maintenant l’adresse de l’objet1. d1 et d2 r´ef´erencent le mˆeme objet.

Manipuler les objets references

Une variable r´ef´erence contient une adresse, un moyen d’a cc´eder a` un objet, pas l’objet lui mˆeme.
Mais comment acc´eder via la variable a` cet objet et comment le modifier ? Nous le savons d´ej`a : par la notation point´ee.
Si d1 est une variable qui r´ef´erence une date, sa valeur est une a dresse, mais d1. d´esigne l’objet date qu’elle r´ef´erence. Nous pouvons ainsi lui appliquer toutes les m´ethodes des dates et acc´eder au variables d’instances jour, mois, annee :
1 p u b l i c c l a s s C h a p 1 2 a {
2 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [ ] a r g s ) {
3 D a t e d 1 = new D a t e ( ) ;
4 d 1 . a f f i c h e r D a t e ( ) ;
5 d 1 . l e n d e m a i n ( ) ;
6 d 1 . j o u r = d 1 . j o u r + 1 ;
7 T e r m i n a l . e c r i r e S t r i n g l n ( ” Annee ” + d 1 . a n n e e ) ;
8 }
9 }

Attention au partage des donnees

Nous avons vu que plusieurs variables peuvent r´ef´erencer le mˆeme objet. Lorsque c’est le cas, le mˆeme objet est accessible (et donc modifiable) par l’inte rm´ediaire de chacune des variables qui le r´ef´erencent :
1 p u b l i c c l a s s Ch a p 1 2 b {
2 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [ ] a r g s ) {
3 D a t e d 1 = new D a t e ( 1 , 6 , 1 9 9 8 ) ;
4 D a t e d 3 = d 1 ;
5 d 1 . a f f i c h e r D a t e ( ) ;
6 d 3 . a f f i c h e r D a t e ( ) ;
7 d 3 . j o u r = 1 2 ;
8 d 1 . a n n e e = 2006;
9 d 1 . a f f i c h e r D a t e ( ) ;
10 d 3 . a f f i c h e r D a t e ( ) ;
11 }
12 }
Dans ce programme, d1 et d3 r´ef´erencent le mˆeme objet, que l’on modifie par l’interm´ ediaire de l’une et de l’autre. A chaque instant, la date point´ee par d1 et d2 et la mˆeme. C’est le mˆeme objet qu’on modifie que ce soit par l’interm´ediaire de d1 ou de d2.
L’ ex´ecution de ce programme produit donc evidemment´ :
simonot@saturne:> java Chap12b
1,6,1998
1,6,1998
12,6,2006
12,6,2006
Le plus souvent, on ne veut pas que plusieurs variables r´ef´erencent le mˆeme objet, mais on veut qu’elles aient a` un moment donn´e, les mˆemes valeurs. C’es t souvent le cas lors de l’initialisation d’une variable locale par exemple. Dans ce cas, il faut proc´eder par recopie de la valeur des variables d’instances, comme nous l’avons fait pour d2 dans l’exemple qui suit.
1 p u b l i c c l a s s C h a p 1 2 c {
2 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [ ] a r g s ) {
3 D a t e d 1 = new D a t e ( 1 , 6 , 1 9 9 8 ) ;
4 D a t e d 2 = new D a t e ( ) ;
5 D a t e d 3 = d 1 ; / / d 3 e t d 1 r e f e r e n c e n t l e meme o b j e t
7 d 2 . j o u r = d 1 . j o u r ;
8 d 2 . a n n e e = d 1 . a n n e e ;
9 d 2 . m o i s = d 1 . m o i s ;
10 / / d 2 r e c o p i e d a n s s a d a t e , l e s v a l e u r s d e l a d a t e r e f e r e n c e e p a r d 1
12 d 1 . a f f i c h e r D a t e ( ) ;
13 d 2 . a f f i c h e r D a t e ( ) ;
14 d 3 . a f f i c h e r D a t e ( ) ;
16 d 2 . j o u r = 1 8 ;
17 d 1 . a f f i c h e r D a t e ( ) ;
18 d 2 . a f f i c h e r D a t e ( ) ;
20 d 3 . j o u r = 1 2 ;
21 d 1 . a n n e e = 2 0 0 6 ;
23 d 1 . a f f i c h e r D a t e ( ) ;
24 d 2 . a f f i c h e r D a t e ( ) ;
25 d 3 . a f f i c h e r D a t e ( ) ;
26 }
27 }
L’ ex´ecution du programme produit donc :
simonot@saturne:> java Chap12c
1,6,1998
1,6,1998
1,6,1998
1,6,1998
18,6,1998
12,6,2006
18,6,1998
12,6,2006

Retour sur l’egalite entre references

Nous pouvons maintenant comprendre le comportement de l’op´erateur d’´egalit´ ==.
L’op´erateur == compare les bits contenus dans les variables. Lorsque les variables sont de types
primitifs (comme n et m), cela teste si les entiers qu’elles contiennent sont les mˆemes. Mais, comme les bits contenus dans les variables r´ef´erences repr´ese ntent des adresses, cela teste si les adresses sont egales,´ c’est a` dire si les variables r´ef´erencent le mˆe me objet.
1 p u b l i c c l a s s Ch a p 1 2 d {
2 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [ ] a r g u m e n t s )
3 {
4 i n t n = 3 ;
5 i n t m = 2 + 1 ;
6 i f (m== n ) {
7 T e r m i n a l . e c r i r e S t r i n g l n ( ” n ==m” ) ;
8 }
9 e l s e {
10 T e r m i n a l . e c r i r e S t r i n g ( ” n ! =m” ) ;
11 }
12 D a t e d 1 = new D a t e ( 1 , 1 , 2 0 0 0 ) ;
13 D a t e d 2 = d 1 ;
14 D a t e d 3 = new D a t e ( 1 , 1 , 2 0 0 0 ) ;
15 i f ( d 1 == d 2 ) {
16 T e r m i n a l . e c r i r e S t r i n g l n ( ” d 1 == d 2 ” ) ;
17 }
18 e l s e {
19 T e r m i n a l . e c r i r e S t r i n g l n ( ” d 1 ! = d 2 ” ) ;
20 }
21 i f ( d 1 == d 3 ) {
22 T e r m i n a l . e c r i r e S t r i n g l n ( ” d 1 == d 3 ” ) ;
23 }
24 e l s e {
25 T e r m i n a l . e c r i r e S t r i n g l n ( ” d 1 ! = d 3 ” ) ;
26 }
27 }
28 }
L’ex´ecution de ce programme produit :
simonot@saturne:> java Chap12d
n==m
d1==d2
d1!=d3
n == m vaut true car n et m contiennent la mˆeme valeur : 3.
d1 == d2 vaut true car d1 et d2 contiennent la mˆeme valeur : l’adresse d’un mˆeme objet.
d1 == d3 vaut false car d1 et d3 contiennent 2 adresses diff´erentes.

LIRE AUSSI :  Java Beans Coding Convention et comment créer un thread ?

Retour sur le passage des parametres

En Java, le passage des param`etres, lors de l’appel d’une m´ethode, se fait par valeur. Nous avons d´ej`a etudi´ cela lors du chapitre sur les sous programme s. Ceci signifie que ce sont les valeurs des arguments d’appel qui sont transmises lors de l’ex´ecution d’un appel de m´ethode. Ce mode de passage des param`etres uniforme induit des comportements diff´er ents suivant que les arguments d’appel sont des variables primitives ou des r´ef´erences. C’est ce que n ous allons detailler maintenant.

Passage par valeur sur des arguments de type primitif

Prenons un exemple simple et d´etaillons les etapes´ de l’execution´ d’un appel de m´ethode.
1 c l a s s P r i m 1 {
2 s t a t i c i n t m1 ( i n t a ) {
3 r e t u r n a ∗ a ;
4 }
5 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [ ] a r g s ) {
6 i n t b = 3 ;
7 T e r m i n a l . e c r i r e I n t l n ( m1 ( b ) ) ;
8 }
9 }
Ex´ecution de m1(b) :
1. La valeur de b est calcul´ee : comme c’est une variable primitive, sa valeur est l’entier qu’elle contient , c’est a` dire 3.
2. De l’espace m´emoire est allou´e pour l’argument a de la m´ethode. a est initialis´ee avec la valeur de b : 3
3. Le corps de m1, ici limit´e a` return a*a est ex´ecut´ : On calcule a*a ce qui donne 9, la valeur de l’appel m1(b) est donc 9. La variable a n’existe plus.
Ainsi, on voit que m1(b) est strictement equivalent´ a` m1(3). On comprends d’autres part que le mode de passage des param`etres par valeur interdit de modifier la valeur des arguments d’appel, lorsqu’ils sont de type primitifs. Prenons un autre exemple :
1 c l a s s P r i m 2 {
2 s t a t i c v o i d m2 ( i n t a ) {
3 a = a ∗ a ;
4 }
5 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [ ] a r g s ) {
6 i n t b = 3 ;
7 ( m2 ( b ) ) ;
8 T e r m i n a l . e c r i r e I n t l n ( b ) ;
9 }
10 }
Cet exemple affiche 3 et non 9, ce qui n’est pas surprenant : le temps de l’execution de l’appel m2(b), une variable locale a, initialisee avec la valeur de b 3, est cree. Le corps de m2 modifie a. en lui donnant 9. A la fin de l’execution de cet appel, a n’existe plus. L’initialisation de a avec la valeur de b est l’unique lien qui existe entre a et b. b n’ est donc pas modifie.

Cours gratuitTélécharger le cours complet

Télécharger aussi :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *