Slu
comment faire pour passer qqchose par reference en java ?
par exemple pour une fonction avec un parametre int que je modifie dans la fonction et que je puisse la recuperer la ou j appelle la fonction.
thx @+
Version imprimable
Slu
comment faire pour passer qqchose par reference en java ?
par exemple pour une fonction avec un parametre int que je modifie dans la fonction et que je puisse la recuperer la ou j appelle la fonction.
thx @+
Un type primitif ne peut être passé par référence.
Tu peux utiliser un tableau d'entier dans lequel tu mets ta valeur, et tu récupères en retour la valeur modifiée, mais ce n'est pas très propre :
ou renvoyer la valeur modifiée en retour de la méthode :Code:
1
2
3 public void incrementerEntier(int[] tableau) { tableau[0] += 1; }
ou passer par un objet dans lequel tu as un attribut de type int :Code:
1
2
3 public int incrementerEntier(int entier) { return entier + 1; }
Code:
1
2
3
4
5
6
7
8
9
10 class Entier { public int i; public Entier(int i) { this.i = i; } } public void incrementerEntier(Entier entier) { entier.i += 1; }
Ah oui en fait j etais pas assez precis ... en fait pour c pour passer plusieurs int ... et donc en recuperer plusieurs ...
Inspire toi du 1er ou du 3ème exemple...
Merci ! 8)
Pour passer un type primitif par reference il y a des classes pour cela : Boolean, Double, Integer, Float... C'est mieux que d'ecrire sa propre classe Entier par exemple.
Salut,
Heu... Ce n'est pas possible puisque ces classes sont immuables...Citation:
Envoyé par Gfx
a++
Je n'ai pas dit le contraire, mais il suffit de changer la reference :
C'est bien ce que l'on fait avec les String tout le temps.Code:
1
2
3
4 public void incrementerEntier(Integer entier) { entier = new Integer(entier.intValue() + 462); }
Justement si tu changes la référence tu ne modifies pas l'objet passé en paramètre, mais tu crées un autre objet qui n'existera pas dans la méthode appellante...
Avec le code suivant :
On obtiens à l'affichage "0"Code:
1
2
3
4
5
6
7
8
9 public static void incrementerEntier(Integer entier) { entier = new Integer(entier.intValue() + 462); } public static void main(String[] args) throws Exception { Integer entier = new Integer(0); incrementerEntier(entier); System.out.println(entier); }
La modification des objets passé par référence ne peut se faire que par des méthodes de la classe (setter ou autre).
Mais comme les types wrappers sont immuable ce n'est pas possible...
a++
Heu oui en effet ^^ Mea culpa j'ai dit n'importe quoi.
ADI !
je passait par la, que veux tu dire quand tu dit qie :
je pensait que c'etait des objet comme les autres avec toutes leur proprieteCitation:
Envoyé par adiGuba
???
WDionysos
Une classe immutable est simplement une classe dont les objets ne changent pas de valeur une fois crees.
Comme quoi ca peut arriver à tout le monde ;)Citation:
Envoyé par Gfx
<mode mauvaise foi>
C'est le jetlag, je suis rentre en Californie hier.
</mode mauvaise foi>
:)))
Moi je croyais qu'en Java tous les paramètres de méthodes étaient passés en valeur, même les références d'objets...
En java tout est passé par référence au contraire. sauf les types primitifs. les types immuables sont d'ailleurs aussi passés par reference, mais vu qu'ils sont immuables... c'est un peu comme s'ils etaient passés par valeur... enfin, en raccourci :wink:
Dans ce cas on devrait pouvoir écrire des méthodes d'échange telles que par exemple :
Pour moi ceci confirme que toutes les variables sont passés par valeur, y compris celles contenant des références d'objets...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 public class Test { public static void swapStringBuffer(StringBuffer s1, StringBuffer s2){ StringBuffer temp = s1; s1 = s2; s2 = temp; } public static void main(String[] args) { StringBuffer s = new StringBuffer("toto"); StringBuffer s2 = new StringBuffer("tata"); System.out.println(s); //s vaut toto System.out.println(s2); //s2 vaut tata Test.swapStringBuffer(s,s2); System.out.println(s); //s vaut toujours toto System.out.println(s2); //s2 vaut toujours tata } }
Si je fais une erreur de raisonnement dites le moi hein, je veux juste comprendre, je prétends pas avoir raison...
Je confirme, pour les objets, ce sont des copies des références qui sont passées.
Par contre ce n'est pas l'objet lui-même qui est passé à la méthode mais bien une référence donc ce n'est pas à proprement parler un passage par valeur.
Certes, c'est bien la référence d'objet qui est passé à la méthode.
Mais bon en java, une variable peut contenir soit une constante primitive (entier, caractère), soit une référence vers un objet.
Ce qui me fait dire que c'est du passage par valeur c'est que quand on utilise la variable dans une méthode, c'est une copie de son contenu qui est transmis ce qui explique que l'on puisse écrire des méthode d'altération d'un objet (puisque l'on possède une copie de la référence vers l'objet) mais pas des méthodes d'échange (objet ou type primitif) ou d'altération d'un type primitif.
Oui je sais c'est ce que j'essaie d'expliquer dans mon message précédent, visiblement moins bien que toi je te l'accorde...
Mais moi j'appelle ça du passage par valeur.
Edit, tiens le message auquel j'ai répondu à disparu!
Bon après quelque recherche sur développez à ce sujet, j'ai trouvé ceci
http://bruce-eckel.developpez.com/li...&page=0#00.005
Et finalement je suis d'accord avec ceci :
Donc en gros tout dépend de la perception qu'on en a.Citation:
Ceci nous amène à discuter terminologie, ce qui est toujours bon dans un débat. Le sens de l'expression « passage par valeur » dépend de la perception qu'on a du fonctionnement du programme. Le sens général est qu'on récupère une copie locale de ce qu'on passe, mais cela est tempéré par notre façon de penser à propos de ce qu'on passe. Deux camps bien distincts s'affrontent quant au sens de « passage par valeur » :
Java passe tout par valeur. Quand on passe un scalaire à une méthode, on obtient une copie distincte de ce scalaire. Quand on passe une référence à une méthode, on obtient une copie de la référence. Ainsi, tous les passages d'arguments se font par valeur. Bien sûr, cela suppose qu'on raisonne en terme de références, mais Java a justement été conçu afin de vous permettre d'ignorer (la plupart du temps) que vous travaillez avec une référence. C'est à dire qu'il permet d'assimiler la référence à « l'objet », car il la déréférence automatiquement lorsqu'on fait un appel à une méthode.
Java passe les scalaires par valeur (pas de contestations sur ce point), mais les objets sont passés par référence. La référence est considérée comme un alias sur l'objet ; on ne pense donc pas passer une référence, mais on se dit plutôt « je passe l'objet ». Comme on n'obtient pas une copie locale de l'objet quand il est passé à une méthode, il est clair que les objets ne sont pas passés par valeur. Sun semble plutôt soutenir ce point de vue, puisque l'un des mot-clefs « réservés mais non implémentés » est byvalue (bien que rien ne précise si ce mot-clef verra le jour).
Désolé de vous avoir pris la tête. :lol:
Au contraire c'est bien de le préciser :ccool:Citation:
Envoyé par Descent
En effet cela peut être trompeur pour ceux qui viennent du C++ où le passage par référence est différent et peut prendre une part importante de la conception d'une application (Cf la FAQ C++ sur les références).
a++
Hello,
selon moi, tout est passé par valeur en java...
quand on écrit:
on passe la valeur "5" à la méthode... normalCode:
1
2 foo(5);
et quand on écrit:
on passe aussi la valeur de "o" à la méthode "foo" ... ;) mais comme "o" est une référence, sa valeur vaut en fait un emplacement mémoire genre "0x10b62c9", et c'est cela qu'on lui passe en paramètre.Code:
1
2
3 Object o = new Object(); foo(o);
logique non ?
c'est d'ailleurs la même chose avec le "==":
Code:
1
2 if(4 == 5) // compare les valeurs
:wink:Code:
1
2 if(o1 == o2) // compare les valeurs des références, renvoie true si et seulement si o1 et o2 référencent le même objet (même valeur = même adresse mémoire = même objet)
Pill : ça se passe bien comme ça. et ça s'appele un passage par référence. La preuve en est :
pour des objets java non immuables (des classes que vous avez créé par exemple), si on passe un objet à une methode et qu'on travaille sur l'objet, en sortant de la méthode, les modifications sont concervées. Faites le test et vous verrez :wink:
oui, mais il ne s'agit que d'une conséquence du fait que les paramètres sont passés par valeur, et les objets gérés par référence ;)
Oui, j'avoue, j'avais lu ton post en diagonale, et j'ai retiré le mien (qui n'apportait rien) le plus vite possible, mais pas assez ... :oops: :oops: :oops:Citation:
Envoyé par Descent
Exactement, dans la méthode on obtient une copie du contenu de la variable, qui est une référence, ce qui permet d'altérer l'objet (s'il est altérable).Citation:
Envoyé par Pill_S
Ca m'arrive souvent aussi! :wink:Citation:
Envoyé par xavlours
Moi perso je suis de l'avis de Viena , mais bon c'est juste une question de point , je crois que l'essentiel c'est qui'on sache a peu pres comment ca marche :wink:Citation:
Envoyé par Pill_S
Mais quand je vois :
je vois une methode foo qui prend en parametre un Object et dans la mesure ou l'object passé en parametre n'est pas une copie de l'original il s'agit d'un passage par reference.Code:
1
2
3
4
5 public void foo(Object o){ ... }
La meme syntaxe en C++ pour un objet créé statiquement provoque la copie de celui ci, et un passage par valeur , alors qu'en java on a le meme objet et non une copie (ou un clone).
Juste pour completer ce débat, je voudrais rajouter un exemple, montrant que tout est bien un passage par valeur et non par référence.
Essayez ceci:
Si c'était vraiment un passage par référence, on aurait ceci:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 class Test { private String display; public Test(String value) { this.display = value; } public String toString() { return display; } } public class Main { public static void foo(Object obj){ obj = new Test("objet2"); System.out.println("foo "+obj); } public static void main(String[] args) { Object object1 = new Test("objet1"); System.out.println(object1); foo(object1); System.out.println(object1); } }
Mais comme c'est un passage par valeur, on obtientCitation:
objet1
foo objet2
objet2
J'espère que jusqu'ici vous avez suivi.Citation:
objet1
foo objet2
objet1
Maintenant, pour compliquer un peu plus, il faut savoir que lorsqu'on ne manipule pas des primitives en Java, on ne manipule pas non plus des objets. Ni des références à des objets, comme pourrait le penser un programmeur C++). Mais on manipule des pointeurs à des objets. Et lorsqu'on "passe un objet" à une méthode, on ne passe pas l'objet ni sa référence, mais on passe la valeur du pointeur à l'objet. Grande nuance.
Je vais citer ci-dessous quelques extraits de l'excellent livre "Au coeur de Java 2" Notion fondamentales JDK 5 Volume 1.
Page 119
(C'est moi qui ai mis en gras à tort)Citation:
De nombreuses personne pensent à tort que les variables objets de Java se comportent comme les références en C++.
Mais en C++, il n'y a pas de référence nlles et les références ne peuvent être affectées. Il faut plutôt penser aux variables objet de Java comme aux pointeurs sur objets de C++. Par exemple,
est en fait identique àCode:Date birthday;// en Java
Lorsqu'on fait cette association, tout redevient clair. Bien entendu, un pointeur Date* n'est pas initialisé tant que l'on n'appelle pas new. La syntaxe est presque la même en C++ et en Java:Code:Date* birthday; //en C++
Code:Date* birthday = new Date(); // C++
Et la méthode Java suivante:
serait en fait équivalente à ceciCode:void method(Date birthday); // en Java
et non à ceciCode:void method(Date* birthday); // en pseudo C++
ni à ceciCode:void method(Date& birthday); // en C++
-------------------------------Code:void method(Date*& birthday); // en pseudo C++
Page 64
-------------------------------Citation:
Les programmeurs C++ sont souvent stupéfaits lorsqu'ils rencontrent des chaines Java pour la première fois, car ils considèrent les chaines comme des tableaux de caractères
La comparaison n'est pas bonne; une chaine Java ressemble davantage à un pointeur char*;Code:char greeting[] = "Hello";
Code:char* greeting = "Hello";
Page 98
Citation:
Un tableau Java est assez différent d'un tableau C/C++ dans la pile (stack). Il peut cependant être comparé à un pointeur sur un tableau alloué dans le tas (segment heap de la mémoire). C'est à dire que
n'est pas la même chose queCode:int[] a = new int[100]; //en Java
mais plutot àCode:int[] a = new int[100]; //en C++
Code:int* a = new int[100]; //en C++
Merci pour cette explication!
Mais alors concrètement, comment fait-on pour faire l'équivalent d'un passage de paramètre de fonction par référence en c++, sur un type primitif en java?
Exemple concret, comment faire en sorte que le code suivant affiche "a=10"?
:question:Code:
1
2
3
4
5
6
7
8
9
10
11
12 public class Test{ public static void f( int a ) { a = 10; } public static void main(String[] args) { int a = 0; f(a); System.out.print("a="); System.out.print(a); } }
Tu sors un vieux sujet du placard :)
Ce que tu demandes est impossible tel quel avec les types primitifs.
Il y a 2 solutions :
:arrow: Ta fonction f renvoi un int et dans le main tu fais a = f(a)
:arrow: Tu travailles avec un objet Integer plutôt qu'un int.
Vi je suis désolé :oops: Mais je pensais que ce serait mieux que d'en créer un nouveau parce que quand j'ai fait la recherche sur ce sujet j'ai eu 3000 résultats et ça fait déjà beaucoup non? :oops:
tu veux que je crée un nouveau?
Ben je viens de tester ceci:et la sortie reste obstinément "number = 0";Code:
1
2
3
4
5
6
7
8
9
10
11
12 public class HelloWord { public static void g( Integer a ){ a=10; } public static void main(String[] args) { Integer a=0; g(a); System.out.print( "number = " + a ); System.out.println(); } }
J'ai bien l'impression que ce n'est pas possible en fait, tout simplement.
Je sais qu'en C# c'est possible avec un mot-clé, ref il me semble. En python ça ne semble pas non plus possible...
Faux : Integer est une classe immutable et ses données ne pourront pas être changé...
Il faudrait donc utiliser une classe mutable contenant un int avec ses getter/setter (il n'y a rien de tel en standard).
Mais cela dépend surtout de ce que tu veux faire avec cela : on ne traduit pas un code C++ en Java ligne par ligne... les philosophies sont différentes !
a++
Oui je sais bien, c'est juste une question "philosophique" que je me pose. En fait, en ce moment j'ai des soucis (en c++) avec des problèmes de gestion de mémoire, j'aimerai comprendre comment les différents langages gèrent le passage de paramètre.
Merci pour vos réponse :)
Et bien en Java c'est tout simple : tout est passé par copie !
La passage par référence est très utile en C++ pour le passage d'objet, car on n'a que deux autres alternatives :
- Passer l'objet par copie (par défaut), ce qui entraine l'appel implicite du constructeur de copie et qui peut être couteux.
- Passer l'adresse de l'objet pour éviter la copie (passage par pointeur), mais cela entraine l'utilisation de pointeur pas forcément toujours pratique.
Le passage par référence permet de passer un objet sans en faire de copie...
En Java on ne retrouve pas ce problème, puisque si on a bien un passage par copie pour tous les éléments, on ne manipule pas vraiment d'objet mais seulement des références. Ainsi lorsqu'on passe un objet à une méthode on fait en réalité une copie de sa référence, ce qui s'apparente en fait à un passage par pointeur (en C++), sans les inconvénients...
Du coup le seul intérêt d'avoir un passage par référence en Java serait la possibilité de simuler plusieurs valeurs de retour, ce qui est généralement plutôt déconseillé (on privilégiera à la place un objet conteneur dont les valeurs seront modifié).
a++
oups :oops: j'avais oublié, je ne travaille jamais avec ces classes...Citation:
Envoyé par adiGuba
Faire un passage par référence ou par copie de référence, n'est-ce pas identique? une référence est bien l'adresse dans la mémoire?
J'avoue que même en ayant compris la pratique depuis un moment, les questions philosophiques restent compliquées. :wow:
Je ne sais pas si ça répondra à ta question, mais en c++, il y a une subtile différence entre pointeur et référence (je ne parle pas de la syntaxe, qui elle est totalement différente):
-> un pointeur c'est une variable qui contient l'adresse de l'objet (la zone mémoire dans laquelle est stocké l'objet). C'est un type.
-> une référence c'est l'adresse de l'objet.
Ca n'a pas l'air à première vue, mais ça change beaucoup de chose: étant donné qu'un pointeur est un type, on peut faire beaucoup de choses que l'on ne peut pas faire avec une référence, comme par exemple définir une valeur nulle, des opérations, etc...
Une référence correspond bien grosso-modo à une adresse, mais le "passage par référence" et par "copie de référence" n'est pas tout à fait pareil :
Prenons le code suivant :
Avec Java nous avons comme résultat "hello" (str n'est pas modifié).Code:
1
2
3
4
5
6
7
8
9 public static void method(String str) { str = "world"; } public static void main(String[] args) { String str = "hello"; method(str); System.out.println(str); }
Pourquoi ?
Dans la méthode main() nous avons :
- Un objet "hello", quelque part en mémoire.
- Une référence str, stocké dans le stack de la méthode.
Lorsqu'on appelle la méthode, on copie la valeur de la référence (l'adresse si tu préfères) dans une nouvelle référence str stocké dans le stack de la méthode method(). On a deux références distinctes :
- str de main(), stocké dans le stack de la méthode main() (puisque c'est une variable locale)
- str de method(), stocké dans le stack de la méthode method() (puisque c'est un paramètre)
Ces deux références pointent vers le même objet en mémoire (ce qui fait que l'utilisation d'une éventuellement méthode setter serait visible via les deux référence).
Mais lorsqu'on fait une affectation comme dans le code de method(), on modifie la valeur de la référence (l'adresse du pointeur si tu veux).
Du coup la référence str de method() pointe vers un autre objet en mémoire, mais il n'y a aucun moyen de modifier la référence str de main() qui est dans un autre espace mémoire.
A l'inverse, si un passage par référence était possible, la variable str de method() ne serait pas stocké dans le stack de cette dernière : on utiliserait directement l'espace mémoire dans le stack de la méthode appelante (main() donc), et donc toutes modifications impacterait également la méthode parente : on a une seule référence et non pas deux !
:arrow: On obtiendrait donc le résultat "world".
En fait tu es proche d'un passage par pointeur (sauf qu'il est caché) :
Code:
1
2
3
4 void method(char* c) { *c = 'a'; // Tu modifies la valeur pointé par c, ce qui impactera le parent, c'est l'équivalent d'un setter en Java c = "a"; // Tu modifies directement c, qui appartient uniquement à la méthode (pas d'impact sur l'appelant) }
a++